1 /*
2 * Copyright (C) 1995-2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7 * Use is subject to license terms.
8 */
9
10 #if defined(KERNEL) || defined(_KERNEL)
11 # undef KERNEL
12 # undef _KERNEL
13 # define KERNEL 1
14 # define _KERNEL 1
15 #endif
16 #include <sys/errno.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <sys/time.h>
20 #include <sys/file.h>
21 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
22 defined(_KERNEL)
23 # include "opt_ipfilter_log.h"
24 #endif
25 #if !defined(_KERNEL)
26 # include <stdio.h>
27 # include <string.h>
28 # include <stdlib.h>
29 # define _KERNEL
30 # ifdef __OpenBSD__
31 struct file;
32 # endif
33 # include <sys/uio.h>
34 # undef _KERNEL
35 #endif
36 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
37 # include <sys/filio.h>
38 # include <sys/fcntl.h>
39 #else
40 # include <sys/ioctl.h>
41 #endif
42 #if !defined(AIX)
43 # include <sys/fcntl.h>
44 #endif
45 #if !defined(linux)
46 # include <sys/protosw.h>
47 #endif
48 #include <sys/socket.h>
49 #if defined(_KERNEL)
50 # include <sys/systm.h>
51 # if !defined(__SVR4) && !defined(__svr4__)
52 # include <sys/mbuf.h>
53 # endif
54 #endif
55 #if defined(__SVR4) || defined(__svr4__)
56 # include <sys/filio.h>
57 # include <sys/byteorder.h>
58 # ifdef _KERNEL
59 # include <sys/dditypes.h>
60 # endif
61 # include <sys/stream.h>
62 # include <sys/kmem.h>
63 #endif
64 #if __FreeBSD_version >= 300000
65 # include <sys/queue.h>
66 #endif
67 #include <net/if.h>
68 #if __FreeBSD_version >= 300000
69 # include <net/if_var.h>
70 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
71 # include "opt_ipfilter.h"
72 # endif
73 #endif
74 #ifdef sun
75 # include <net/af.h>
76 #endif
77 #include <net/route.h>
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/ip.h>
81
82 #ifdef RFC1825
83 # include <vpn/md5.h>
84 # include <vpn/ipsec.h>
85 extern struct ifnet vpnif;
86 #endif
87
88 #if !defined(linux)
89 # include <netinet/ip_var.h>
90 #endif
91 #include <netinet/tcp.h>
92 #include <netinet/udp.h>
93 #include <netinet/ip_icmp.h>
94 #include "netinet/ip_compat.h"
95 #include <netinet/tcpip.h>
96 #include "netinet/ip_fil.h"
97 #include "netinet/ip_nat.h"
98 #include "netinet/ip_frag.h"
99 #include "netinet/ip_state.h"
100 #include "netinet/ip_proxy.h"
101 #include "netinet/ipf_stack.h"
102 #ifdef IPFILTER_SYNC
103 #include "netinet/ip_sync.h"
104 #endif
105 #if (__FreeBSD_version >= 300000)
106 # include <sys/malloc.h>
107 #endif
108 /* END OF INCLUDES */
109
110 #undef SOCKADDR_IN
111 #define SOCKADDR_IN struct sockaddr_in
112
113 #if !defined(lint)
114 static const char rcsid[] = "@(#)$Id: ip_nat6.c,v 1.2 2008/02/14 21:05:50 darrenr Exp $";
115 #endif
116
117 static hostmap_t *nat6_hostmap __P((ipnat_t *, i6addr_t *, i6addr_t *,
118 i6addr_t *, u_32_t, ipf_stack_t *));
119 static INLINE int nat6_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
120 static INLINE int nat6_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
121 static INLINE int nat6_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
122 tcphdr_t *, nat_t **, int));
123 static void nat6_tabmove __P((nat_t *, ipf_stack_t *));
124 static int nat6_match __P((fr_info_t *, ipnat_t *));
125 static INLINE int nat_icmpquerytype6 __P((int));
126
127
128 /* ------------------------------------------------------------------------ */
129 /* Function: nat6_addrdr */
130 /* Returns: Nil */
131 /* Parameters: n(I) - pointer to NAT rule to add */
132 /* */
133 /* Adds a redirect rule to the hash table of redirect rules and the list of */
134 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */
135 /* use by redirect rules. */
136 /* ------------------------------------------------------------------------ */
nat6_addrdr(n,ifs)137 void nat6_addrdr(n, ifs)
138 ipnat_t *n;
139 ipf_stack_t *ifs;
140 {
141 ipnat_t **np;
142 i6addr_t j;
143 u_int hv;
144 int k;
145
146 k = count6bits(n->in_out[1].i6);
147 if ((k >= 0) && (k != 128))
148 ifs->ifs_rdr6_masks[k >> 5] |= 1 << (k & 31);
149 IP6_AND(&n->in_out[0], &n->in_out[1], &j);
150 hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_rdrrules_sz);
151 np = ifs->ifs_rdr_rules + hv;
152 while (*np != NULL)
153 np = &(*np)->in_rnext;
154 n->in_rnext = NULL;
155 n->in_prnext = np;
156 n->in_hv = hv;
157 *np = n;
158 }
159
160
161 /* ------------------------------------------------------------------------ */
162 /* Function: nat6_addnat */
163 /* Returns: Nil */
164 /* Parameters: n(I) - pointer to NAT rule to add */
165 /* */
166 /* Adds a NAT map rule to the hash table of rules and the list of loaded */
167 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */
168 /* redirect rules. */
169 /* ------------------------------------------------------------------------ */
nat6_addnat(n,ifs)170 void nat6_addnat(n, ifs)
171 ipnat_t *n;
172 ipf_stack_t *ifs;
173 {
174 ipnat_t **np;
175 i6addr_t j;
176 u_int hv;
177 int k;
178
179 k = count6bits(n->in_in[1].i6);
180 if ((k >= 0) && (k != 128))
181 ifs->ifs_nat6_masks[k >> 5] |= 1 << (k & 31);
182 IP6_AND(&n->in_in[0], &n->in_in[1], &j);
183 hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_natrules_sz);
184 np = ifs->ifs_nat_rules + hv;
185 while (*np != NULL)
186 np = &(*np)->in_mnext;
187 n->in_mnext = NULL;
188 n->in_pmnext = np;
189 n->in_hv = hv;
190 *np = n;
191 }
192
193
194 /* ------------------------------------------------------------------------ */
195 /* Function: nat6_hostmap */
196 /* Returns: struct hostmap* - NULL if no hostmap could be created, */
197 /* else a pointer to the hostmapping to use */
198 /* Parameters: np(I) - pointer to NAT rule */
199 /* real(I) - real IP address */
200 /* map(I) - mapped IP address */
201 /* port(I) - destination port number */
202 /* Write Locks: ipf_nat */
203 /* */
204 /* Check if an ip address has already been allocated for a given mapping */
205 /* that is not doing port based translation. If is not yet allocated, then */
206 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */
207 /* ------------------------------------------------------------------------ */
nat6_hostmap(np,src,dst,map,port,ifs)208 static struct hostmap *nat6_hostmap(np, src, dst, map, port, ifs)
209 ipnat_t *np;
210 i6addr_t *src, *dst, *map;
211 u_32_t port;
212 ipf_stack_t *ifs;
213 {
214 hostmap_t *hm;
215 u_int hv;
216
217 hv = (src->i6[3] ^ dst->i6[3]);
218 hv += (src->i6[2] ^ dst->i6[2]);
219 hv += (src->i6[1] ^ dst->i6[1]);
220 hv += (src->i6[0] ^ dst->i6[0]);
221 hv += src->i6[3];
222 hv += src->i6[2];
223 hv += src->i6[1];
224 hv += src->i6[0];
225 hv += dst->i6[3];
226 hv += dst->i6[2];
227 hv += dst->i6[1];
228 hv += dst->i6[0];
229 hv %= HOSTMAP_SIZE;
230 for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next)
231 if (IP6_EQ(&hm->hm_srcip6, src) &&
232 IP6_EQ(&hm->hm_dstip6, dst) &&
233 ((np == NULL) || (np == hm->hm_ipnat)) &&
234 ((port == 0) || (port == hm->hm_port))) {
235 hm->hm_ref++;
236 return hm;
237 }
238
239 if (np == NULL)
240 return NULL;
241
242 KMALLOC(hm, hostmap_t *);
243 if (hm) {
244 hm->hm_hnext = ifs->ifs_ipf_hm_maplist;
245 hm->hm_phnext = &ifs->ifs_ipf_hm_maplist;
246 if (ifs->ifs_ipf_hm_maplist != NULL)
247 ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext;
248 ifs->ifs_ipf_hm_maplist = hm;
249
250 hm->hm_next = ifs->ifs_maptable[hv];
251 hm->hm_pnext = ifs->ifs_maptable + hv;
252 if (ifs->ifs_maptable[hv] != NULL)
253 ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next;
254 ifs->ifs_maptable[hv] = hm;
255 hm->hm_ipnat = np;
256 hm->hm_src = *src;
257 hm->hm_dst = *dst;
258 hm->hm_map = *map;
259 hm->hm_ref = 1;
260 hm->hm_port = port;
261 hm->hm_v = 6;
262 }
263 return hm;
264 }
265
266
267 /* ------------------------------------------------------------------------ */
268 /* Function: nat6_newmap */
269 /* Returns: int - -1 == error, 0 == success */
270 /* Parameters: fin(I) - pointer to packet information */
271 /* nat(I) - pointer to NAT entry */
272 /* ni(I) - pointer to structure with misc. information needed */
273 /* to create new NAT entry. */
274 /* */
275 /* Given an empty NAT structure, populate it with new information about a */
276 /* new NAT session, as defined by the matching NAT rule. */
277 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
278 /* to the new IP address for the translation. */
279 /* ------------------------------------------------------------------------ */
nat6_newmap(fin,nat,ni)280 static INLINE int nat6_newmap(fin, nat, ni)
281 fr_info_t *fin;
282 nat_t *nat;
283 natinfo_t *ni;
284 {
285 u_short st_port, dport, sport, port, sp, dp;
286 i6addr_t in, st_ip;
287 hostmap_t *hm;
288 u_32_t flags;
289 ipnat_t *np;
290 nat_t *natl;
291 int l;
292 ipf_stack_t *ifs = fin->fin_ifs;
293
294 /*
295 * If it's an outbound packet which doesn't match any existing
296 * record, then create a new port
297 */
298 l = 0;
299 hm = NULL;
300 np = ni->nai_np;
301 st_ip = np->in_next6;
302 st_port = np->in_pnext;
303 flags = ni->nai_flags;
304 sport = ni->nai_sport;
305 dport = ni->nai_dport;
306
307 /*
308 * Do a loop until we either run out of entries to try or we find
309 * a NAT mapping that isn't currently being used. This is done
310 * because the change to the source is not (usually) being fixed.
311 */
312 do {
313 port = 0;
314 in = np->in_next6;
315 if (l == 0) {
316 /*
317 * Check to see if there is an existing NAT
318 * setup for this IP address pair.
319 */
320 hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
321 &in, 0, ifs);
322 if (hm != NULL)
323 in = hm->hm_map;
324 } else if ((l == 1) && (hm != NULL)) {
325 fr_hostmapdel(&hm);
326 }
327
328 nat->nat_hm = hm;
329
330 if (IP6_ISONES(&np->in_out[1]) && (np->in_pnext == 0)) {
331 if (l > 0)
332 return -1;
333 }
334
335 if (np->in_redir == NAT_BIMAP &&
336 IP6_EQ(&np->in_in[1], &np->in_out[1])) {
337 i6addr_t temp;
338 /*
339 * map the address block in a 1:1 fashion
340 */
341 temp.i6[0] = fin->fin_src6.i6[0] &
342 ~np->in_in[1].i6[0];
343 temp.i6[1] = fin->fin_src6.i6[1] &
344 ~np->in_in[1].i6[1];
345 temp.i6[2] = fin->fin_src6.i6[2] &
346 ~np->in_in[1].i6[2];
347 temp.i6[3] = fin->fin_src6.i6[3] &
348 ~np->in_in[1].i6[3];
349 in = np->in_out[0];
350 IP6_MERGE(&in, &temp, &np->in_in[0]);
351
352 #ifdef NEED_128BIT_MATH
353 } else if (np->in_redir & NAT_MAPBLK) {
354 if ((l >= np->in_ppip) || ((l > 0) &&
355 !(flags & IPN_TCPUDP)))
356 return -1;
357 /*
358 * map-block - Calculate destination address.
359 */
360 IP6_MASK(&in, &fin->fin_src6, &np->in_in[1]);
361 in = ntol(in);
362 inb = in;
363 in /= np->in_ippip;
364 in &= ntohl(~np->in_out[1]);
365 in += ntohl(np->in_out[0]);
366 /*
367 * Calculate destination port.
368 */
369 if ((flags & IPN_TCPUDP) &&
370 (np->in_ppip != 0)) {
371 port = ntohs(sport) + l;
372 port %= np->in_ppip;
373 port += np->in_ppip *
374 (inb.s_addr % np->in_ippip);
375 port += MAPBLK_MINPORT;
376 port = htons(port);
377 }
378 #endif
379
380 } else if (IP6_ISZERO(&np->in_out[0]) &&
381 IP6_ISONES(&np->in_out[1])) {
382 /*
383 * 0/128 - use the interface's IP address.
384 */
385 if ((l > 0) ||
386 fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp,
387 (void *)&in, NULL, fin->fin_ifs) == -1)
388 return -1;
389
390 } else if (IP6_ISZERO(&np->in_out[0]) &&
391 IP6_ISZERO(&np->in_out[1])) {
392 /*
393 * 0/0 - use the original source address/port.
394 */
395 if (l > 0)
396 return -1;
397 in = fin->fin_src6;
398
399 } else if (!IP6_ISONES(&np->in_out[1]) &&
400 (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) {
401 IP6_INC(&np->in_next6);
402 }
403
404 natl = NULL;
405
406 if ((flags & IPN_TCPUDP) &&
407 ((np->in_redir & NAT_MAPBLK) == 0) &&
408 (np->in_flags & IPN_AUTOPORTMAP)) {
409 /*EMPTY*/;
410 #ifdef NEED_128BIT_MATH
411 /*
412 * XXX "ports auto" (without map-block)
413 */
414 if ((l > 0) && (l % np->in_ppip == 0)) {
415 if (l > np->in_space) {
416 return -1;
417 } else if ((l > np->in_ppip) &&
418 !IP6_ISONES(&np->in_out[1])) {
419 IP6_INC(&np->in_next6);
420 }
421 }
422 if (np->in_ppip != 0) {
423 port = ntohs(sport);
424 port += (l % np->in_ppip);
425 port %= np->in_ppip;
426 port += np->in_ppip *
427 (ntohl(fin->fin_src6) %
428 np->in_ippip);
429 port += MAPBLK_MINPORT;
430 port = htons(port);
431 }
432 #endif
433
434 } else if (((np->in_redir & NAT_MAPBLK) == 0) &&
435 (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) {
436 /*
437 * Standard port translation. Select next port.
438 */
439 if (np->in_flags & IPN_SEQUENTIAL) {
440 port = np->in_pnext;
441 } else {
442 port = ipf_random() % (ntohs(np->in_pmax) -
443 ntohs(np->in_pmin));
444 port += ntohs(np->in_pmin);
445 }
446 port = htons(port);
447 np->in_pnext++;
448
449 if (np->in_pnext > ntohs(np->in_pmax)) {
450 np->in_pnext = ntohs(np->in_pmin);
451 if (!IP6_ISONES(&np->in_out[1])) {
452 IP6_INC(&np->in_next6);
453 }
454 }
455 }
456
457 if (np->in_flags & IPN_IPRANGE) {
458 if (IP6_GT(&np->in_next6, &np->in_out[1]))
459 np->in_next6 = np->in_out[0];
460 } else {
461 i6addr_t a1, a2;
462
463 a1 = np->in_next6;
464 IP6_INC(&a1);
465 IP6_AND(&a1, &np->in_out[1], &a2);
466 if (!IP6_ISONES(&np->in_out[1]) &&
467 IP6_GT(&a2, &np->in_out[0])) {
468 IP6_ADD(&np->in_out[0], 1, &np->in_next6);
469 }
470 }
471
472 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
473 port = sport;
474
475 /*
476 * Here we do a lookup of the connection as seen from
477 * the outside. If an IP# pair already exists, try
478 * again. So if you have A->B becomes C->B, you can
479 * also have D->E become C->E but not D->B causing
480 * another C->B. Also take protocol and ports into
481 * account when determining whether a pre-existing
482 * NAT setup will cause an external conflict where
483 * this is appropriate.
484 */
485 sp = fin->fin_data[0];
486 dp = fin->fin_data[1];
487 fin->fin_data[0] = fin->fin_data[1];
488 fin->fin_data[1] = htons(port);
489 natl = nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
490 (u_int)fin->fin_p, &fin->fin_dst6.in6, &in.in6);
491 fin->fin_data[0] = sp;
492 fin->fin_data[1] = dp;
493
494 /*
495 * Has the search wrapped around and come back to the
496 * start ?
497 */
498 if ((natl != NULL) &&
499 (np->in_pnext != 0) && (st_port == np->in_pnext) &&
500 !IP6_ISZERO(&np->in_next6) &&
501 IP6_EQ(&st_ip, &np->in_next6))
502 return -1;
503 l++;
504 } while (natl != NULL);
505
506 if (np->in_space > 0)
507 np->in_space--;
508
509 /* Setup the NAT table */
510 nat->nat_inip6 = fin->fin_src6;
511 nat->nat_outip6 = in;
512 nat->nat_oip6 = fin->fin_dst6;
513 if (nat->nat_hm == NULL)
514 nat->nat_hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
515 &nat->nat_outip6, 0, ifs);
516
517 if (flags & IPN_TCPUDP) {
518 nat->nat_inport = sport;
519 nat->nat_outport = port; /* sport */
520 nat->nat_oport = dport;
521 ((tcphdr_t *)fin->fin_dp)->th_sport = port;
522 } else if (flags & IPN_ICMPQUERY) {
523 ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port;
524 nat->nat_inport = port;
525 nat->nat_outport = port;
526 }
527
528 ni->nai_port = port;
529 ni->nai_nport = dport;
530 return 0;
531 }
532
533
534 /* ------------------------------------------------------------------------ */
535 /* Function: nat6_newrdr */
536 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
537 /* allow rule to be moved if IPN_ROUNDR is set. */
538 /* Parameters: fin(I) - pointer to packet information */
539 /* nat(I) - pointer to NAT entry */
540 /* ni(I) - pointer to structure with misc. information needed */
541 /* to create new NAT entry. */
542 /* */
543 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
544 /* to the new IP address for the translation. */
545 /* ------------------------------------------------------------------------ */
nat6_newrdr(fin,nat,ni)546 static INLINE int nat6_newrdr(fin, nat, ni)
547 fr_info_t *fin;
548 nat_t *nat;
549 natinfo_t *ni;
550 {
551 u_short nport, dport, sport;
552 i6addr_t in;
553 u_short sp, dp;
554 hostmap_t *hm;
555 u_32_t flags;
556 ipnat_t *np;
557 nat_t *natl;
558 int move;
559 ipf_stack_t *ifs = fin->fin_ifs;
560
561 move = 1;
562 hm = NULL;
563 in.i6[0] = 0;
564 in.i6[1] = 0;
565 in.i6[2] = 0;
566 in.i6[3] = 0;
567 np = ni->nai_np;
568 flags = ni->nai_flags;
569 sport = ni->nai_sport;
570 dport = ni->nai_dport;
571
572 /*
573 * If the matching rule has IPN_STICKY set, then we want to have the
574 * same rule kick in as before. Why would this happen? If you have
575 * a collection of rdr rules with "round-robin sticky", the current
576 * packet might match a different one to the previous connection but
577 * we want the same destination to be used.
578 */
579 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) ==
580 (IPN_ROUNDR|IPN_STICKY)) {
581 hm = nat6_hostmap(NULL, &fin->fin_src6, &fin->fin_dst6, &in,
582 (u_32_t)dport, ifs);
583 if (hm != NULL) {
584 in = hm->hm_map;
585 np = hm->hm_ipnat;
586 ni->nai_np = np;
587 move = 0;
588 }
589 }
590
591 /*
592 * Otherwise, it's an inbound packet. Most likely, we don't
593 * want to rewrite source ports and source addresses. Instead,
594 * we want to rewrite to a fixed internal address and fixed
595 * internal port.
596 */
597 if (np->in_flags & IPN_SPLIT) {
598 in = np->in_next6;
599
600 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
601 hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
602 &in, (u_32_t)dport, ifs);
603 if (hm != NULL) {
604 in = hm->hm_map;
605 move = 0;
606 }
607 }
608
609 if (hm == NULL || hm->hm_ref == 1) {
610 if (IP6_EQ(&np->in_in[0], &in)) {
611 np->in_next6 = np->in_in[1];
612 move = 0;
613 } else {
614 np->in_next6 = np->in_in[0];
615 }
616 }
617
618 } else if (IP6_ISZERO(&np->in_in[0]) &&
619 IP6_ISONES(&np->in_in[1])) {
620 /*
621 * 0/128 - use the interface's IP address.
622 */
623 if (fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp, (void *)&in, NULL,
624 fin->fin_ifs) == -1)
625 return -1;
626
627 } else if (IP6_ISZERO(&np->in_in[0]) &&
628 IP6_ISZERO(&np->in_in[1])) {
629 /*
630 * 0/0 - use the original destination address/port.
631 */
632 in = fin->fin_dst6;
633
634 } else if (np->in_redir == NAT_BIMAP &&
635 IP6_EQ(&np->in_in[1], &np->in_out[1])) {
636 i6addr_t temp;
637 /*
638 * map the address block in a 1:1 fashion
639 */
640 temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_in[1].i6[0];
641 temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_in[1].i6[1];
642 temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_in[1].i6[2];
643 temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_in[1].i6[3];
644 in = np->in_in[0];
645 IP6_MERGE(&in, &temp, &np->in_in[1]);
646 } else {
647 in = np->in_in[0];
648 }
649
650 if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
651 nport = dport;
652 else {
653 /*
654 * Whilst not optimized for the case where
655 * pmin == pmax, the gain is not significant.
656 */
657 if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
658 (np->in_pmin != np->in_pmax)) {
659 nport = ntohs(dport) - ntohs(np->in_pmin) +
660 ntohs(np->in_pnext);
661 nport = htons(nport);
662 } else
663 nport = np->in_pnext;
664 }
665
666 /*
667 * When the redirect-to address is set to 0.0.0.0, just
668 * assume a blank `forwarding' of the packet. We don't
669 * setup any translation for this either.
670 */
671 if (IP6_ISZERO(&in)) {
672 if (nport == dport)
673 return -1;
674 in = fin->fin_dst6;
675 }
676
677 /*
678 * Check to see if this redirect mapping already exists and if
679 * it does, return "failure" (allowing it to be created will just
680 * cause one or both of these "connections" to stop working.)
681 */
682 sp = fin->fin_data[0];
683 dp = fin->fin_data[1];
684 fin->fin_data[1] = fin->fin_data[0];
685 fin->fin_data[0] = ntohs(nport);
686 natl = nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
687 (u_int)fin->fin_p, &in.in6, &fin->fin_src6.in6);
688 fin->fin_data[0] = sp;
689 fin->fin_data[1] = dp;
690 if (natl != NULL)
691 return -1;
692
693 nat->nat_inip6 = in;
694 nat->nat_outip6 = fin->fin_dst6;
695 nat->nat_oip6 = fin->fin_src6;
696 if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
697 nat->nat_hm = nat6_hostmap(np, &fin->fin_src6,
698 &fin->fin_dst6, &in, (u_32_t)dport, ifs);
699
700 ni->nai_nport = nport;
701 ni->nai_port = sport;
702
703 if (flags & IPN_TCPUDP) {
704 nat->nat_inport = nport;
705 nat->nat_outport = dport;
706 nat->nat_oport = sport;
707 ((tcphdr_t *)fin->fin_dp)->th_dport = nport;
708 } else if (flags & IPN_ICMPQUERY) {
709 ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport;
710 nat->nat_inport = nport;
711 nat->nat_outport = nport;
712 }
713
714 return move;
715 }
716
717 /* ------------------------------------------------------------------------ */
718 /* Function: nat6_new */
719 /* Returns: nat_t* - NULL == failure to create new NAT structure, */
720 /* else pointer to new NAT structure */
721 /* Parameters: fin(I) - pointer to packet information */
722 /* np(I) - pointer to NAT rule */
723 /* natsave(I) - pointer to where to store NAT struct pointer */
724 /* flags(I) - flags describing the current packet */
725 /* direction(I) - direction of packet (in/out) */
726 /* Write Lock: ipf_nat */
727 /* */
728 /* Attempts to create a new NAT entry. Does not actually change the packet */
729 /* in any way. */
730 /* */
731 /* This fucntion is in three main parts: (1) deal with creating a new NAT */
732 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */
733 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
734 /* and (3) building that structure and putting it into the NAT table(s). */
735 /* ------------------------------------------------------------------------ */
nat6_new(fin,np,natsave,flags,direction)736 nat_t *nat6_new(fin, np, natsave, flags, direction)
737 fr_info_t *fin;
738 ipnat_t *np;
739 nat_t **natsave;
740 u_int flags;
741 int direction;
742 {
743 tcphdr_t *tcp = NULL;
744 hostmap_t *hm = NULL;
745 nat_t *nat, *natl;
746 u_int nflags;
747 natinfo_t ni;
748 int move;
749 ipf_stack_t *ifs = fin->fin_ifs;
750
751 /*
752 * Trigger automatic call to ipf_extraflush() if the
753 * table has reached capcity specified by hi watermark.
754 */
755 if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi)
756 ifs->ifs_nat_doflush = 1;
757
758 if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
759 ifs->ifs_nat_stats.ns_memfail++;
760 return NULL;
761 }
762
763 move = 1;
764 nflags = np->in_flags & flags;
765 nflags &= NAT_FROMRULE;
766
767 ni.nai_np = np;
768 ni.nai_nflags = nflags;
769 ni.nai_flags = flags;
770
771 /* Give me a new nat */
772 KMALLOC(nat, nat_t *);
773 if (nat == NULL) {
774 ifs->ifs_nat_stats.ns_memfail++;
775 /*
776 * Try to automatically tune the max # of entries in the
777 * table allowed to be less than what will cause kmem_alloc()
778 * to fail and try to eliminate panics due to out of memory
779 * conditions arising.
780 */
781 if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) {
782 ifs->ifs_ipf_nattable_max =
783 ifs->ifs_nat_stats.ns_inuse - 100;
784 printf("ipf_nattable_max reduced to %d\n",
785 ifs->ifs_ipf_nattable_max);
786 }
787 return NULL;
788 }
789
790 if (flags & IPN_TCPUDP) {
791 tcp = fin->fin_dp;
792 ni.nai_sport = htons(fin->fin_sport);
793 ni.nai_dport = htons(fin->fin_dport);
794 } else if (flags & IPN_ICMPQUERY) {
795 /*
796 * In the ICMP query NAT code, we translate the ICMP id fields
797 * to make them unique. This is indepedent of the ICMP type
798 * (e.g. in the unlikely event that a host sends an echo and
799 * an tstamp request with the same id, both packets will have
800 * their ip address/id field changed in the same way).
801 *
802 * The icmp_id field is used by the sender to identify the
803 * process making the icmp request. (the receiver justs
804 * copies it back in its response). So, it closely matches
805 * the concept of source port. We overlay sport, so we can
806 * maximally reuse the existing code.
807 */
808 ni.nai_sport = ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id;
809 ni.nai_dport = ni.nai_sport;
810 }
811
812 bzero((char *)nat, sizeof (*nat));
813 nat->nat_flags = flags;
814 nat->nat_redir = np->in_redir;
815
816 if ((flags & NAT_SLAVE) == 0) {
817 MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
818 }
819
820 /*
821 * Search the current table for a match.
822 */
823 if (direction == NAT_OUTBOUND) {
824 /*
825 * We can now arrange to call this for the same connection
826 * because ipf_nat_new doesn't protect the code path into
827 * this function.
828 */
829 natl = nat6_outlookup(fin, nflags, (u_int)fin->fin_p,
830 &fin->fin_src6.in6, &fin->fin_dst6.in6);
831 if (natl != NULL) {
832 KFREE(nat);
833 nat = natl;
834 goto done;
835 }
836
837 move = nat6_newmap(fin, nat, &ni);
838 if (move == -1)
839 goto badnat;
840
841 np = ni.nai_np;
842 } else {
843 /*
844 * NAT_INBOUND is used only for redirects rules
845 */
846 natl = nat6_inlookup(fin, nflags, (u_int)fin->fin_p,
847 &fin->fin_src6.in6, &fin->fin_dst6.in6);
848 if (natl != NULL) {
849 KFREE(nat);
850 nat = natl;
851 goto done;
852 }
853
854 move = nat6_newrdr(fin, nat, &ni);
855 if (move == -1)
856 goto badnat;
857
858 np = ni.nai_np;
859 }
860
861 if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
862 if (np->in_redir == NAT_REDIRECT) {
863 nat_delrdr(np);
864 nat6_addrdr(np, ifs);
865 } else if (np->in_redir == NAT_MAP) {
866 nat_delnat(np);
867 nat6_addnat(np, ifs);
868 }
869 }
870
871 if (nat6_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
872 goto badnat;
873 }
874
875 nat_calc_chksum_diffs(nat);
876
877 if (flags & SI_WILDP)
878 ifs->ifs_nat_stats.ns_wilds++;
879 goto done;
880 badnat:
881 ifs->ifs_nat_stats.ns_badnat++;
882 if ((hm = nat->nat_hm) != NULL)
883 fr_hostmapdel(&hm);
884 KFREE(nat);
885 nat = NULL;
886 done:
887 if ((flags & NAT_SLAVE) == 0) {
888 MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
889 }
890 return nat;
891 }
892
893
894 /* ------------------------------------------------------------------------ */
895 /* Function: nat6_finalise */
896 /* Returns: int - 0 == sucess, -1 == failure */
897 /* Parameters: fin(I) - pointer to packet information */
898 /* nat(I) - pointer to NAT entry */
899 /* ni(I) - pointer to structure with misc. information needed */
900 /* to create new NAT entry. */
901 /* Write Lock: ipf_nat */
902 /* */
903 /* This is the tail end of constructing a new NAT entry and is the same */
904 /* for both IPv4 and IPv6. */
905 /* ------------------------------------------------------------------------ */
906 /*ARGSUSED*/
nat6_finalise(fin,nat,ni,tcp,natsave,direction)907 static INLINE int nat6_finalise(fin, nat, ni, tcp, natsave, direction)
908 fr_info_t *fin;
909 nat_t *nat;
910 natinfo_t *ni;
911 tcphdr_t *tcp;
912 nat_t **natsave;
913 int direction;
914 {
915 frentry_t *fr;
916 ipnat_t *np;
917 ipf_stack_t *ifs = fin->fin_ifs;
918
919 np = ni->nai_np;
920
921 COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v);
922
923 #ifdef IPFILTER_SYNC
924 if ((nat->nat_flags & SI_CLONE) == 0)
925 nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
926 #endif
927
928 nat->nat_me = natsave;
929 nat->nat_dir = direction;
930 nat->nat_ifps[0] = np->in_ifps[0];
931 nat->nat_ifps[1] = np->in_ifps[1];
932 nat->nat_ptr = np;
933 nat->nat_p = fin->fin_p;
934 nat->nat_v = fin->fin_v;
935 nat->nat_mssclamp = np->in_mssclamp;
936 fr = fin->fin_fr;
937 nat->nat_fr = fr;
938 nat->nat_v = 6;
939
940 #ifdef IPF_V6_PROXIES
941 if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
942 if (appr_new(fin, nat) == -1)
943 return -1;
944 #endif
945
946 if (nat6_insert(nat, fin->fin_rev, ifs) == 0) {
947 if (ifs->ifs_nat_logging)
948 nat_log(nat, (u_int)np->in_redir, ifs);
949 np->in_use++;
950 if (fr != NULL) {
951 MUTEX_ENTER(&fr->fr_lock);
952 fr->fr_ref++;
953 MUTEX_EXIT(&fr->fr_lock);
954 }
955 return 0;
956 }
957
958 /*
959 * nat6_insert failed, so cleanup time...
960 */
961 return -1;
962 }
963
964
965 /* ------------------------------------------------------------------------ */
966 /* Function: nat6_insert */
967 /* Returns: int - 0 == sucess, -1 == failure */
968 /* Parameters: nat(I) - pointer to NAT structure */
969 /* rev(I) - flag indicating forward/reverse direction of packet */
970 /* Write Lock: ipf_nat */
971 /* */
972 /* Insert a NAT entry into the hash tables for searching and add it to the */
973 /* list of active NAT entries. Adjust global counters when complete. */
974 /* ------------------------------------------------------------------------ */
nat6_insert(nat,rev,ifs)975 int nat6_insert(nat, rev, ifs)
976 nat_t *nat;
977 int rev;
978 ipf_stack_t *ifs;
979 {
980 u_int hv1, hv2;
981 nat_t **natp;
982
983 /*
984 * Try and return an error as early as possible, so calculate the hash
985 * entry numbers first and then proceed.
986 */
987 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
988 hv1 = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport,
989 0xffffffff);
990 hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1 + nat->nat_oport,
991 ifs->ifs_ipf_nattable_sz);
992 hv2 = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport,
993 0xffffffff);
994 hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2 + nat->nat_oport,
995 ifs->ifs_ipf_nattable_sz);
996 } else {
997 hv1 = NAT_HASH_FN6(&nat->nat_inip6, 0, 0xffffffff);
998 hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1,
999 ifs->ifs_ipf_nattable_sz);
1000 hv2 = NAT_HASH_FN6(&nat->nat_outip6, 0, 0xffffffff);
1001 hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2,
1002 ifs->ifs_ipf_nattable_sz);
1003 }
1004
1005 if ((ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >=
1006 ifs->ifs_fr_nat_maxbucket) ||
1007 (ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >=
1008 ifs->ifs_fr_nat_maxbucket)) {
1009 return -1;
1010 }
1011
1012 nat->nat_hv[0] = hv1;
1013 nat->nat_hv[1] = hv2;
1014
1015 MUTEX_INIT(&nat->nat_lock, "nat entry lock");
1016
1017 nat->nat_rev = rev;
1018 nat->nat_ref = 1;
1019 nat->nat_bytes[0] = 0;
1020 nat->nat_pkts[0] = 0;
1021 nat->nat_bytes[1] = 0;
1022 nat->nat_pkts[1] = 0;
1023
1024 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
1025 nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 6, ifs);
1026
1027 if (nat->nat_ifnames[1][0] !='\0') {
1028 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1029 nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 6, ifs);
1030 } else {
1031 (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0],
1032 LIFNAMSIZ);
1033 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1034 nat->nat_ifps[1] = nat->nat_ifps[0];
1035 }
1036
1037 nat->nat_next = ifs->ifs_nat_instances;
1038 nat->nat_pnext = &ifs->ifs_nat_instances;
1039 if (ifs->ifs_nat_instances)
1040 ifs->ifs_nat_instances->nat_pnext = &nat->nat_next;
1041 ifs->ifs_nat_instances = nat;
1042
1043 natp = &ifs->ifs_nat_table[0][hv1];
1044 if (*natp)
1045 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
1046 nat->nat_phnext[0] = natp;
1047 nat->nat_hnext[0] = *natp;
1048 *natp = nat;
1049 ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++;
1050
1051 natp = &ifs->ifs_nat_table[1][hv2];
1052 if (*natp)
1053 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
1054 nat->nat_phnext[1] = natp;
1055 nat->nat_hnext[1] = *natp;
1056 *natp = nat;
1057 ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++;
1058
1059 fr_setnatqueue(nat, rev, ifs);
1060
1061 ifs->ifs_nat_stats.ns_added++;
1062 ifs->ifs_nat_stats.ns_inuse++;
1063 return 0;
1064 }
1065
1066
1067 /* ------------------------------------------------------------------------ */
1068 /* Function: nat6_icmperrorlookup */
1069 /* Returns: nat_t* - point to matching NAT structure */
1070 /* Parameters: fin(I) - pointer to packet information */
1071 /* dir(I) - direction of packet (in/out) */
1072 /* */
1073 /* Check if the ICMP error message is related to an existing TCP, UDP or */
1074 /* ICMP query nat entry. It is assumed that the packet is already of the */
1075 /* the required length. */
1076 /* ------------------------------------------------------------------------ */
nat6_icmperrorlookup(fin,dir)1077 nat_t *nat6_icmperrorlookup(fin, dir)
1078 fr_info_t *fin;
1079 int dir;
1080 {
1081 int flags = 0, minlen;
1082 struct icmp6_hdr *orgicmp;
1083 tcphdr_t *tcp = NULL;
1084 u_short data[2];
1085 nat_t *nat;
1086 ip6_t *oip6;
1087 u_int p;
1088
1089 minlen = 40;
1090 /*
1091 * Does it at least have the return (basic) IP header ?
1092 * Only a basic IP header (no options) should be with an ICMP error
1093 * header. Also, if it's not an error type, then return.
1094 */
1095 if (!(fin->fin_flx & FI_ICMPERR))
1096 return NULL;
1097
1098 /*
1099 * Check packet size
1100 */
1101 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
1102 return NULL;
1103 oip6 = (ip6_t *)((char *)fin->fin_dp + 8);
1104
1105 /*
1106 * Is the buffer big enough for all of it ? It's the size of the IP
1107 * header claimed in the encapsulated part which is of concern. It
1108 * may be too big to be in this buffer but not so big that it's
1109 * outside the ICMP packet, leading to TCP deref's causing problems.
1110 * This is possible because we don't know how big oip_hl is when we
1111 * do the pullup early in fr_check() and thus can't gaurantee it is
1112 * all here now.
1113 */
1114 #ifdef _KERNEL
1115 {
1116 mb_t *m;
1117
1118 m = fin->fin_m;
1119 # if defined(MENTAT)
1120 if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
1121 return NULL;
1122 # else
1123 if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
1124 (char *)fin->fin_ip + M_LEN(m))
1125 return NULL;
1126 # endif
1127 }
1128 #endif
1129
1130 if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src))
1131 return NULL;
1132
1133 p = oip6->ip6_nxt;
1134 if (p == IPPROTO_TCP)
1135 flags = IPN_TCP;
1136 else if (p == IPPROTO_UDP)
1137 flags = IPN_UDP;
1138 else if (p == IPPROTO_ICMPV6) {
1139 orgicmp = (struct icmp6_hdr *)(oip6 + 1);
1140
1141 /* see if this is related to an ICMP query */
1142 if (nat_icmpquerytype6(orgicmp->icmp6_type)) {
1143 data[0] = fin->fin_data[0];
1144 data[1] = fin->fin_data[1];
1145 fin->fin_data[0] = 0;
1146 fin->fin_data[1] = orgicmp->icmp6_id;
1147
1148 flags = IPN_ICMPERR|IPN_ICMPQUERY;
1149 /*
1150 * NOTE : dir refers to the direction of the original
1151 * ip packet. By definition the icmp error
1152 * message flows in the opposite direction.
1153 */
1154 if (dir == NAT_INBOUND)
1155 nat = nat6_inlookup(fin, flags, p,
1156 &oip6->ip6_dst, &oip6->ip6_src);
1157 else
1158 nat = nat6_outlookup(fin, flags, p,
1159 &oip6->ip6_dst, &oip6->ip6_src);
1160 fin->fin_data[0] = data[0];
1161 fin->fin_data[1] = data[1];
1162 return nat;
1163 }
1164 }
1165
1166 if (flags & IPN_TCPUDP) {
1167 minlen += 8; /* + 64bits of data to get ports */
1168 if (fin->fin_plen < ICMPERR_ICMPHLEN + minlen)
1169 return NULL;
1170
1171 data[0] = fin->fin_data[0];
1172 data[1] = fin->fin_data[1];
1173 tcp = (tcphdr_t *)(oip6 + 1);
1174 fin->fin_data[0] = ntohs(tcp->th_dport);
1175 fin->fin_data[1] = ntohs(tcp->th_sport);
1176
1177 if (dir == NAT_INBOUND) {
1178 nat = nat6_inlookup(fin, flags, p,
1179 &oip6->ip6_dst, &oip6->ip6_src);
1180 } else {
1181 nat = nat6_outlookup(fin, flags, p,
1182 &oip6->ip6_dst, &oip6->ip6_src);
1183 }
1184 fin->fin_data[0] = data[0];
1185 fin->fin_data[1] = data[1];
1186 return nat;
1187 }
1188 if (dir == NAT_INBOUND)
1189 return nat6_inlookup(fin, 0, p, &oip6->ip6_dst, &oip6->ip6_src);
1190 else
1191 return nat6_outlookup(fin, 0, p, &oip6->ip6_dst,
1192 &oip6->ip6_src);
1193 }
1194
1195
1196 /* ------------------------------------------------------------------------ */
1197 /* Function: nat6_icmperror */
1198 /* Returns: nat_t* - point to matching NAT structure */
1199 /* Parameters: fin(I) - pointer to packet information */
1200 /* nflags(I) - NAT flags for this packet */
1201 /* dir(I) - direction of packet (in/out) */
1202 /* */
1203 /* Fix up an ICMP packet which is an error message for an existing NAT */
1204 /* session. This will correct both packet header data and checksums. */
1205 /* */
1206 /* This should *ONLY* be used for incoming ICMP error packets to make sure */
1207 /* a NAT'd ICMP packet gets correctly recognised. */
1208 /* ------------------------------------------------------------------------ */
nat6_icmperror(fin,nflags,dir)1209 nat_t *nat6_icmperror(fin, nflags, dir)
1210 fr_info_t *fin;
1211 u_int *nflags;
1212 int dir;
1213 {
1214 u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd1;
1215 i6addr_t in;
1216 struct icmp6_hdr *icmp6, *orgicmp;
1217 int dlen;
1218 udphdr_t *udp;
1219 tcphdr_t *tcp;
1220 nat_t *nat;
1221 ip6_t *oip6;
1222 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY)))
1223 return NULL;
1224
1225 /*
1226 * nat6_icmperrorlookup() looks up nat entry associated with the
1227 * offending IP packet and returns pointer to the entry, or NULL
1228 * if packet wasn't natted or for `defective' packets.
1229 */
1230
1231 if ((fin->fin_v != 6) || !(nat = nat6_icmperrorlookup(fin, dir)))
1232 return NULL;
1233
1234 sumd1 = 0;
1235 *nflags = IPN_ICMPERR;
1236 icmp6 = fin->fin_dp;
1237 oip6 = (ip6_t *)((char *)icmp6 + sizeof (*icmp6));
1238 udp = (udphdr_t *)(((char *)oip6) + sizeof (*oip6));
1239 tcp = (tcphdr_t *)udp;
1240 dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip);
1241
1242 /*
1243 * Need to adjust ICMP header to include the real IP#'s and
1244 * port #'s. There are three steps required.
1245 *
1246 * Step 1
1247 * No update needed for ip6 header checksum.
1248 *
1249 * Unlike IPv4, we need to update icmp_cksum for IPv6 address
1250 * changes because there's no ip_sum change to cancel it.
1251 */
1252
1253 if (IP6_EQ((i6addr_t *)&oip6->ip6_dst, &nat->nat_oip6)) {
1254 sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_src);
1255 in = nat->nat_inip6;
1256 oip6->ip6_src = in.in6;
1257 } else {
1258 sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_dst);
1259 in = nat->nat_outip6;
1260 oip6->ip6_dst = in.in6;
1261 }
1262
1263 sum2 = LONG_SUM6(&in);
1264 CALC_SUMD(sum1, sum2, sumd);
1265
1266 /*
1267 * Step 2
1268 * Perform other adjustments based on protocol of offending packet.
1269 */
1270
1271 switch (oip6->ip6_nxt) {
1272 case IPPROTO_TCP :
1273 case IPPROTO_UDP :
1274
1275 /*
1276 * For offending TCP/UDP IP packets, translate the ports
1277 * based on the NAT specification.
1278 *
1279 * Advance notice : Now it becomes complicated :-)
1280 *
1281 * Since the port and IP addresse fields are both part
1282 * of the TCP/UDP checksum of the offending IP packet,
1283 * we need to adjust that checksum as well.
1284 *
1285 * To further complicate things, the TCP/UDP checksum
1286 * may not be present. We must check to see if the
1287 * length of the data portion is big enough to hold
1288 * the checksum. In the UDP case, a test to determine
1289 * if the checksum is even set is also required.
1290 *
1291 * Any changes to an IP address, port or checksum within
1292 * the ICMP packet requires a change to icmp_cksum.
1293 *
1294 * Be extremely careful here ... The change is dependent
1295 * upon whether or not the TCP/UPD checksum is present.
1296 *
1297 * If TCP/UPD checksum is present, the icmp_cksum must
1298 * compensate for checksum modification resulting from
1299 * IP address change only. Port change and resulting
1300 * data checksum adjustments cancel each other out.
1301 *
1302 * If TCP/UDP checksum is not present, icmp_cksum must
1303 * compensate for port change only. The IP address
1304 * change does not modify anything else in this case.
1305 */
1306
1307 psum1 = 0;
1308 psum2 = 0;
1309 psumd = 0;
1310
1311 if ((tcp->th_dport == nat->nat_oport) &&
1312 (tcp->th_sport != nat->nat_inport)) {
1313
1314 /*
1315 * Translate the source port.
1316 */
1317
1318 psum1 = ntohs(tcp->th_sport);
1319 psum2 = ntohs(nat->nat_inport);
1320 tcp->th_sport = nat->nat_inport;
1321
1322 } else if ((tcp->th_sport == nat->nat_oport) &&
1323 (tcp->th_dport != nat->nat_outport)) {
1324
1325 /*
1326 * Translate the destination port.
1327 */
1328
1329 psum1 = ntohs(tcp->th_dport);
1330 psum2 = ntohs(nat->nat_outport);
1331 tcp->th_dport = nat->nat_outport;
1332 }
1333
1334 if ((oip6->ip6_nxt == IPPROTO_TCP) && (dlen >= 18)) {
1335
1336 /*
1337 * TCP checksum present.
1338 *
1339 * Adjust data checksum and icmp checksum to
1340 * compensate for any IP address change.
1341 */
1342
1343 sum1 = ntohs(tcp->th_sum);
1344 fix_datacksum(&tcp->th_sum, sumd);
1345 sum2 = ntohs(tcp->th_sum);
1346 CALC_SUMD(sum1, sum2, sumd);
1347 sumd1 += sumd;
1348
1349 /*
1350 * Also make data checksum adjustment to
1351 * compensate for any port change.
1352 */
1353
1354 if (psum1 != psum2) {
1355 CALC_SUMD(psum1, psum2, psumd);
1356 fix_datacksum(&tcp->th_sum, psumd);
1357 }
1358
1359 } else if ((oip6->ip6_nxt == IPPROTO_UDP) &&
1360 (dlen >= 8) && (udp->uh_sum != 0)) {
1361
1362 /*
1363 * The UDP checksum is present and set.
1364 *
1365 * Adjust data checksum and icmp checksum to
1366 * compensate for any IP address change.
1367 */
1368
1369 sum1 = ntohs(udp->uh_sum);
1370 fix_datacksum(&udp->uh_sum, sumd);
1371 sum2 = ntohs(udp->uh_sum);
1372 CALC_SUMD(sum1, sum2, sumd);
1373 sumd1 += sumd;
1374
1375 /*
1376 * Also make data checksum adjustment to
1377 * compensate for any port change.
1378 */
1379
1380 if (psum1 != psum2) {
1381 CALC_SUMD(psum1, psum2, psumd);
1382 fix_datacksum(&udp->uh_sum, psumd);
1383 }
1384
1385 } else {
1386
1387 /*
1388 * Data checksum was not present.
1389 *
1390 * Compensate for any port change.
1391 */
1392
1393 CALC_SUMD(psum2, psum1, psumd);
1394 sumd1 += psumd;
1395 }
1396 break;
1397
1398 case IPPROTO_ICMPV6 :
1399
1400 orgicmp = (struct icmp6_hdr *)udp;
1401
1402 if ((nat->nat_dir == NAT_OUTBOUND) &&
1403 (orgicmp->icmp6_id != nat->nat_inport) &&
1404 (dlen >= 8)) {
1405
1406 /*
1407 * Fix ICMP checksum (of the offening ICMP
1408 * query packet) to compensate the change
1409 * in the ICMP id of the offending ICMP
1410 * packet.
1411 *
1412 * Since you modify orgicmp->icmp_id with
1413 * a delta (say x) and you compensate that
1414 * in origicmp->icmp_cksum with a delta
1415 * minus x, you don't have to adjust the
1416 * overall icmp->icmp_cksum
1417 */
1418
1419 sum1 = ntohs(orgicmp->icmp6_id);
1420 sum2 = ntohs(nat->nat_inport);
1421 CALC_SUMD(sum1, sum2, sumd);
1422 orgicmp->icmp6_id = nat->nat_inport;
1423 fix_datacksum(&orgicmp->icmp6_cksum, sumd);
1424
1425 } /* nat_dir can't be NAT_INBOUND for icmp queries */
1426
1427 break;
1428
1429 default :
1430
1431 break;
1432
1433 } /* switch (oip6->ip6_nxt) */
1434
1435 /*
1436 * Step 3
1437 * Make the adjustments to icmp checksum.
1438 */
1439
1440 if (sumd1 != 0) {
1441 sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16);
1442 sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16);
1443 fix_incksum(&icmp6->icmp6_cksum, sumd1);
1444 }
1445 return nat;
1446 }
1447
1448
1449 /*
1450 * NB: these lookups don't lock access to the list, it assumed that it has
1451 * already been done!
1452 */
1453
1454 /* ------------------------------------------------------------------------ */
1455 /* Function: nat6_inlookup */
1456 /* Returns: nat_t* - NULL == no match, */
1457 /* else pointer to matching NAT entry */
1458 /* Parameters: fin(I) - pointer to packet information */
1459 /* flags(I) - NAT flags for this packet */
1460 /* p(I) - protocol for this packet */
1461 /* src(I) - source IP address */
1462 /* mapdst(I) - destination IP address */
1463 /* */
1464 /* Lookup a nat entry based on the mapped destination ip address/port and */
1465 /* real source address/port. We use this lookup when receiving a packet, */
1466 /* we're looking for a table entry, based on the destination address. */
1467 /* */
1468 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
1469 /* */
1470 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
1471 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
1472 /* */
1473 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
1474 /* the packet is of said protocol */
1475 /* ------------------------------------------------------------------------ */
nat6_inlookup(fin,flags,p,src,mapdst)1476 nat_t *nat6_inlookup(fin, flags, p, src, mapdst)
1477 fr_info_t *fin;
1478 u_int flags, p;
1479 struct in6_addr *src, *mapdst;
1480 {
1481 u_short sport, dport;
1482 u_int sflags;
1483 nat_t *nat;
1484 int nflags;
1485 i6addr_t dst;
1486 void *ifp;
1487 u_int hv;
1488 ipf_stack_t *ifs = fin->fin_ifs;
1489
1490 if (fin != NULL)
1491 ifp = fin->fin_ifp;
1492 else
1493 ifp = NULL;
1494 sport = 0;
1495 dport = 0;
1496 dst.in6 = *mapdst;
1497 sflags = flags & NAT_TCPUDPICMP;
1498
1499 switch (p)
1500 {
1501 case IPPROTO_TCP :
1502 case IPPROTO_UDP :
1503 sport = htons(fin->fin_data[0]);
1504 dport = htons(fin->fin_data[1]);
1505 break;
1506 case IPPROTO_ICMPV6 :
1507 if (flags & IPN_ICMPERR)
1508 sport = fin->fin_data[1];
1509 else
1510 dport = fin->fin_data[1];
1511 break;
1512 default :
1513 break;
1514 }
1515
1516
1517 if ((flags & SI_WILDP) != 0)
1518 goto find_in_wild_ports;
1519
1520 hv = NAT_HASH_FN6(&dst, dport, 0xffffffff);
1521 hv = NAT_HASH_FN6(src, hv + sport, ifs->ifs_ipf_nattable_sz);
1522 nat = ifs->ifs_nat_table[1][hv];
1523 for (; nat; nat = nat->nat_hnext[1]) {
1524 if (nat->nat_v != 6)
1525 continue;
1526
1527 if (nat->nat_ifps[0] != NULL) {
1528 if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
1529 continue;
1530 } else if (ifp != NULL)
1531 nat->nat_ifps[0] = ifp;
1532
1533 nflags = nat->nat_flags;
1534
1535 if (IP6_EQ(&nat->nat_oip6, src) &&
1536 IP6_EQ(&nat->nat_outip6, &dst) &&
1537 (((p == 0) &&
1538 (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) ||
1539 (p == nat->nat_p))) {
1540 switch (p)
1541 {
1542 #if 0
1543 case IPPROTO_GRE :
1544 if (nat->nat_call[1] != fin->fin_data[0])
1545 continue;
1546 break;
1547 #endif
1548 case IPPROTO_ICMPV6 :
1549 if ((flags & IPN_ICMPERR) != 0) {
1550 if (nat->nat_outport != sport)
1551 continue;
1552 } else {
1553 if (nat->nat_outport != dport)
1554 continue;
1555 }
1556 break;
1557 case IPPROTO_TCP :
1558 case IPPROTO_UDP :
1559 if (nat->nat_oport != sport)
1560 continue;
1561 if (nat->nat_outport != dport)
1562 continue;
1563 break;
1564 default :
1565 break;
1566 }
1567
1568 #ifdef IPF_V6_PROXIES
1569 ipn = nat->nat_ptr;
1570 if ((ipn != NULL) && (nat->nat_aps != NULL))
1571 if (appr_match(fin, nat) != 0)
1572 continue;
1573 #endif
1574 return nat;
1575 }
1576 }
1577
1578 /*
1579 * So if we didn't find it but there are wildcard members in the hash
1580 * table, go back and look for them. We do this search and update here
1581 * because it is modifying the NAT table and we want to do this only
1582 * for the first packet that matches. The exception, of course, is
1583 * for "dummy" (FI_IGNORE) lookups.
1584 */
1585 find_in_wild_ports:
1586 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
1587 return NULL;
1588 if (ifs->ifs_nat_stats.ns_wilds == 0)
1589 return NULL;
1590
1591 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1592
1593 hv = NAT_HASH_FN6(&dst, 0, 0xffffffff);
1594 hv = NAT_HASH_FN6(src, hv, ifs->ifs_ipf_nattable_sz);
1595
1596 WRITE_ENTER(&ifs->ifs_ipf_nat);
1597
1598 nat = ifs->ifs_nat_table[1][hv];
1599 for (; nat; nat = nat->nat_hnext[1]) {
1600 if (nat->nat_v != 6)
1601 continue;
1602
1603 if (nat->nat_ifps[0] != NULL) {
1604 if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
1605 continue;
1606 } else if (ifp != NULL)
1607 nat->nat_ifps[0] = ifp;
1608
1609 if (nat->nat_p != fin->fin_p)
1610 continue;
1611 if (IP6_NEQ(&nat->nat_oip6, src) ||
1612 IP6_NEQ(&nat->nat_outip6, &dst))
1613 continue;
1614
1615 nflags = nat->nat_flags;
1616 if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
1617 continue;
1618
1619 if (nat_wildok(nat, (int)sport, (int)dport, nflags,
1620 NAT_INBOUND) == 1) {
1621 if ((fin->fin_flx & FI_IGNORE) != 0)
1622 break;
1623 if ((nflags & SI_CLONE) != 0) {
1624 nat = fr_natclone(fin, nat);
1625 if (nat == NULL)
1626 break;
1627 } else {
1628 MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
1629 ifs->ifs_nat_stats.ns_wilds--;
1630 MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
1631 }
1632 nat->nat_oport = sport;
1633 nat->nat_outport = dport;
1634 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
1635 nat6_tabmove(nat, ifs);
1636 break;
1637 }
1638 }
1639
1640 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
1641
1642 return nat;
1643 }
1644
1645
1646 /* ------------------------------------------------------------------------ */
1647 /* Function: nat6_tabmove */
1648 /* Returns: Nil */
1649 /* Parameters: nat(I) - pointer to NAT structure */
1650 /* Write Lock: ipf_nat */
1651 /* */
1652 /* This function is only called for TCP/UDP NAT table entries where the */
1653 /* original was placed in the table without hashing on the ports and we now */
1654 /* want to include hashing on port numbers. */
1655 /* ------------------------------------------------------------------------ */
nat6_tabmove(nat,ifs)1656 static void nat6_tabmove(nat, ifs)
1657 nat_t *nat;
1658 ipf_stack_t *ifs;
1659 {
1660 nat_t **natp;
1661 u_int hv;
1662
1663 if (nat->nat_flags & SI_CLONE)
1664 return;
1665
1666 /*
1667 * Remove the NAT entry from the old location
1668 */
1669 if (nat->nat_hnext[0])
1670 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
1671 *nat->nat_phnext[0] = nat->nat_hnext[0];
1672 ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
1673
1674 if (nat->nat_hnext[1])
1675 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
1676 *nat->nat_phnext[1] = nat->nat_hnext[1];
1677 ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
1678
1679 /*
1680 * Add into the NAT table in the new position
1681 */
1682 hv = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport, 0xffffffff);
1683 hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport,
1684 ifs->ifs_ipf_nattable_sz);
1685 nat->nat_hv[0] = hv;
1686 natp = &ifs->ifs_nat_table[0][hv];
1687 if (*natp)
1688 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
1689 nat->nat_phnext[0] = natp;
1690 nat->nat_hnext[0] = *natp;
1691 *natp = nat;
1692 ifs->ifs_nat_stats.ns_bucketlen[0][hv]++;
1693
1694 hv = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport, 0xffffffff);
1695 hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport,
1696 ifs->ifs_ipf_nattable_sz);
1697 nat->nat_hv[1] = hv;
1698 natp = &ifs->ifs_nat_table[1][hv];
1699 if (*natp)
1700 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
1701 nat->nat_phnext[1] = natp;
1702 nat->nat_hnext[1] = *natp;
1703 *natp = nat;
1704 ifs->ifs_nat_stats.ns_bucketlen[1][hv]++;
1705 }
1706
1707
1708 /* ------------------------------------------------------------------------ */
1709 /* Function: nat6_outlookup */
1710 /* Returns: nat_t* - NULL == no match, */
1711 /* else pointer to matching NAT entry */
1712 /* Parameters: fin(I) - pointer to packet information */
1713 /* flags(I) - NAT flags for this packet */
1714 /* p(I) - protocol for this packet */
1715 /* src(I) - source IP address */
1716 /* dst(I) - destination IP address */
1717 /* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */
1718 /* */
1719 /* Lookup a nat entry based on the source 'real' ip address/port and */
1720 /* destination address/port. We use this lookup when sending a packet out, */
1721 /* we're looking for a table entry, based on the source address. */
1722 /* */
1723 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
1724 /* */
1725 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
1726 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
1727 /* */
1728 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
1729 /* the packet is of said protocol */
1730 /* ------------------------------------------------------------------------ */
nat6_outlookup(fin,flags,p,src,dst)1731 nat_t *nat6_outlookup(fin, flags, p, src, dst)
1732 fr_info_t *fin;
1733 u_int flags, p;
1734 struct in6_addr *src , *dst;
1735 {
1736 u_short sport, dport;
1737 u_int sflags;
1738 nat_t *nat;
1739 int nflags;
1740 void *ifp;
1741 u_int hv;
1742 ipf_stack_t *ifs = fin->fin_ifs;
1743
1744 ifp = fin->fin_ifp;
1745
1746 sflags = flags & IPN_TCPUDPICMP;
1747 sport = 0;
1748 dport = 0;
1749
1750 switch (p)
1751 {
1752 case IPPROTO_TCP :
1753 case IPPROTO_UDP :
1754 sport = htons(fin->fin_data[0]);
1755 dport = htons(fin->fin_data[1]);
1756 break;
1757 case IPPROTO_ICMPV6 :
1758 if (flags & IPN_ICMPERR)
1759 sport = fin->fin_data[1];
1760 else
1761 dport = fin->fin_data[1];
1762 break;
1763 default :
1764 break;
1765 }
1766
1767 if ((flags & SI_WILDP) != 0)
1768 goto find_out_wild_ports;
1769
1770 hv = NAT_HASH_FN6(src, sport, 0xffffffff);
1771 hv = NAT_HASH_FN6(dst, hv + dport, ifs->ifs_ipf_nattable_sz);
1772 nat = ifs->ifs_nat_table[0][hv];
1773 for (; nat; nat = nat->nat_hnext[0]) {
1774 if (nat->nat_v != 6)
1775 continue;
1776
1777 if (nat->nat_ifps[1] != NULL) {
1778 if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
1779 continue;
1780 } else if (ifp != NULL)
1781 nat->nat_ifps[1] = ifp;
1782
1783 nflags = nat->nat_flags;
1784
1785 if (IP6_EQ(&nat->nat_inip6, src) &&
1786 IP6_EQ(&nat->nat_oip6, dst) &&
1787 (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) ||
1788 (p == nat->nat_p))) {
1789 switch (p)
1790 {
1791 #if 0
1792 case IPPROTO_GRE :
1793 if (nat->nat_call[1] != fin->fin_data[0])
1794 continue;
1795 break;
1796 #endif
1797 case IPPROTO_TCP :
1798 case IPPROTO_UDP :
1799 if (nat->nat_oport != dport)
1800 continue;
1801 if (nat->nat_inport != sport)
1802 continue;
1803 break;
1804 default :
1805 break;
1806 }
1807
1808 #ifdef IPF_V6_PROXIES
1809 ipn = nat->nat_ptr;
1810 if ((ipn != NULL) && (nat->nat_aps != NULL))
1811 if (appr_match(fin, nat) != 0)
1812 continue;
1813 #endif
1814 return nat;
1815 }
1816 }
1817
1818 /*
1819 * So if we didn't find it but there are wildcard members in the hash
1820 * table, go back and look for them. We do this search and update here
1821 * because it is modifying the NAT table and we want to do this only
1822 * for the first packet that matches. The exception, of course, is
1823 * for "dummy" (FI_IGNORE) lookups.
1824 */
1825 find_out_wild_ports:
1826 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
1827 return NULL;
1828 if (ifs->ifs_nat_stats.ns_wilds == 0)
1829 return NULL;
1830
1831 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1832
1833 hv = NAT_HASH_FN6(src, 0, 0xffffffff);
1834 hv = NAT_HASH_FN6(dst, hv, ifs->ifs_ipf_nattable_sz);
1835
1836 WRITE_ENTER(&ifs->ifs_ipf_nat);
1837
1838 nat = ifs->ifs_nat_table[0][hv];
1839 for (; nat; nat = nat->nat_hnext[0]) {
1840 if (nat->nat_v != 6)
1841 continue;
1842
1843 if (nat->nat_ifps[1] != NULL) {
1844 if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
1845 continue;
1846 } else if (ifp != NULL)
1847 nat->nat_ifps[1] = ifp;
1848
1849 if (nat->nat_p != fin->fin_p)
1850 continue;
1851 if (IP6_NEQ(&nat->nat_inip6, src) ||
1852 IP6_NEQ(&nat->nat_oip6, dst))
1853 continue;
1854
1855 nflags = nat->nat_flags;
1856 if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
1857 continue;
1858
1859 if (nat_wildok(nat, (int)sport, (int)dport, nflags,
1860 NAT_OUTBOUND) == 1) {
1861 if ((fin->fin_flx & FI_IGNORE) != 0)
1862 break;
1863 if ((nflags & SI_CLONE) != 0) {
1864 nat = fr_natclone(fin, nat);
1865 if (nat == NULL)
1866 break;
1867 } else {
1868 MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
1869 ifs->ifs_nat_stats.ns_wilds--;
1870 MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
1871 }
1872 nat->nat_inport = sport;
1873 nat->nat_oport = dport;
1874 if (nat->nat_outport == 0)
1875 nat->nat_outport = sport;
1876 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
1877 nat6_tabmove(nat, ifs);
1878 break;
1879 }
1880 }
1881
1882 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
1883
1884 return nat;
1885 }
1886
1887
1888 /* ------------------------------------------------------------------------ */
1889 /* Function: nat6_lookupredir */
1890 /* Returns: nat_t* - NULL == no match, */
1891 /* else pointer to matching NAT entry */
1892 /* Parameters: np(I) - pointer to description of packet to find NAT table */
1893 /* entry for. */
1894 /* */
1895 /* Lookup the NAT tables to search for a matching redirect */
1896 /* ------------------------------------------------------------------------ */
nat6_lookupredir(np,ifs)1897 nat_t *nat6_lookupredir(np, ifs)
1898 natlookup_t *np;
1899 ipf_stack_t *ifs;
1900 {
1901 fr_info_t fi;
1902 nat_t *nat;
1903
1904 bzero((char *)&fi, sizeof (fi));
1905 if (np->nl_flags & IPN_IN) {
1906 fi.fin_data[0] = ntohs(np->nl_realport);
1907 fi.fin_data[1] = ntohs(np->nl_outport);
1908 } else {
1909 fi.fin_data[0] = ntohs(np->nl_inport);
1910 fi.fin_data[1] = ntohs(np->nl_outport);
1911 }
1912 if (np->nl_flags & IPN_TCP)
1913 fi.fin_p = IPPROTO_TCP;
1914 else if (np->nl_flags & IPN_UDP)
1915 fi.fin_p = IPPROTO_UDP;
1916 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
1917 fi.fin_p = IPPROTO_ICMPV6;
1918
1919 fi.fin_ifs = ifs;
1920 /*
1921 * We can do two sorts of lookups:
1922 * - IPN_IN: we have the `real' and `out' address, look for `in'.
1923 * - default: we have the `in' and `out' address, look for `real'.
1924 */
1925 if (np->nl_flags & IPN_IN) {
1926 if ((nat = nat6_inlookup(&fi, np->nl_flags, fi.fin_p,
1927 &np->nl_realip6, &np->nl_outip6))) {
1928 np->nl_inipaddr = nat->nat_inip6;
1929 np->nl_inport = nat->nat_inport;
1930 }
1931 } else {
1932 /*
1933 * If nl_inip is non null, this is a lookup based on the real
1934 * ip address. Else, we use the fake.
1935 */
1936 if ((nat = nat6_outlookup(&fi, np->nl_flags, fi.fin_p,
1937 &np->nl_inip6, &np->nl_outip6))) {
1938 if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
1939 fr_info_t fin;
1940 bzero((char *)&fin, sizeof (fin));
1941 fin.fin_p = nat->nat_p;
1942 fin.fin_data[0] = ntohs(nat->nat_outport);
1943 fin.fin_data[1] = ntohs(nat->nat_oport);
1944 fin.fin_ifs = ifs;
1945 if (nat6_inlookup(&fin, np->nl_flags, fin.fin_p,
1946 &nat->nat_outip6.in6,
1947 &nat->nat_oip6.in6) != NULL) {
1948 np->nl_flags &= ~IPN_FINDFORWARD;
1949 }
1950 }
1951
1952 np->nl_realip6 = nat->nat_outip6.in6;
1953 np->nl_realport = nat->nat_outport;
1954 }
1955 }
1956
1957 return nat;
1958 }
1959
1960
1961 /* ------------------------------------------------------------------------ */
1962 /* Function: nat6_match */
1963 /* Returns: int - 0 == no match, 1 == match */
1964 /* Parameters: fin(I) - pointer to packet information */
1965 /* np(I) - pointer to NAT rule */
1966 /* */
1967 /* Pull the matching of a packet against a NAT rule out of that complex */
1968 /* loop inside fr_checknat6in() and lay it out properly in its own function.*/
1969 /* ------------------------------------------------------------------------ */
nat6_match(fin,np)1970 static int nat6_match(fin, np)
1971 fr_info_t *fin;
1972 ipnat_t *np;
1973 {
1974 frtuc_t *ft;
1975
1976 if (fin->fin_v != 6)
1977 return 0;
1978
1979 if (np->in_p && fin->fin_p != np->in_p)
1980 return 0;
1981
1982 if (fin->fin_out) {
1983 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
1984 return 0;
1985 if (IP6_MASKNEQ(&fin->fin_src6, &np->in_in[1], &np->in_in[0])
1986 ^ ((np->in_flags & IPN_NOTSRC) != 0))
1987 return 0;
1988 if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_src[1], &np->in_src[0])
1989 ^ ((np->in_flags & IPN_NOTDST) != 0))
1990 return 0;
1991 } else {
1992 if (!(np->in_redir & NAT_REDIRECT))
1993 return 0;
1994 if (IP6_MASKNEQ(&fin->fin_src6, &np->in_src[1], &np->in_src[0])
1995 ^ ((np->in_flags & IPN_NOTSRC) != 0))
1996 return 0;
1997 if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_out[1], &np->in_out[0])
1998 ^ ((np->in_flags & IPN_NOTDST) != 0))
1999 return 0;
2000 }
2001
2002 ft = &np->in_tuc;
2003 if (!(fin->fin_flx & FI_TCPUDP) ||
2004 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
2005 if (ft->ftu_scmp || ft->ftu_dcmp)
2006 return 0;
2007 return 1;
2008 }
2009
2010 return fr_tcpudpchk(fin, ft);
2011 }
2012
2013
2014 /* ------------------------------------------------------------------------ */
2015 /* Function: fr_checknat6out */
2016 /* Returns: int - -1 == packet failed NAT checks so block it, */
2017 /* 0 == no packet translation occurred, */
2018 /* 1 == packet was successfully translated. */
2019 /* Parameters: fin(I) - pointer to packet information */
2020 /* passp(I) - pointer to filtering result flags */
2021 /* */
2022 /* Check to see if an outcoming packet should be changed. ICMP packets are */
2023 /* first checked to see if they match an existing entry (if an error), */
2024 /* otherwise a search of the current NAT table is made. If neither results */
2025 /* in a match then a search for a matching NAT rule is made. Create a new */
2026 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */
2027 /* packet header(s) as required. */
2028 /* ------------------------------------------------------------------------ */
fr_checknat6out(fin,passp)2029 int fr_checknat6out(fin, passp)
2030 fr_info_t *fin;
2031 u_32_t *passp;
2032 {
2033 struct ifnet *ifp, *sifp;
2034 int rval, natfailed;
2035 ipnat_t *np = NULL;
2036 u_int nflags = 0;
2037 i6addr_t ipa, iph;
2038 int natadd = 1;
2039 frentry_t *fr;
2040 nat_t *nat;
2041 ipf_stack_t *ifs = fin->fin_ifs;
2042
2043 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
2044 return 0;
2045
2046 natfailed = 0;
2047 fr = fin->fin_fr;
2048 sifp = fin->fin_ifp;
2049 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) &&
2050 fr->fr_tifs[fin->fin_rev].fd_ifp &&
2051 fr->fr_tifs[fin->fin_rev].fd_ifp != (void *)-1)
2052 fin->fin_ifp = fr->fr_tifs[fin->fin_rev].fd_ifp;
2053 ifp = fin->fin_ifp;
2054
2055 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2056 switch (fin->fin_p)
2057 {
2058 case IPPROTO_TCP :
2059 nflags = IPN_TCP;
2060 break;
2061 case IPPROTO_UDP :
2062 nflags = IPN_UDP;
2063 break;
2064 case IPPROTO_ICMPV6 :
2065 /*
2066 * This is an incoming packet, so the destination is
2067 * the icmp6_id and the source port equals 0
2068 */
2069 if ((fin->fin_flx & FI_ICMPQUERY) != 0)
2070 nflags = IPN_ICMPQUERY;
2071 break;
2072 default :
2073 break;
2074 }
2075
2076 #ifdef IPF_V6_PROXIES
2077 if ((nflags & IPN_TCPUDP))
2078 tcp = fin->fin_dp;
2079 #endif
2080 }
2081
2082 ipa = fin->fin_src6;
2083
2084 READ_ENTER(&ifs->ifs_ipf_nat);
2085
2086 if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
2087 (nat = nat6_icmperror(fin, &nflags, NAT_OUTBOUND)))
2088 /*EMPTY*/;
2089 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
2090 natadd = 0;
2091 else if ((nat = nat6_outlookup(fin, nflags|NAT_SEARCH,
2092 (u_int)fin->fin_p, &fin->fin_src6.in6,
2093 &fin->fin_dst6.in6))) {
2094 nflags = nat->nat_flags;
2095 } else {
2096 u_32_t hv, nmsk;
2097 i6addr_t msk;
2098 int i;
2099
2100 /*
2101 * If there is no current entry in the nat table for this IP#,
2102 * create one for it (if there is a matching rule).
2103 */
2104 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2105 i = 3;
2106 msk.i6[0] = 0xffffffff;
2107 msk.i6[1] = 0xffffffff;
2108 msk.i6[2] = 0xffffffff;
2109 msk.i6[3] = 0xffffffff;
2110 nmsk = ifs->ifs_nat6_masks[3];
2111 WRITE_ENTER(&ifs->ifs_ipf_nat);
2112 maskloop:
2113 IP6_AND(&ipa, &msk, &iph);
2114 hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_natrules_sz);
2115 for (np = ifs->ifs_nat_rules[hv]; np; np = np->in_mnext)
2116 {
2117 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
2118 continue;
2119 if (np->in_v != 6)
2120 continue;
2121 if (np->in_p && (np->in_p != fin->fin_p))
2122 continue;
2123 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
2124 continue;
2125 if (np->in_flags & IPN_FILTER) {
2126 if (!nat6_match(fin, np))
2127 continue;
2128 } else if (!IP6_MASKEQ(&ipa, &np->in_in[1],
2129 &np->in_in[0]))
2130 continue;
2131
2132 if ((fr != NULL) &&
2133 !fr_matchtag(&np->in_tag, &fr->fr_nattag))
2134 continue;
2135
2136 #ifdef IPF_V6_PROXIES
2137 if (*np->in_plabel != '\0') {
2138 if (((np->in_flags & IPN_FILTER) == 0) &&
2139 (np->in_dport != tcp->th_dport))
2140 continue;
2141 if (appr_ok(fin, tcp, np) == 0)
2142 continue;
2143 }
2144 #endif
2145
2146 if (nat = nat6_new(fin, np, NULL, nflags,
2147 NAT_OUTBOUND)) {
2148 np->in_hits++;
2149 break;
2150 } else
2151 natfailed = -1;
2152 }
2153 if ((np == NULL) && (i >= 0)) {
2154 while (i >= 0) {
2155 while (nmsk) {
2156 msk.i6[i] = htonl(ntohl(msk.i6[i])<<1);
2157 if ((nmsk & 0x80000000) != 0) {
2158 nmsk <<= 1;
2159 goto maskloop;
2160 }
2161 nmsk <<= 1;
2162 }
2163 msk.i6[i--] = 0;
2164 if (i >= 0) {
2165 nmsk = ifs->ifs_nat6_masks[i];
2166 if (nmsk != 0)
2167 goto maskloop;
2168 }
2169 }
2170 }
2171 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
2172 }
2173
2174 if (nat != NULL) {
2175 rval = fr_nat6out(fin, nat, natadd, nflags);
2176 } else {
2177 rval = natfailed;
2178 }
2179 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2180
2181 if (rval == -1) {
2182 if (passp != NULL)
2183 *passp = FR_BLOCK;
2184 fin->fin_flx |= FI_BADNAT;
2185 }
2186 fin->fin_ifp = sifp;
2187 return rval;
2188 }
2189
2190 /* ------------------------------------------------------------------------ */
2191 /* Function: fr_nat6out */
2192 /* Returns: int - -1 == packet failed NAT checks so block it, */
2193 /* 1 == packet was successfully translated. */
2194 /* Parameters: fin(I) - pointer to packet information */
2195 /* nat(I) - pointer to NAT structure */
2196 /* natadd(I) - flag indicating if it is safe to add frag cache */
2197 /* nflags(I) - NAT flags set for this packet */
2198 /* */
2199 /* Translate a packet coming "out" on an interface. */
2200 /* ------------------------------------------------------------------------ */
fr_nat6out(fin,nat,natadd,nflags)2201 int fr_nat6out(fin, nat, natadd, nflags)
2202 fr_info_t *fin;
2203 nat_t *nat;
2204 int natadd;
2205 u_32_t nflags;
2206 {
2207 struct icmp6_hdr *icmp6;
2208 u_short *csump;
2209 tcphdr_t *tcp;
2210 ipnat_t *np;
2211 int i;
2212 ipf_stack_t *ifs = fin->fin_ifs;
2213
2214 #if SOLARIS && defined(_KERNEL)
2215 net_handle_t net_data_p = ifs->ifs_ipf_ipv6;
2216 #endif
2217
2218 tcp = NULL;
2219 icmp6 = NULL;
2220 csump = NULL;
2221 np = nat->nat_ptr;
2222
2223 if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
2224 (void) fr_nat_newfrag(fin, 0, nat);
2225
2226 MUTEX_ENTER(&nat->nat_lock);
2227 nat->nat_bytes[1] += fin->fin_plen;
2228 nat->nat_pkts[1]++;
2229 MUTEX_EXIT(&nat->nat_lock);
2230
2231 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2232 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
2233 tcp = fin->fin_dp;
2234
2235 tcp->th_sport = nat->nat_outport;
2236 fin->fin_data[0] = ntohs(nat->nat_outport);
2237 }
2238
2239 if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) {
2240 icmp6 = fin->fin_dp;
2241 icmp6->icmp6_id = nat->nat_outport;
2242 }
2243
2244 csump = nat_proto(fin, nat, nflags);
2245 }
2246
2247 fin->fin_ip6->ip6_src = nat->nat_outip6.in6;
2248 fin->fin_src6 = nat->nat_outip6;
2249
2250 nat_update(fin, nat, np);
2251
2252 /*
2253 * TCP/UDP/ICMPv6 checksum needs to be adjusted.
2254 */
2255 if (csump != NULL && (!(nflags & IPN_TCPUDP) ||
2256 !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m))) {
2257 if (nflags & IPN_TCPUDP &&
2258 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
2259 if (nat->nat_dir == NAT_OUTBOUND)
2260 fix_outcksum(csump, nat->nat_sumd[1]);
2261 else
2262 fix_incksum(csump, nat->nat_sumd[1]);
2263 } else {
2264 if (nat->nat_dir == NAT_OUTBOUND)
2265 fix_outcksum(csump, nat->nat_sumd[0]);
2266 else
2267 fix_incksum(csump, nat->nat_sumd[0]);
2268 }
2269 }
2270 #ifdef IPFILTER_SYNC
2271 ipfsync_update(SMC_NAT, fin, nat->nat_sync);
2272 #endif
2273 /* ------------------------------------------------------------- */
2274 /* A few quick notes: */
2275 /* Following are test conditions prior to calling the */
2276 /* appr_check routine. */
2277 /* */
2278 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
2279 /* with a redirect rule, we attempt to match the packet's */
2280 /* source port against in_dport, otherwise we'd compare the */
2281 /* packet's destination. */
2282 /* ------------------------------------------------------------- */
2283 if ((np != NULL) && (np->in_apr != NULL)) {
2284 i = appr_check(fin, nat);
2285 if (i == 0)
2286 i = 1;
2287 } else
2288 i = 1;
2289 ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[1]);
2290 fin->fin_flx |= FI_NATED;
2291 return i;
2292 }
2293
2294
2295 /* ------------------------------------------------------------------------ */
2296 /* Function: fr_checknat6in */
2297 /* Returns: int - -1 == packet failed NAT checks so block it, */
2298 /* 0 == no packet translation occurred, */
2299 /* 1 == packet was successfully translated. */
2300 /* Parameters: fin(I) - pointer to packet information */
2301 /* passp(I) - pointer to filtering result flags */
2302 /* */
2303 /* Check to see if an incoming packet should be changed. ICMP packets are */
2304 /* first checked to see if they match an existing entry (if an error), */
2305 /* otherwise a search of the current NAT table is made. If neither results */
2306 /* in a match then a search for a matching NAT rule is made. Create a new */
2307 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */
2308 /* packet header(s) as required. */
2309 /* ------------------------------------------------------------------------ */
fr_checknat6in(fin,passp)2310 int fr_checknat6in(fin, passp)
2311 fr_info_t *fin;
2312 u_32_t *passp;
2313 {
2314 u_int nflags, natadd;
2315 int rval, natfailed;
2316 struct ifnet *ifp;
2317 struct icmp6_hdr *icmp6;
2318 tcphdr_t *tcp;
2319 u_short dport;
2320 ipnat_t *np;
2321 nat_t *nat;
2322 i6addr_t ipa, iph;
2323 ipf_stack_t *ifs = fin->fin_ifs;
2324
2325 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
2326 return 0;
2327
2328 tcp = NULL;
2329 icmp6 = NULL;
2330 dport = 0;
2331 natadd = 1;
2332 nflags = 0;
2333 natfailed = 0;
2334 ifp = fin->fin_ifp;
2335
2336 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2337 switch (fin->fin_p)
2338 {
2339 case IPPROTO_TCP :
2340 nflags = IPN_TCP;
2341 break;
2342 case IPPROTO_UDP :
2343 nflags = IPN_UDP;
2344 break;
2345 case IPPROTO_ICMPV6 :
2346 icmp6 = fin->fin_dp;
2347
2348 /*
2349 * This is an incoming packet, so the destination is
2350 * the icmp_id and the source port equals 0
2351 */
2352 if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
2353 nflags = IPN_ICMPQUERY;
2354 dport = icmp6->icmp6_id;
2355 } break;
2356 default :
2357 break;
2358 }
2359
2360 if ((nflags & IPN_TCPUDP)) {
2361 tcp = fin->fin_dp;
2362 dport = tcp->th_dport;
2363 }
2364 }
2365
2366 ipa = fin->fin_dst6;
2367
2368 READ_ENTER(&ifs->ifs_ipf_nat);
2369
2370 if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
2371 (nat = nat6_icmperror(fin, &nflags, NAT_INBOUND)))
2372 /*EMPTY*/;
2373 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
2374 natadd = 0;
2375 else if ((nat = nat6_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
2376 &fin->fin_src6.in6, &ipa.in6))) {
2377 nflags = nat->nat_flags;
2378 } else {
2379 u_32_t hv, rmsk;
2380 i6addr_t msk;
2381 int i;
2382
2383 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2384 i = 3;
2385 msk.i6[0] = 0xffffffff;
2386 msk.i6[1] = 0xffffffff;
2387 msk.i6[2] = 0xffffffff;
2388 msk.i6[3] = 0xffffffff;
2389 rmsk = ifs->ifs_rdr6_masks[3];
2390 WRITE_ENTER(&ifs->ifs_ipf_nat);
2391 /*
2392 * If there is no current entry in the nat table for this IP#,
2393 * create one for it (if there is a matching rule).
2394 */
2395 maskloop:
2396 IP6_AND(&ipa, &msk, &iph);
2397 hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_rdrrules_sz);
2398 for (np = ifs->ifs_rdr_rules[hv]; np; np = np->in_rnext) {
2399 if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
2400 continue;
2401 if (np->in_v != fin->fin_v)
2402 continue;
2403 if (np->in_p && (np->in_p != fin->fin_p))
2404 continue;
2405 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
2406 continue;
2407 if (np->in_flags & IPN_FILTER) {
2408 if (!nat6_match(fin, np))
2409 continue;
2410 } else {
2411 if (!IP6_MASKEQ(&ipa, &np->in_out[1],
2412 &np->in_out[0]))
2413 continue;
2414 if (np->in_pmin &&
2415 ((ntohs(np->in_pmax) < ntohs(dport)) ||
2416 (ntohs(dport) < ntohs(np->in_pmin))))
2417 continue;
2418 }
2419
2420 #ifdef IPF_V6_PROXIES
2421 if (*np->in_plabel != '\0') {
2422 if (!appr_ok(fin, tcp, np)) {
2423 continue;
2424 }
2425 }
2426 #endif
2427
2428 nat = nat6_new(fin, np, NULL, nflags, NAT_INBOUND);
2429 if (nat != NULL) {
2430 np->in_hits++;
2431 break;
2432 } else
2433 natfailed = -1;
2434 }
2435
2436 if ((np == NULL) && (i >= 0)) {
2437 while (i >= 0) {
2438 while (rmsk) {
2439 msk.i6[i] = htonl(ntohl(msk.i6[i])<<1);
2440 if ((rmsk & 0x80000000) != 0) {
2441 rmsk <<= 1;
2442 goto maskloop;
2443 }
2444 rmsk <<= 1;
2445 }
2446 msk.i6[i--] = 0;
2447 if (i >= 0) {
2448 rmsk = ifs->ifs_rdr6_masks[i];
2449 if (rmsk != 0)
2450 goto maskloop;
2451 }
2452 }
2453 }
2454 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
2455 }
2456 if (nat != NULL) {
2457 rval = fr_nat6in(fin, nat, natadd, nflags);
2458 } else {
2459 rval = natfailed;
2460 }
2461 RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2462
2463 if (rval == -1) {
2464 if (passp != NULL)
2465 *passp = FR_BLOCK;
2466 fin->fin_flx |= FI_BADNAT;
2467 }
2468 return rval;
2469 }
2470
2471
2472 /* ------------------------------------------------------------------------ */
2473 /* Function: fr_nat6in */
2474 /* Returns: int - -1 == packet failed NAT checks so block it, */
2475 /* 1 == packet was successfully translated. */
2476 /* Parameters: fin(I) - pointer to packet information */
2477 /* nat(I) - pointer to NAT structure */
2478 /* natadd(I) - flag indicating if it is safe to add frag cache */
2479 /* nflags(I) - NAT flags set for this packet */
2480 /* Locks Held: ipf_nat (READ) */
2481 /* */
2482 /* Translate a packet coming "in" on an interface. */
2483 /* ------------------------------------------------------------------------ */
fr_nat6in(fin,nat,natadd,nflags)2484 int fr_nat6in(fin, nat, natadd, nflags)
2485 fr_info_t *fin;
2486 nat_t *nat;
2487 int natadd;
2488 u_32_t nflags;
2489 {
2490 struct icmp6_hdr *icmp6;
2491 u_short *csump;
2492 tcphdr_t *tcp;
2493 ipnat_t *np;
2494 ipf_stack_t *ifs = fin->fin_ifs;
2495
2496 #if SOLARIS && defined(_KERNEL)
2497 net_handle_t net_data_p = ifs->ifs_ipf_ipv6;
2498 #endif
2499
2500 tcp = NULL;
2501 csump = NULL;
2502 np = nat->nat_ptr;
2503 fin->fin_fr = nat->nat_fr;
2504
2505 if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
2506 (void) fr_nat_newfrag(fin, 0, nat);
2507
2508 #ifdef IPF_V6_PROXIES
2509 if (np != NULL) {
2510
2511 /* ------------------------------------------------------------- */
2512 /* A few quick notes: */
2513 /* Following are test conditions prior to calling the */
2514 /* appr_check routine. */
2515 /* */
2516 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
2517 /* with a map rule, we attempt to match the packet's */
2518 /* source port against in_dport, otherwise we'd compare the */
2519 /* packet's destination. */
2520 /* ------------------------------------------------------------- */
2521 if (np->in_apr != NULL) {
2522 i = appr_check(fin, nat);
2523 if (i == -1) {
2524 return -1;
2525 }
2526 }
2527 }
2528 #endif
2529
2530 #ifdef IPFILTER_SYNC
2531 ipfsync_update(SMC_NAT, fin, nat->nat_sync);
2532 #endif
2533
2534 MUTEX_ENTER(&nat->nat_lock);
2535 nat->nat_bytes[0] += fin->fin_plen;
2536 nat->nat_pkts[0]++;
2537 MUTEX_EXIT(&nat->nat_lock);
2538
2539 fin->fin_ip6->ip6_dst = nat->nat_inip6.in6;
2540 fin->fin_dst6 = nat->nat_inip6;
2541
2542 if (nflags & IPN_TCPUDP)
2543 tcp = fin->fin_dp;
2544
2545 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2546 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
2547 tcp->th_dport = nat->nat_inport;
2548 fin->fin_data[1] = ntohs(nat->nat_inport);
2549 }
2550
2551
2552 if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) {
2553 icmp6 = fin->fin_dp;
2554
2555 icmp6->icmp6_id = nat->nat_inport;
2556 }
2557
2558 csump = nat_proto(fin, nat, nflags);
2559 }
2560
2561 nat_update(fin, nat, np);
2562
2563 /*
2564 * In case they are being forwarded, inbound packets always need to have
2565 * their checksum adjusted even if hardware checksum validation said OK.
2566 */
2567 if (csump != NULL) {
2568 if (nat->nat_dir == NAT_OUTBOUND)
2569 fix_incksum(csump, nat->nat_sumd[0]);
2570 else
2571 fix_outcksum(csump, nat->nat_sumd[0]);
2572 }
2573
2574 #if SOLARIS && defined(_KERNEL)
2575 if (nflags & IPN_TCPUDP &&
2576 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
2577 /*
2578 * Need to adjust the partial checksum result stored in
2579 * db_cksum16, which will be used for validation in IP.
2580 * See IP_CKSUM_RECV().
2581 * Adjustment data should be the inverse of the IP address
2582 * changes, because db_cksum16 is supposed to be the complement
2583 * of the pesudo header.
2584 */
2585 csump = &fin->fin_m->b_datap->db_cksum16;
2586 if (nat->nat_dir == NAT_OUTBOUND)
2587 fix_outcksum(csump, nat->nat_sumd[1]);
2588 else
2589 fix_incksum(csump, nat->nat_sumd[1]);
2590 }
2591 #endif
2592
2593 ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[0]);
2594 fin->fin_flx |= FI_NATED;
2595 if (np != NULL && np->in_tag.ipt_num[0] != 0)
2596 fin->fin_nattag = &np->in_tag;
2597 return 1;
2598 }
2599
2600
2601 /* ------------------------------------------------------------------------ */
2602 /* Function: nat_icmpquerytype6 */
2603 /* Returns: int - 1 == success, 0 == failure */
2604 /* Parameters: icmptype(I) - ICMP type number */
2605 /* */
2606 /* Tests to see if the ICMP type number passed is a query/response type or */
2607 /* not. */
2608 /* ------------------------------------------------------------------------ */
nat_icmpquerytype6(icmptype)2609 static INLINE int nat_icmpquerytype6(icmptype)
2610 int icmptype;
2611 {
2612
2613 /*
2614 * For the ICMP query NAT code, it is essential that both the query
2615 * and the reply match on the NAT rule. Because the NAT structure
2616 * does not keep track of the icmptype, and a single NAT structure
2617 * is used for all icmp types with the same src, dest and id, we
2618 * simply define the replies as queries as well. The funny thing is,
2619 * altough it seems silly to call a reply a query, this is exactly
2620 * as it is defined in the IPv4 specification
2621 */
2622
2623 switch (icmptype)
2624 {
2625
2626 case ICMP6_ECHO_REPLY:
2627 case ICMP6_ECHO_REQUEST:
2628 /* route aedvertisement/solliciation is currently unsupported: */
2629 /* it would require rewriting the ICMP data section */
2630 case ICMP6_MEMBERSHIP_QUERY:
2631 case ICMP6_MEMBERSHIP_REPORT:
2632 case ICMP6_MEMBERSHIP_REDUCTION:
2633 case ICMP6_WRUREQUEST:
2634 case ICMP6_WRUREPLY:
2635 case MLD6_MTRACE_RESP:
2636 case MLD6_MTRACE:
2637 return 1;
2638 default:
2639 return 0;
2640 }
2641 }
2642