npf_nat.c revision 1.12 1 /* $NetBSD: npf_nat.c,v 1.12 2012/03/11 18:27:59 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This material is based upon work partially supported by The
8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * NPF network address port translation (NAPT).
34 * Described in RFC 2663, RFC 3022. Commonly just "NAT".
35 *
36 * Overview
37 *
38 * There are few mechanisms: NAT policy, port map and translation.
39 * NAT module has a separate ruleset, where rules contain associated
40 * NAT policy, thus flexible filter criteria can be used.
41 *
42 * Translation types
43 *
44 * There are two types of translation: outbound (NPF_NATOUT) and
45 * inbound (NPF_NATIN). It should not be confused with connection
46 * direction.
47 *
48 * Outbound NAT rewrites:
49 * - Source on "forwards" stream.
50 * - Destination on "backwards" stream.
51 * Inbound NAT rewrites:
52 * - Destination on "forwards" stream.
53 * - Source on "backwards" stream.
54 *
55 * It should be noted that bi-directional NAT is a combined outbound
56 * and inbound translation, therefore constructed as two policies.
57 *
58 * NAT policies and port maps
59 *
60 * NAT (translation) policy is applied when a packet matches the rule.
61 * Apart from filter criteria, NAT policy has a translation IP address
62 * and associated port map. Port map is a bitmap used to reserve and
63 * use unique TCP/UDP ports for translation. Port maps are unique to
64 * the IP addresses, therefore multiple NAT policies with the same IP
65 * will share the same port map.
66 *
67 * Sessions, translation entries and their life-cycle
68 *
69 * NAT module relies on session management module. Each translated
70 * session has an associated translation entry (npf_nat_t), which
71 * contains information used for backwards stream translation, i.e.
72 * original IP address with port and translation port, allocated from
73 * the port map. Each NAT entry is associated with the policy, which
74 * contains translation IP address. Allocated port is returned to the
75 * port map and NAT entry is destroyed when session expires.
76 */
77
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.12 2012/03/11 18:27:59 rmind Exp $");
80
81 #include <sys/param.h>
82 #include <sys/types.h>
83
84 #include <sys/atomic.h>
85 #include <sys/bitops.h>
86 #include <sys/condvar.h>
87 #include <sys/kmem.h>
88 #include <sys/mutex.h>
89 #include <sys/pool.h>
90 #include <sys/cprng.h>
91
92 #include <net/pfil.h>
93 #include <netinet/in.h>
94
95 #include "npf_impl.h"
96
97 /*
98 * NPF portmap structure.
99 */
100 typedef struct {
101 u_int p_refcnt;
102 uint32_t p_bitmap[0];
103 } npf_portmap_t;
104
105 /* Portmap range: [ 1024 .. 65535 ] */
106 #define PORTMAP_FIRST (1024)
107 #define PORTMAP_SIZE ((65536 - PORTMAP_FIRST) / 32)
108 #define PORTMAP_FILLED ((uint32_t)~0)
109 #define PORTMAP_MASK (31)
110 #define PORTMAP_SHIFT (5)
111
112 #define PORTMAP_MEM_SIZE \
113 (sizeof(npf_portmap_t) + (PORTMAP_SIZE * sizeof(uint32_t)))
114
115 /*
116 * NAT policy structure.
117 */
118 struct npf_natpolicy {
119 LIST_HEAD(, npf_nat) n_nat_list;
120 kmutex_t n_lock;
121 kcondvar_t n_cv;
122 npf_portmap_t * n_portmap;
123 int n_type;
124 u_int n_flags;
125 size_t n_addr_sz;
126 npf_addr_t n_taddr;
127 in_port_t n_tport;
128 };
129
130 #define NPF_NP_CMP_START offsetof(npf_natpolicy_t, n_type)
131 #define NPF_NP_CMP_SIZE (sizeof(npf_natpolicy_t) - NPF_NP_CMP_START)
132
133 /*
134 * NAT translation entry for a session.
135 */
136 struct npf_nat {
137 /* Association (list entry and a link pointer) with NAT policy. */
138 LIST_ENTRY(npf_nat) nt_entry;
139 npf_natpolicy_t * nt_natpolicy;
140 npf_session_t * nt_session;
141 /* Original address and port (for backwards translation). */
142 npf_addr_t nt_oaddr;
143 in_port_t nt_oport;
144 /* Translation port (for redirects). */
145 in_port_t nt_tport;
146 /* ALG (if any) associated with this NAT entry. */
147 npf_alg_t * nt_alg;
148 uintptr_t nt_alg_arg;
149 };
150
151 static pool_cache_t nat_cache __read_mostly;
152
153 /*
154 * npf_nat_sys{init,fini}: initialise/destroy NAT subsystem structures.
155 */
156
157 void
158 npf_nat_sysinit(void)
159 {
160
161 nat_cache = pool_cache_init(sizeof(npf_nat_t), coherency_unit,
162 0, 0, "npfnatpl", NULL, IPL_NET, NULL, NULL, NULL);
163 KASSERT(nat_cache != NULL);
164 }
165
166 void
167 npf_nat_sysfini(void)
168 {
169
170 /* NAT policies should already be destroyed. */
171 pool_cache_destroy(nat_cache);
172 }
173
174 /*
175 * npf_nat_newpolicy: create a new NAT policy.
176 *
177 * => Shares portmap if policy is on existing translation address.
178 * => XXX: serialise at upper layer.
179 */
180 npf_natpolicy_t *
181 npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *nrlset)
182 {
183 npf_natpolicy_t *np;
184 prop_object_t obj;
185 npf_portmap_t *pm;
186
187 np = kmem_zalloc(sizeof(npf_natpolicy_t), KM_SLEEP);
188
189 /* Translation type and flags. */
190 prop_dictionary_get_int32(natdict, "type", &np->n_type);
191 prop_dictionary_get_uint32(natdict, "flags", &np->n_flags);
192
193 /* Should be exclusively either inbound or outbound NAT. */
194 if (((np->n_type == NPF_NATIN) ^ (np->n_type == NPF_NATOUT)) == 0) {
195 kmem_free(np, sizeof(npf_natpolicy_t));
196 return NULL;
197 }
198 mutex_init(&np->n_lock, MUTEX_DEFAULT, IPL_SOFTNET);
199 cv_init(&np->n_cv, "npfnatcv");
200 LIST_INIT(&np->n_nat_list);
201
202 /* Translation IP. */
203 obj = prop_dictionary_get(natdict, "translation-ip");
204 np->n_addr_sz = prop_data_size(obj);
205 KASSERT(np->n_addr_sz > 0 && np->n_addr_sz <= sizeof(npf_addr_t));
206 memcpy(&np->n_taddr, prop_data_data_nocopy(obj), np->n_addr_sz);
207
208 /* Translation port (for redirect case). */
209 prop_dictionary_get_uint16(natdict, "translation-port", &np->n_tport);
210
211 /* Determine if port map is needed. */
212 np->n_portmap = NULL;
213 if ((np->n_flags & NPF_NAT_PORTMAP) == 0) {
214 /* No port map. */
215 return np;
216 }
217
218 /*
219 * Inspect NAT policies in the ruleset for port map sharing.
220 * Note that npf_ruleset_sharepm() will increase the reference count.
221 */
222 if (!npf_ruleset_sharepm(nrlset, np)) {
223 /* Allocate a new port map for the NAT policy. */
224 pm = kmem_zalloc(PORTMAP_MEM_SIZE, KM_SLEEP);
225 pm->p_refcnt = 1;
226 KASSERT((uintptr_t)pm->p_bitmap == (uintptr_t)pm + sizeof(*pm));
227 np->n_portmap = pm;
228 } else {
229 KASSERT(np->n_portmap != NULL);
230 }
231 return np;
232 }
233
234 /*
235 * npf_nat_freepolicy: free NAT policy and, on last reference, free portmap.
236 *
237 * => Called from npf_rule_free() during the reload via npf_ruleset_destroy().
238 */
239 void
240 npf_nat_freepolicy(npf_natpolicy_t *np)
241 {
242 npf_portmap_t *pm = np->n_portmap;
243 npf_session_t *se;
244 npf_nat_t *nt;
245
246 /* De-associate all entries from the policy. */
247 mutex_enter(&np->n_lock);
248 LIST_FOREACH(nt, &np->n_nat_list, nt_entry) {
249 se = nt->nt_session; /* XXXSMP */
250 if (se == NULL) {
251 continue;
252 }
253 npf_session_expire(se);
254 }
255 while (!LIST_EMPTY(&np->n_nat_list)) {
256 cv_wait(&np->n_cv, &np->n_lock);
257 }
258 mutex_exit(&np->n_lock);
259
260 /* Destroy the port map, on last reference. */
261 if (pm && --pm->p_refcnt == 0) {
262 KASSERT((np->n_flags & NPF_NAT_PORTMAP) != 0);
263 kmem_free(pm, PORTMAP_MEM_SIZE);
264 }
265 cv_destroy(&np->n_cv);
266 mutex_destroy(&np->n_lock);
267 kmem_free(np, sizeof(npf_natpolicy_t));
268 }
269
270 /*
271 * npf_nat_matchpolicy: compare two NAT policies.
272 *
273 * => Return 0 on match, and non-zero otherwise.
274 */
275 bool
276 npf_nat_matchpolicy(npf_natpolicy_t *np, npf_natpolicy_t *mnp)
277 {
278 void *np_raw, *mnp_raw;
279 /*
280 * Compare the relevant NAT policy information (in raw form),
281 * which is enough for matching criterion.
282 */
283 KASSERT(np && mnp && np != mnp);
284 np_raw = (uint8_t *)np + NPF_NP_CMP_START;
285 mnp_raw = (uint8_t *)mnp + NPF_NP_CMP_START;
286 return (memcmp(np_raw, mnp_raw, NPF_NP_CMP_SIZE) == 0);
287 }
288
289 bool
290 npf_nat_sharepm(npf_natpolicy_t *np, npf_natpolicy_t *mnp)
291 {
292 npf_portmap_t *pm, *mpm;
293
294 KASSERT(np && mnp && np != mnp);
295
296 /* Using port map and having equal translation address? */
297 if ((np->n_flags & mnp->n_flags & NPF_NAT_PORTMAP) == 0) {
298 return false;
299 }
300 if (np->n_addr_sz != mnp->n_addr_sz) {
301 return false;
302 }
303 if (memcmp(&np->n_taddr, &mnp->n_taddr, np->n_addr_sz) != 0) {
304 return false;
305 }
306 /* If NAT policy has an old port map - drop the reference. */
307 mpm = mnp->n_portmap;
308 if (mpm) {
309 /* Note: at this point we cannot hold a last reference. */
310 KASSERT(mpm->p_refcnt > 1);
311 mpm->p_refcnt--;
312 }
313 /* Share the port map. */
314 pm = np->n_portmap;
315 mnp->n_portmap = pm;
316 pm->p_refcnt++;
317 return true;
318 }
319
320 /*
321 * npf_nat_getport: allocate and return a port in the NAT policy portmap.
322 *
323 * => Returns in network byte-order.
324 * => Zero indicates failure.
325 */
326 static in_port_t
327 npf_nat_getport(npf_natpolicy_t *np)
328 {
329 npf_portmap_t *pm = np->n_portmap;
330 u_int n = PORTMAP_SIZE, idx, bit;
331 uint32_t map, nmap;
332
333 idx = cprng_fast32() % PORTMAP_SIZE;
334 for (;;) {
335 KASSERT(idx < PORTMAP_SIZE);
336 map = pm->p_bitmap[idx];
337 if (__predict_false(map == PORTMAP_FILLED)) {
338 if (n-- == 0) {
339 /* No space. */
340 return 0;
341 }
342 /* This bitmap is filled, next. */
343 idx = (idx ? idx : PORTMAP_SIZE) - 1;
344 continue;
345 }
346 bit = ffs32(~map) - 1;
347 nmap = map | (1 << bit);
348 if (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) == map) {
349 /* Success. */
350 break;
351 }
352 }
353 return htons(PORTMAP_FIRST + (idx << PORTMAP_SHIFT) + bit);
354 }
355
356 /*
357 * npf_nat_takeport: allocate specific port in the NAT policy portmap.
358 */
359 static bool
360 npf_nat_takeport(npf_natpolicy_t *np, in_port_t port)
361 {
362 npf_portmap_t *pm = np->n_portmap;
363 uint32_t map, nmap;
364 u_int idx, bit;
365
366 port = ntohs(port) - PORTMAP_FIRST;
367 idx = port >> PORTMAP_SHIFT;
368 bit = port & PORTMAP_MASK;
369 map = pm->p_bitmap[idx];
370 nmap = map | (1 << bit);
371 if (map == nmap) {
372 /* Already taken. */
373 return false;
374 }
375 return atomic_cas_32(&pm->p_bitmap[idx], map, nmap) == map;
376 }
377
378 /*
379 * npf_nat_putport: return port as available in the NAT policy portmap.
380 *
381 * => Port should be in network byte-order.
382 */
383 static void
384 npf_nat_putport(npf_natpolicy_t *np, in_port_t port)
385 {
386 npf_portmap_t *pm = np->n_portmap;
387 uint32_t map, nmap;
388 u_int idx, bit;
389
390 port = ntohs(port) - PORTMAP_FIRST;
391 idx = port >> PORTMAP_SHIFT;
392 bit = port & PORTMAP_MASK;
393 do {
394 map = pm->p_bitmap[idx];
395 KASSERT(map | (1 << bit));
396 nmap = map & ~(1 << bit);
397 } while (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) != map);
398 }
399
400 /*
401 * npf_nat_inspect: inspect packet against NAT ruleset and return a policy.
402 */
403 static npf_natpolicy_t *
404 npf_nat_inspect(npf_cache_t *npc, nbuf_t *nbuf, ifnet_t *ifp, const int di)
405 {
406 npf_ruleset_t *rlset;
407 npf_natpolicy_t *np;
408 npf_rule_t *rl;
409
410 npf_core_enter();
411 rlset = npf_core_natset();
412 rl = npf_ruleset_inspect(npc, nbuf, rlset, ifp, di, NPF_LAYER_3);
413 if (rl == NULL) {
414 npf_core_exit();
415 return NULL;
416 }
417 np = npf_rule_getnat(rl);
418 if (np == NULL) {
419 npf_core_exit();
420 return NULL;
421 }
422 return np;
423 }
424
425 /*
426 * npf_nat_create: create a new NAT translation entry.
427 */
428 static npf_nat_t *
429 npf_nat_create(npf_cache_t *npc, npf_natpolicy_t *np)
430 {
431 const int proto = npf_cache_ipproto(npc);
432 npf_nat_t *nt;
433
434 KASSERT(npf_iscached(npc, NPC_IP46));
435 KASSERT(npf_iscached(npc, NPC_LAYER4));
436
437 /* New NAT association. */
438 nt = pool_cache_get(nat_cache, PR_NOWAIT);
439 if (nt == NULL){
440 return NULL;
441 }
442 npf_stats_inc(NPF_STAT_NAT_CREATE);
443 nt->nt_natpolicy = np;
444 nt->nt_session = NULL;
445 nt->nt_alg = NULL;
446
447 /* Save the original address which may be rewritten. */
448 if (np->n_type == NPF_NATOUT) {
449 /* Source (local) for Outbound NAT. */
450 memcpy(&nt->nt_oaddr, npc->npc_srcip, npc->npc_ipsz);
451 } else {
452 /* Destination (external) for Inbound NAT. */
453 KASSERT(np->n_type == NPF_NATIN);
454 memcpy(&nt->nt_oaddr, npc->npc_dstip, npc->npc_ipsz);
455 }
456
457 /*
458 * Port translation, if required, and if it is TCP/UDP.
459 */
460 if ((np->n_flags & NPF_NAT_PORTS) == 0 ||
461 (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) {
462 nt->nt_oport = 0;
463 nt->nt_tport = 0;
464 goto out;
465 }
466
467 /* Save the relevant TCP/UDP port. */
468 if (proto == IPPROTO_TCP) {
469 struct tcphdr *th = &npc->npc_l4.tcp;
470 nt->nt_oport = (np->n_type == NPF_NATOUT) ?
471 th->th_sport : th->th_dport;
472 } else {
473 struct udphdr *uh = &npc->npc_l4.udp;
474 nt->nt_oport = (np->n_type == NPF_NATOUT) ?
475 uh->uh_sport : uh->uh_dport;
476 }
477
478 /* Get a new port for translation. */
479 if ((np->n_flags & NPF_NAT_PORTMAP) != 0) {
480 nt->nt_tport = npf_nat_getport(np);
481 } else {
482 nt->nt_tport = np->n_tport;
483 }
484 out:
485 mutex_enter(&np->n_lock);
486 LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry);
487 mutex_exit(&np->n_lock);
488 return nt;
489 }
490
491 /*
492 * npf_nat_translate: perform address and/or port translation.
493 */
494 static int
495 npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt,
496 const bool forw, const int di)
497 {
498 void *n_ptr = nbuf_dataptr(nbuf);
499 npf_natpolicy_t *np = nt->nt_natpolicy;
500 npf_addr_t *addr;
501 in_port_t port;
502
503 KASSERT(npf_iscached(npc, NPC_IP46));
504
505 if (forw) {
506 /* "Forwards" stream: use translation address/port. */
507 KASSERT(
508 (np->n_type == NPF_NATIN && di == PFIL_IN) ^
509 (np->n_type == NPF_NATOUT && di == PFIL_OUT)
510 );
511 addr = &np->n_taddr;
512 port = nt->nt_tport;
513 } else {
514 /* "Backwards" stream: use original address/port. */
515 KASSERT(
516 (np->n_type == NPF_NATIN && di == PFIL_OUT) ^
517 (np->n_type == NPF_NATOUT && di == PFIL_IN)
518 );
519 addr = &nt->nt_oaddr;
520 port = nt->nt_oport;
521 }
522 KASSERT((np->n_flags & NPF_NAT_PORTS) != 0 || port == 0);
523
524 /* Execute ALG hook first. */
525 npf_alg_exec(npc, nbuf, nt, di);
526
527 /*
528 * Rewrite IP and/or TCP/UDP checksums first, since it will use
529 * the cache containing original values for checksum calculation.
530 */
531 if (!npf_rwrcksum(npc, nbuf, n_ptr, di, addr, port)) {
532 return EINVAL;
533 }
534
535 /*
536 * Address translation: rewrite source/destination address, depending
537 * on direction (PFIL_OUT - for source, PFIL_IN - for destination).
538 */
539 if (!npf_rwrip(npc, nbuf, n_ptr, di, addr)) {
540 return EINVAL;
541 }
542 if ((np->n_flags & NPF_NAT_PORTS) == 0) {
543 /* Done. */
544 return 0;
545 }
546
547 switch (npf_cache_ipproto(npc)) {
548 case IPPROTO_TCP:
549 case IPPROTO_UDP:
550 KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
551 /* Rewrite source/destination port. */
552 if (!npf_rwrport(npc, nbuf, n_ptr, di, port)) {
553 return EINVAL;
554 }
555 break;
556 case IPPROTO_ICMP:
557 KASSERT(npf_iscached(npc, NPC_ICMP));
558 /* Nothing. */
559 break;
560 default:
561 return ENOTSUP;
562 }
563 return 0;
564 }
565
566 /*
567 * npf_do_nat:
568 * - Inspect packet for a NAT policy, unless a session with a NAT
569 * association already exists. In such case, determine whether it
570 * is a "forwards" or "backwards" stream.
571 * - Perform translation: rewrite source or destination fields,
572 * depending on translation type and direction.
573 * - Associate a NAT policy with a session (may establish a new).
574 */
575 int
576 npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf,
577 ifnet_t *ifp, const int di)
578 {
579 npf_session_t *nse = NULL;
580 npf_natpolicy_t *np;
581 npf_nat_t *nt;
582 int error;
583 bool forw, new;
584
585 /* All relevant IPv4 data should be already cached. */
586 if (!npf_iscached(npc, NPC_IP46) || !npf_iscached(npc, NPC_LAYER4)) {
587 return 0;
588 }
589
590 /*
591 * Return the NAT entry associated with the session, if any.
592 * Determines whether the stream is "forwards" or "backwards".
593 * Note: no need to lock, since reference on session is held.
594 */
595 if (se && (nt = npf_session_retnat(se, di, &forw)) != NULL) {
596 np = nt->nt_natpolicy;
597 new = false;
598 goto translate;
599 }
600
601 /*
602 * Inspect the packet for a NAT policy, if there is no session.
603 * Note: acquires the lock (releases, if not found).
604 */
605 np = npf_nat_inspect(npc, nbuf, ifp, di);
606 if (np == NULL) {
607 /* If packet does not match - done. */
608 return 0;
609 }
610 forw = true;
611
612 /*
613 * Create a new NAT entry. Note: it is safe to unlock, since the
614 * NAT policy wont be desotroyed while there are list entries, which
615 * are removed only on session expiration. Currently, NAT entry is
616 * not yet associated with any session.
617 */
618 nt = npf_nat_create(npc, np);
619 if (nt == NULL) {
620 npf_core_exit();
621 return ENOMEM;
622 }
623 npf_core_exit();
624 new = true;
625
626 /* Determine whether any ALG matches. */
627 if (npf_alg_match(npc, nbuf, nt)) {
628 KASSERT(nt->nt_alg != NULL);
629 }
630
631 /*
632 * If there is no local session (no "keep state" rule - unusual, but
633 * possible configuration), establish one before translation. Note
634 * that it is not a "pass" session, therefore passing of "backwards"
635 * stream depends on other, stateless filtering rules.
636 */
637 if (se == NULL) {
638 nse = npf_session_establish(npc, nbuf, di);
639 if (nse == NULL) {
640 error = ENOMEM;
641 goto out;
642 }
643 se = nse;
644 }
645 translate:
646 /* Perform the translation. */
647 error = npf_nat_translate(npc, nbuf, nt, forw, di);
648 if (error) {
649 goto out;
650 }
651
652 if (__predict_false(new)) {
653 /*
654 * Associate NAT translation entry with the session.
655 * Note: packet now has a translated address in the cache.
656 */
657 nt->nt_session = se;
658 error = npf_session_setnat(se, nt, di);
659 out:
660 if (error) {
661 /* If session was for NAT only - expire it. */
662 if (nse) {
663 npf_session_expire(nse);
664 }
665 /* Will free the structure and return the port. */
666 npf_nat_expire(nt);
667 }
668 if (nse != NULL) {
669 npf_session_release(nse);
670 }
671 }
672 return error;
673 }
674
675 /*
676 * npf_nat_gettrans: return translation IP address and port.
677 */
678 void
679 npf_nat_gettrans(npf_nat_t *nt, npf_addr_t **addr, in_port_t *port)
680 {
681 npf_natpolicy_t *np = nt->nt_natpolicy;
682
683 *addr = &np->n_taddr;
684 *port = nt->nt_tport;
685 }
686
687 /*
688 * npf_nat_getorig: return original IP address and port from translation entry.
689 */
690 void
691 npf_nat_getorig(npf_nat_t *nt, npf_addr_t **addr, in_port_t *port)
692 {
693
694 *addr = &nt->nt_oaddr;
695 *port = nt->nt_oport;
696 }
697
698 /*
699 * npf_nat_setalg: associate an ALG with the NAT entry.
700 */
701 void
702 npf_nat_setalg(npf_nat_t *nt, npf_alg_t *alg, uintptr_t arg)
703 {
704
705 nt->nt_alg = alg;
706 nt->nt_alg_arg = arg;
707 }
708
709 /*
710 * npf_nat_expire: free NAT-related data structures on session expiration.
711 */
712 void
713 npf_nat_expire(npf_nat_t *nt)
714 {
715 npf_natpolicy_t *np = nt->nt_natpolicy;
716
717 /* Return any taken port to the portmap. */
718 if ((np->n_flags & NPF_NAT_PORTMAP) != 0 && nt->nt_tport) {
719 npf_nat_putport(np, nt->nt_tport);
720 }
721
722 /* Remove NAT entry from the list, notify any waiters if last entry. */
723 mutex_enter(&np->n_lock);
724 LIST_REMOVE(nt, nt_entry);
725 if (LIST_EMPTY(&np->n_nat_list)) {
726 cv_broadcast(&np->n_cv);
727 }
728 mutex_exit(&np->n_lock);
729
730 /* Free structure, increase the counter. */
731 pool_cache_put(nat_cache, nt);
732 npf_stats_inc(NPF_STAT_NAT_DESTROY);
733 }
734
735 /*
736 * npf_nat_save: construct NAT entry and reference to the NAT policy.
737 */
738 int
739 npf_nat_save(prop_dictionary_t sedict, prop_array_t natlist, npf_nat_t *nt)
740 {
741 npf_natpolicy_t *np = nt->nt_natpolicy;
742 prop_object_iterator_t it;
743 prop_dictionary_t npdict;
744 prop_data_t nd, npd;
745 uintptr_t itnp;
746
747 /* Set NAT entry data. */
748 nd = prop_data_create_data(nt, sizeof(npf_nat_t));
749 prop_dictionary_set(sedict, "nat-data", nd);
750 prop_object_release(nd);
751
752 /* Find or create a NAT policy. */
753 it = prop_array_iterator(natlist);
754 while ((npdict = prop_object_iterator_next(it)) != NULL) {
755 CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
756 prop_dictionary_get_uint64(npdict, "id-ptr", (uint64_t *)&itnp);
757 if (itnp == (uintptr_t)np) {
758 break;
759 }
760 }
761 if (npdict == NULL) {
762 /* Create NAT policy dictionary and copy the data. */
763 npdict = prop_dictionary_create();
764 npd = prop_data_create_data(np, sizeof(npf_natpolicy_t));
765 prop_dictionary_set(npdict, "nat-policy-data", npd);
766 prop_object_release(npd);
767
768 CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
769 prop_dictionary_set_uint64(npdict, "id-ptr", (uintptr_t)np);
770 prop_array_add(natlist, npdict);
771 prop_object_release(npdict);
772 }
773 prop_dictionary_set(sedict, "nat-policy", npdict);
774 prop_object_release(npdict);
775 return 0;
776 }
777
778 /*
779 * npf_nat_restore: find a matching NAT policy and restore NAT entry.
780 *
781 * => Caller should lock the active NAT ruleset.
782 */
783 npf_nat_t *
784 npf_nat_restore(prop_dictionary_t sedict, npf_session_t *se)
785 {
786 const npf_natpolicy_t *onp;
787 const npf_nat_t *ntraw;
788 prop_object_t obj;
789 npf_natpolicy_t *np;
790 npf_rule_t *rl;
791 npf_nat_t *nt;
792
793 /* Get raw NAT entry. */
794 obj = prop_dictionary_get(sedict, "nat-data");
795 ntraw = prop_data_data_nocopy(obj);
796 if (ntraw == NULL || prop_data_size(obj) != sizeof(npf_nat_t)) {
797 return NULL;
798 }
799
800 /* Find a stored NAT policy information. */
801 obj = prop_dictionary_get(
802 prop_dictionary_get(sedict, "nat-policy"), "nat-policy-data");
803 onp = prop_data_data_nocopy(obj);
804 if (onp == NULL || prop_data_size(obj) != sizeof(npf_natpolicy_t)) {
805 return NULL;
806 }
807
808 /* Match if there is an existing NAT policy. */
809 rl = npf_ruleset_matchnat(npf_core_natset(), __UNCONST(onp));
810 if (rl == NULL) {
811 return NULL;
812 }
813 np = npf_rule_getnat(rl);
814 KASSERT(np != NULL);
815
816 /* Take a specific port from port-map. */
817 if (!npf_nat_takeport(np, ntraw->nt_tport)) {
818 return NULL;
819 }
820
821 /* Create and return NAT entry for association. */
822 nt = pool_cache_get(nat_cache, PR_WAITOK);
823 memcpy(nt, ntraw, sizeof(npf_nat_t));
824 LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry);
825 nt->nt_natpolicy = np;
826 nt->nt_session = se;
827 nt->nt_alg = NULL;
828 return nt;
829 }
830
831 #if defined(DDB) || defined(_NPF_TESTING)
832
833 void
834 npf_nat_dump(npf_nat_t *nt)
835 {
836 npf_natpolicy_t *np;
837 struct in_addr ip;
838
839 np = nt->nt_natpolicy;
840 memcpy(&ip, &np->n_taddr, sizeof(ip));
841 printf("\tNATP(%p): type %d flags 0x%x taddr %s tport %d\n",
842 np, np->n_type, np->n_flags, inet_ntoa(ip), np->n_tport);
843 memcpy(&ip, &nt->nt_oaddr, sizeof(ip));
844 printf("\tNAT: original address %s oport %d tport %d\n",
845 inet_ntoa(ip), ntohs(nt->nt_oport), ntohs(nt->nt_tport));
846 if (nt->nt_alg) {
847 printf("\tNAT ALG = %p, ARG = %p\n",
848 nt->nt_alg, (void *)nt->nt_alg_arg);
849 }
850 }
851
852 #endif
853