ip_nat6.c revision 1.1 1 /* $NetBSD: ip_nat6.c,v 1.1 2012/03/23 20:37:01 christos Exp $ */
2
3 /*
4 * Copyright (C) 2011 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef ipf_nat6_KERNEL
11 # define KERNEL 1
12 # define ipf_nat6_KERNEL 1
13 #endif
14 #include <sys/errno.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/time.h>
18 #include <sys/file.h>
19 #if defined(_KERNEL) && defined(__NetBSD_Version__) && \
20 (__NetBSD_Version__ >= 399002000)
21 # include <sys/kauth.h>
22 #endif
23 #if !defined(_KERNEL)
24 # include <stdio.h>
25 # include <string.h>
26 # include <stdlib.h>
27 # define ipf_nat6_KERNEL
28 # ifdef ipf_nat6__OpenBSD__
29 struct file;
30 # endif
31 # include <sys/uio.h>
32 # undef ipf_nat6_KERNEL
33 #endif
34 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
35 # include <sys/filio.h>
36 # include <sys/fcntl.h>
37 #else
38 # include <sys/ioctl.h>
39 #endif
40 #if !defined(AIX)
41 # include <sys/fcntl.h>
42 #endif
43 #if !defined(linux)
44 # include <sys/protosw.h>
45 #endif
46 #include <sys/socket.h>
47 #if defined(_KERNEL)
48 # include <sys/systm.h>
49 # if !defined(__SVR4) && !defined(__svr4__)
50 # include <sys/mbuf.h>
51 # endif
52 #endif
53 #if defined(__SVR4) || defined(__svr4__)
54 # include <sys/filio.h>
55 # include <sys/byteorder.h>
56 # ifdef ipf_nat6_KERNEL
57 # include <sys/dditypes.h>
58 # endif
59 # include <sys/stream.h>
60 # include <sys/kmem.h>
61 #endif
62 #if ipf_nat6__FreeBSD_version >= 300000
63 # include <sys/queue.h>
64 #endif
65 #include <net/if.h>
66 #if ipf_nat6__FreeBSD_version >= 300000
67 # include <net/if_var.h>
68 #endif
69 #ifdef sun
70 # include <net/af.h>
71 #endif
72 #include <net/route.h>
73 #include <netinet/in.h>
74 #include <netinet/in_systm.h>
75 #include <netinet/ip.h>
76
77 #ifdef RFC1825
78 # include <vpn/md5.h>
79 # include <vpn/ipsec.h>
80 extern struct ifnet vpnif;
81 #endif
82
83 #if !defined(linux)
84 # include <netinet/ip_var.h>
85 #endif
86 #include <netinet/tcp.h>
87 #include <netinet/udp.h>
88 #include <netinet/ip_icmp.h>
89 #include "netinet/ip_compat.h"
90 #include <netinet/tcpip.h>
91 #include "netinet/ip_fil.h"
92 #include "netinet/ip_nat.h"
93 #include "netinet/ip_frag.h"
94 #include "netinet/ip_state.h"
95 #include "netinet/ip_proxy.h"
96 #include "netinet/ip_lookup.h"
97 #include "netinet/ip_dstlist.h"
98 #include "netinet/ip_sync.h"
99 #if (__FreeBSD_version >= 300000)
100 # include <sys/malloc.h>
101 #endif
102 #ifdef HAS_SYS_MD5_H
103 # include <sys/md5.h>
104 #else
105 # include "md5.h"
106 #endif
107 /* END OF INCLUDES */
108
109 #undef SOCKADDR_IN
110 #define SOCKADDR_IN struct sockaddr_in
111
112 #if !defined(lint)
113 static const char rcsid[] = "@(#)Id: ip_nat6.c,v 1.22.2.11 2012/01/29 05:30:35 darren_r Exp ";
114 #endif
115
116 #ifdef USE_INET6
117 static struct hostmap *ipf_nat6_hostmap __P((ipf_nat_softc_t *, ipnat_t *,
118 i6addr_t *, i6addr_t *,
119 i6addr_t *, u_32_t));
120 static int ipf_nat6_match __P((fr_info_t *, ipnat_t *));
121 static void ipf_nat6_tabmove __P((ipf_nat_softc_t *, nat_t *));
122 static int ipf_nat6_decap __P((fr_info_t *, nat_t *));
123 static int ipf_nat6_nextaddr __P((fr_info_t *, nat_addr_t *, i6addr_t *,
124 i6addr_t *));
125 static int ipf_nat6_encapok __P((fr_info_t *, nat_t *));
126 static int ipf_nat6_matchencap __P((fr_info_t *, ipnat_t *));
127 static nat_t *ipf_nat6_rebuildencapicmp __P((fr_info_t *, nat_t *));
128 static int ipf_nat6_icmpquerytype __P((int));
129 static int ipf_nat6_out __P((fr_info_t *, nat_t *, int, u_32_t));
130 static int ipf_nat6_in __P((fr_info_t *, nat_t *, int, u_32_t));
131 static int ipf_nat6_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *));
132 static int ipf_nat6_nextaddrinit __P((ipf_main_softc_t *, char *,
133 nat_addr_t *, int, void *));
134 static int ipf_nat6_insert __P((ipf_main_softc_t *, ipf_nat_softc_t *,
135 nat_t *));
136 static void ipf_nat6_add_active __P((i6addr_t *, i6addr_t *));
137 static void ipf_nat6_add_map_mask __P((ipf_nat_softc_t *, i6addr_t *));
138 static void ipf_nat6_add_rdr_mask __P((ipf_nat_softc_t *, i6addr_t *));
139 static void ipf_nat6_delmap __P((ipf_nat_softc_t *, ipnat_t *));
140 static void ipf_nat6_delrdr __P((ipf_nat_softc_t *, ipnat_t *));
141 static void ipf_nat6_del_active __P((i6addr_t *, i6addr_t *));
142 static void ipf_nat6_del_map_mask __P((ipf_nat_softc_t *, i6addr_t *));
143 static void ipf_nat6_del_rdr_mask __P((ipf_nat_softc_t *, i6addr_t *));
144
145
146 #define NINCLSIDE6(y,x) ATOMIC_INCL(softn->ipf_nat_stats.ns_side6[y].x)
147 #define NBUMPSIDE6(y,x) softn->ipf_nat_stats.ns_side6[y].x++
148 #define NBUMPSIDE6D(y,x) \
149 do { \
150 softn->ipf_nat_stats.ns_side6[y].x++; \
151 DT(x); \
152 } while (0)
153 #define NBUMPSIDE6DX(y,x,z) \
154 do { \
155 softn->ipf_nat_stats.ns_side6[y].x++; \
156 DT(z); \
157 } while (0)
158
159
160 /* ------------------------------------------------------------------------ */
161 /* Function: ipf_nat6_ruleaddrinit */
162 /* Returns: int - 0 == success, else failure */
163 /* Parameters: in(I) - NAT rule that requires address fields to be init'd */
164 /* */
165 /* For each of the source/destination address fields in a NAT rule, call */
166 /* ipf_nat6_nextaddrinit() to prepare the structure for active duty. Other */
167 /* IPv6 specific actions can also be taken care of here. */
168 /* ------------------------------------------------------------------------ */
169 int
170 ipf_nat6_ruleaddrinit(softc, softn, n)
171 ipf_main_softc_t *softc;
172 ipf_nat_softc_t *softn;
173 ipnat_t *n;
174 {
175 int idx, error;
176
177 if (n->in_redir == NAT_BIMAP) {
178 n->in_ndstip6 = n->in_osrcip6;
179 n->in_ndstmsk6 = n->in_osrcmsk6;
180 n->in_odstip6 = n->in_nsrcip6;
181 n->in_odstmsk6 = n->in_nsrcmsk6;
182
183 }
184
185 if (n->in_redir & NAT_REDIRECT)
186 idx = 1;
187 else
188 idx = 0;
189 /*
190 * Initialise all of the address fields.
191 */
192 error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
193 n->in_ifps[idx]);
194 if (error != 0)
195 return error;
196
197 error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
198 n->in_ifps[idx]);
199 if (error != 0)
200 return error;
201
202 error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
203 n->in_ifps[idx]);
204 if (error != 0)
205 return error;
206
207 error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
208 n->in_ifps[idx]);
209 if (error != 0)
210 return error;
211
212 if (n->in_redir & (NAT_ENCAP|NAT_DIVERTUDP))
213 ipf_nat6_builddivertmp(softn, n);
214 return 0;
215 }
216
217
218 /* ------------------------------------------------------------------------ */
219 /* Function: ipf_nat6_add_active */
220 /* Returns: Nil */
221 /* Parameters: mask(I) - mask to add to the active array */
222 /* active(O) - pointer to array of active masks */
223 /* */
224 /* Insert the bitmask at "mask" into the array pointed to by "active". */
225 /* The array is kept sorted in order from most specific mask at [0] to */
226 /* the least specific mask. When full, [0] will have a mask with all 128 */
227 /* bits set and [128] will have a mask with all 0s. */
228 /* ------------------------------------------------------------------------ */
229 static void
230 ipf_nat6_add_active(mask, active)
231 i6addr_t *mask, *active;
232 {
233 int i;
234
235 for (i = 0; i < 33; i++) {
236 if (IP6_LT(&active[i], mask)) {
237 int j;
238
239 for (j = i + 1; j < 33; j++)
240 active[j] = active[j - 1];
241 active[i] = *mask;
242 break;
243 }
244 }
245 }
246
247
248 /* ------------------------------------------------------------------------ */
249 /* Function: ipf_nat6_del_active */
250 /* Returns: Nil */
251 /* Parameters: mask(I) - mask to remove from the active array */
252 /* active(O) - pointer to array of active masks */
253 /* */
254 /* Remove the bitmask at "mask" from the array pointed to by "active". */
255 /* This should be called as part of th cleanup of the last rule that is */
256 /* using the mask at "mask" for its matching. */
257 /* ------------------------------------------------------------------------ */
258 static void
259 ipf_nat6_del_active(mask, active)
260 i6addr_t *mask, *active;
261 {
262 int i;
263
264 for (i = 0; i < 33; i++) {
265 if (IP6_EQ(&active[i], mask)) {
266 int j;
267
268 for (j = i + 1; j < 33; j++)
269 active[j - 1] = active[j];
270 break;
271 }
272 }
273 }
274
275
276 /* ------------------------------------------------------------------------ */
277 /* Function: ipf_nat6_add_map_mask */
278 /* Returns: Nil */
279 /* Parameters: softn(I) - pointer to nat context information */
280 /* mask(I) - pointer to mask to add */
281 /* */
282 /* Add the mask pointed to by "mask" to the active set of masks used for */
283 /* map rules and update the number of active masks to reflect the new mask */
284 /* being present. */
285 /* ------------------------------------------------------------------------ */
286 static void
287 ipf_nat6_add_map_mask(softn, mask)
288 ipf_nat_softc_t *softn;
289 i6addr_t *mask;
290 {
291 ipf_nat6_add_active(mask, softn->ipf_nat6_map_active_masks);
292 softn->ipf_nat6_map_max++;
293 }
294
295
296 /* ------------------------------------------------------------------------ */
297 /* Function: ipf_nat6_add_rdr_mask */
298 /* Returns: Nil */
299 /* Parameters: softn(I) - pointer to nat context information */
300 /* mask(I) - mask to add to the active array */
301 /* */
302 /* Add the mask pointed to by "mask" to the active set of masks used for */
303 /* rdr rules and update the number of active masks to reflect the new mask */
304 /* being present. */
305 /* ------------------------------------------------------------------------ */
306 static void
307 ipf_nat6_add_rdr_mask(softn, mask)
308 ipf_nat_softc_t *softn;
309 i6addr_t *mask;
310 {
311 ipf_nat6_add_active(mask, softn->ipf_nat6_rdr_active_masks);
312 softn->ipf_nat6_rdr_max++;
313 }
314
315
316 /* ------------------------------------------------------------------------ */
317 /* Function: ipf_nat6_del_map_mask */
318 /* Returns: Nil */
319 /* Parameters: softn(I) - pointer to nat context information */
320 /* mask(I) - mask to add to the active array */
321 /* */
322 /* Remove the mask at "mask" from the list of active masks in use with map */
323 /* rules and reduce the number of active masks accordingly. There should be */
324 /* no more map rules present using the mask matching "mask" after the */
325 /* current rule is deleted. */
326 /* ------------------------------------------------------------------------ */
327 static void
328 ipf_nat6_del_map_mask(softn, mask)
329 ipf_nat_softc_t *softn;
330 i6addr_t *mask;
331 {
332 ipf_nat6_del_active(mask, softn->ipf_nat6_map_active_masks);
333 softn->ipf_nat6_map_max--;
334 }
335
336
337 /* ------------------------------------------------------------------------ */
338 /* Function: ipf_nat6_del_rdr_mask */
339 /* Returns: Nil */
340 /* Parameters: softn(I) - pointer to nat context information */
341 /* mask(I) - mask to add to the active array */
342 /* */
343 /* Remove the mask at "mask" from the list of active masks in use with rdr */
344 /* rules and reduce the number of active masks accordingly. There should be */
345 /* no more rdr rules present using the mask matching "mask" after the */
346 /* current rule is deleted. */
347 /* ------------------------------------------------------------------------ */
348 static void
349 ipf_nat6_del_rdr_mask(softn, mask)
350 ipf_nat_softc_t *softn;
351 i6addr_t *mask;
352 {
353 ipf_nat6_del_active(mask, softn->ipf_nat6_rdr_active_masks);
354 softn->ipf_nat6_rdr_max--;
355 }
356
357
358 /* ------------------------------------------------------------------------ */
359 /* Function: ipf_nat6_addrdr */
360 /* Returns: Nil */
361 /* Parameters: n(I) - pointer to NAT rule to add */
362 /* */
363 /* Adds a redirect rule to the hash table of redirect rules and the list of */
364 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */
365 /* use by redirect rules. */
366 /* ------------------------------------------------------------------------ */
367 void
368 ipf_nat6_addrdr(softn, n)
369 ipf_nat_softc_t *softn;
370 ipnat_t *n;
371 {
372 ipnat_t **np;
373 i6addr_t j;
374 u_int hv;
375 int k;
376
377 if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) {
378 k = count6bits(n->in_nsrcmsk6.i6);
379 softn->ipf_nat6_rdr_masks[k]++;
380 if (softn->ipf_nat6_rdr_masks[k] == 1)
381 ipf_nat6_add_rdr_mask(softn, &n->in_nsrcmsk6);
382
383 IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
384 hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
385
386 } else if (n->in_odstatype == FRI_NORMAL) {
387 k = count6bits(n->in_odstmsk6.i6);
388 softn->ipf_nat6_rdr_masks[k]++;
389 if (softn->ipf_nat6_rdr_masks[k] == 1)
390 ipf_nat6_add_rdr_mask(softn, &n->in_odstmsk6);
391
392 IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
393 hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
394 } else {
395 softn->ipf_nat6_rdr_masks[0]++;
396 if (softn->ipf_nat6_rdr_masks[0] == 1)
397 ipf_nat6_add_rdr_mask(softn, &n->in_odstmsk6);
398 hv = 0;
399 }
400 np = softn->ipf_nat_rdr_rules + hv;
401 while (*np != NULL)
402 np = &(*np)->in_rnext;
403 n->in_rnext = NULL;
404 n->in_prnext = np;
405 n->in_hv[0] = hv;
406 *np = n;
407 }
408
409
410 /* ------------------------------------------------------------------------ */
411 /* Function: ipf_nat6_addmap */
412 /* Returns: Nil */
413 /* Parameters: n(I) - pointer to NAT rule to add */
414 /* */
415 /* Adds a NAT map rule to the hash table of rules and the list of loaded */
416 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */
417 /* redirect rules. */
418 /* ------------------------------------------------------------------------ */
419 void
420 ipf_nat6_addmap(softn, n)
421 ipf_nat_softc_t *softn;
422 ipnat_t *n;
423 {
424 ipnat_t **np;
425 i6addr_t j;
426 u_int hv;
427 int k;
428
429 if (n->in_osrcatype == FRI_NORMAL) {
430 k = count6bits(n->in_osrcmsk6.i6);
431 softn->ipf_nat6_map_masks[k]++;
432 if (softn->ipf_nat6_map_masks[k] == 1)
433 ipf_nat6_add_map_mask(softn, &n->in_osrcmsk6);
434 IP6_AND(&n->in_osrcip6, &n->in_osrcmsk6, &j);
435 hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_maprules_sz);
436 } else {
437 softn->ipf_nat6_map_masks[0]++;
438 if (softn->ipf_nat6_map_masks[0] == 1)
439 ipf_nat6_add_map_mask(softn, &n->in_osrcmsk6);
440 hv = 0;
441 }
442 np = softn->ipf_nat_map_rules + hv;
443 while (*np != NULL)
444 np = &(*np)->in_mnext;
445 n->in_mnext = NULL;
446 n->in_pmnext = np;
447 n->in_hv[1] = hv;
448 *np = n;
449 }
450
451
452 /* ------------------------------------------------------------------------ */
453 /* Function: ipf_nat6_del_rdr */
454 /* Returns: Nil */
455 /* Parameters: n(I) - pointer to NAT rule to delete */
456 /* */
457 /* Removes a NAT rdr rule from the hash table of NAT rdr rules. */
458 /* ------------------------------------------------------------------------ */
459 static void
460 ipf_nat6_delrdr(softn, n)
461 ipf_nat_softc_t *softn;
462 ipnat_t *n;
463 {
464 int k;
465
466 if (n->in_osrcatype == FRI_NORMAL) {
467 k = count6bits(n->in_osrcmsk6.i6);
468 } else {
469 k = 0;
470 }
471 softn->ipf_nat6_rdr_masks[k]--;
472 if (softn->ipf_nat6_rdr_masks[k] == 0)
473 ipf_nat6_del_rdr_mask(softn, &n->in_osrcmsk6);
474
475 if (n->in_mnext != NULL)
476 n->in_mnext->in_pmnext = n->in_pmnext;
477 *n->in_pmnext = n->in_mnext;
478 }
479
480
481 /* ------------------------------------------------------------------------ */
482 /* Function: ipf_nat6_delmap */
483 /* Returns: Nil */
484 /* Parameters: n(I) - pointer to NAT rule to delete */
485 /* */
486 /* Removes a NAT map rule from the hash table of NAT map rules. */
487 /* ------------------------------------------------------------------------ */
488 static void
489 ipf_nat6_delmap(softn, n)
490 ipf_nat_softc_t *softn;
491 ipnat_t *n;
492 {
493 int k;
494
495 if (n->in_osrcatype == FRI_NORMAL) {
496 k = count6bits(n->in_odstmsk6.i6);
497 } else {
498 k = 0;
499 }
500 softn->ipf_nat6_map_masks[k]--;
501 if (softn->ipf_nat6_map_masks[k] == 0)
502 ipf_nat6_del_map_mask(softn, &n->in_odstmsk6);
503
504 if (n->in_mnext != NULL)
505 n->in_mnext->in_pmnext = n->in_pmnext;
506 *n->in_pmnext = n->in_mnext;
507 }
508
509
510 /* ------------------------------------------------------------------------ */
511 /* Function: ipf_nat6_addencap */
512 /* Returns: Nil */
513 /* Parameters: n(I) - pointer to NAT rule to add */
514 /* */
515 /* Here we add in a pointer in the NAT rules hash table to match reply */
516 /* packets that are encapsulated. For encap rules that are "out", what we */
517 /* will want to match upon will be the source address in the encap rule as */
518 /* this is what will become the destination in packets coming back to us. */
519 /* For encaps pointing in, it is still the same because it is still the */
520 /* reply packet we want to match. */
521 /* ------------------------------------------------------------------------ */
522 void
523 ipf_nat6_addencap(softn, n)
524 ipf_nat_softc_t *softn;
525 ipnat_t *n;
526 {
527 ipnat_t **np;
528 u_32_t j;
529 u_int hv;
530 int k;
531
532 k = -1;
533
534 /*
535 * It is the new source address we're after...
536 */
537 if (n->in_nsrcatype == FRI_NORMAL) {
538 k = count6bits(n->in_nsrcip6.i6);
539 IP6_AND(&n->in_nsrcip6, &n->in_nsrcip6, &j);
540 hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_maprules_sz);
541 } else {
542 k = 0;
543 j = 0;
544 hv = 0;
545 }
546
547 /*
548 * And place the rules table entry in the reverse spot, so for out
549 * we use the rdr-links and for rdr, we use the map-links/
550 */
551 if (n->in_redir & NAT_MAP) {
552 softn->ipf_nat6_rdr_masks[k]++;
553 if (softn->ipf_nat6_rdr_masks[k] == 1)
554 ipf_nat6_add_rdr_mask(softn, &n->in_nsrcip6);
555
556 np = softn->ipf_nat_rdr_rules + hv;
557 while (*np != NULL)
558 np = &(*np)->in_rnext;
559 n->in_rnext = NULL;
560 n->in_prnext = np;
561 n->in_hv[0] = hv;
562 *np = n;
563 } else if (n->in_redir & NAT_REDIRECT) {
564 softn->ipf_nat6_map_masks[k]++;
565 if (softn->ipf_nat6_map_masks[k] == 1)
566 ipf_nat6_add_map_mask(softn, &n->in_nsrcip6);
567 np = softn->ipf_nat_map_rules + hv;
568 while (*np != NULL)
569 np = &(*np)->in_mnext;
570 n->in_mnext = NULL;
571 n->in_pmnext = np;
572 n->in_hv[1] = hv;
573 *np = n;
574 }
575
576 /* TRACE(n, hv, k) */
577 }
578
579
580 /* ------------------------------------------------------------------------ */
581 /* Function: ipf_nat6_hostmap */
582 /* Returns: struct hostmap* - NULL if no hostmap could be created, */
583 /* else a pointer to the hostmapping to use */
584 /* Parameters: np(I) - pointer to NAT rule */
585 /* real(I) - real IP address */
586 /* map(I) - mapped IP address */
587 /* port(I) - destination port number */
588 /* Write Locks: ipf_nat */
589 /* */
590 /* Check if an ip address has already been allocated for a given mapping */
591 /* that is not doing port based translation. If is not yet allocated, then */
592 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */
593 /* ------------------------------------------------------------------------ */
594 static struct hostmap *
595 ipf_nat6_hostmap(softn, np, src, dst, map, port)
596 ipf_nat_softc_t *softn;
597 ipnat_t *np;
598 i6addr_t *src, *dst, *map;
599 u_32_t port;
600 {
601 hostmap_t *hm;
602 u_int hv;
603
604 hv = (src->i6[3] ^ dst->i6[3]);
605 hv += (src->i6[2] ^ dst->i6[2]);
606 hv += (src->i6[1] ^ dst->i6[1]);
607 hv += (src->i6[0] ^ dst->i6[0]);
608 hv += src->i6[3];
609 hv += src->i6[2];
610 hv += src->i6[1];
611 hv += src->i6[0];
612 hv += dst->i6[3];
613 hv += dst->i6[2];
614 hv += dst->i6[1];
615 hv += dst->i6[0];
616 hv %= HOSTMAP_SIZE;
617 for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_next)
618 if (IP6_EQ(&hm->hm_osrc6, src) &&
619 IP6_EQ(&hm->hm_odst6, dst) &&
620 ((np == NULL) || (np == hm->hm_ipnat)) &&
621 ((port == 0) || (port == hm->hm_port))) {
622 softn->ipf_nat_stats.ns_hm_addref++;
623 hm->hm_ref++;
624 return hm;
625 }
626
627 if (np == NULL) {
628 softn->ipf_nat_stats.ns_hm_nullnp++;
629 return NULL;
630 }
631
632 KMALLOC(hm, hostmap_t *);
633 if (hm) {
634 hm->hm_next = softn->ipf_hm_maplist;
635 hm->hm_pnext = &softn->ipf_hm_maplist;
636 if (softn->ipf_hm_maplist != NULL)
637 softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
638 softn->ipf_hm_maplist = hm;
639 hm->hm_hnext = softn->ipf_hm_maptable[hv];
640 hm->hm_phnext = softn->ipf_hm_maptable + hv;
641 if (softn->ipf_hm_maptable[hv] != NULL)
642 softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
643 softn->ipf_hm_maptable[hv] = hm;
644 hm->hm_ipnat = np;
645 hm->hm_osrcip6 = *src;
646 hm->hm_odstip6 = *dst;
647 hm->hm_nsrcip6 = *map;
648 hm->hm_ndstip6.i6[0] = 0;
649 hm->hm_ndstip6.i6[1] = 0;
650 hm->hm_ndstip6.i6[2] = 0;
651 hm->hm_ndstip6.i6[3] = 0;
652 hm->hm_ref = 1;
653 hm->hm_port = port;
654 hm->hm_hv = hv;
655 hm->hm_v = 6;
656 softn->ipf_nat_stats.ns_hm_new++;
657 } else {
658 softn->ipf_nat_stats.ns_hm_newfail++;
659 }
660 return hm;
661 }
662
663
664 /* ------------------------------------------------------------------------ */
665 /* Function: ipf_nat6_newmap */
666 /* Returns: int - -1 == error, 0 == success */
667 /* Parameters: fin(I) - pointer to packet information */
668 /* nat(I) - pointer to NAT entry */
669 /* ni(I) - pointer to structure with misc. information needed */
670 /* to create new NAT entry. */
671 /* */
672 /* Given an empty NAT structure, populate it with new information about a */
673 /* new NAT session, as defined by the matching NAT rule. */
674 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
675 /* to the new IP address for the translation. */
676 /* ------------------------------------------------------------------------ */
677 int
678 ipf_nat6_newmap(fin, nat, ni)
679 fr_info_t *fin;
680 nat_t *nat;
681 natinfo_t *ni;
682 {
683 ipf_main_softc_t *softc = fin->fin_main_soft;
684 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
685 u_short st_port, dport, sport, port, sp, dp;
686 i6addr_t in, st_ip;
687 hostmap_t *hm;
688 u_32_t flags;
689 ipnat_t *np;
690 nat_t *natl;
691 int l;
692
693 /*
694 * If it's an outbound packet which doesn't match any existing
695 * record, then create a new port
696 */
697 l = 0;
698 hm = NULL;
699 np = ni->nai_np;
700 st_ip = np->in_snip6;
701 st_port = np->in_spnext;
702 flags = nat->nat_flags;
703
704 if (flags & IPN_ICMPQUERY) {
705 sport = fin->fin_data[1];
706 dport = 0;
707 } else {
708 sport = htons(fin->fin_data[0]);
709 dport = htons(fin->fin_data[1]);
710 }
711
712 /*
713 * Do a loop until we either run out of entries to try or we find
714 * a NAT mapping that isn't currently being used. This is done
715 * because the change to the source is not (usually) being fixed.
716 */
717 do {
718 port = 0;
719 in = np->in_nsrc.na_nextaddr;
720 if (l == 0) {
721 /*
722 * Check to see if there is an existing NAT
723 * setup for this IP address pair.
724 */
725 hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
726 &fin->fin_dst6, &in, 0);
727 if (hm != NULL)
728 in = hm->hm_nsrcip6;
729 } else if ((l == 1) && (hm != NULL)) {
730 ipf_nat_hostmapdel(&hm);
731 }
732
733 nat->nat_hm = hm;
734
735 if (IP6_ISONES(&np->in_nsrcmsk6) && (np->in_spnext == 0)) {
736 if (l > 0) {
737 NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_1);
738 return -1;
739 }
740 }
741
742 if ((np->in_redir == NAT_BIMAP) &&
743 IP6_EQ(&np->in_osrcmsk6, &np->in_nsrcmsk6)) {
744 i6addr_t temp;
745 /*
746 * map the address block in a 1:1 fashion
747 */
748 temp.i6[0] = fin->fin_src6.i6[0] &
749 ~np->in_osrcmsk6.i6[0];
750 temp.i6[1] = fin->fin_src6.i6[1] &
751 ~np->in_osrcmsk6.i6[1];
752 temp.i6[2] = fin->fin_src6.i6[2] &
753 ~np->in_osrcmsk6.i6[0];
754 temp.i6[3] = fin->fin_src6.i6[3] &
755 ~np->in_osrcmsk6.i6[3];
756 in = np->in_nsrcip6;
757 IP6_MERGE(&in, &temp, &np->in_osrc);
758
759 #ifdef NEED_128BIT_MATH
760 } else if (np->in_redir & NAT_MAPBLK) {
761 if ((l >= np->in_ppip) || ((l > 0) &&
762 !(flags & IPN_TCPUDP))) {
763 NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_2);
764 return -1;
765 }
766 /*
767 * map-block - Calculate destination address.
768 */
769 IP6_MASK(&in, &fin->fin_src6, &np->in_osrcmsk6);
770 in = ntohl(in);
771 inb = in;
772 in.s_addr /= np->in_ippip;
773 in.s_addr &= ntohl(~np->in_nsrcmsk6);
774 in.s_addr += ntohl(np->in_nsrcaddr6);
775 /*
776 * Calculate destination port.
777 */
778 if ((flags & IPN_TCPUDP) &&
779 (np->in_ppip != 0)) {
780 port = ntohs(sport) + l;
781 port %= np->in_ppip;
782 port += np->in_ppip *
783 (inb.s_addr % np->in_ippip);
784 port += MAPBLK_MINPORT;
785 port = htons(port);
786 }
787 #endif
788
789 } else if (IP6_ISZERO(&np->in_nsrcaddr) &&
790 IP6_ISONES(&np->in_nsrcmsk)) {
791 /*
792 * 0/32 - use the interface's IP address.
793 */
794 if ((l > 0) ||
795 ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
796 &in, NULL) == -1) {
797 NBUMPSIDE6DX(1, ns_new_ifpaddr,
798 ns_new_ifpaddr_1);
799 return -1;
800 }
801
802 } else if (IP6_ISZERO(&np->in_nsrcip6) &&
803 IP6_ISZERO(&np->in_nsrcmsk6)) {
804 /*
805 * 0/0 - use the original source address/port.
806 */
807 if (l > 0) {
808 NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_3);
809 return -1;
810 }
811 in = fin->fin_src6;
812
813 } else if (!IP6_ISONES(&np->in_nsrcmsk6) &&
814 (np->in_spnext == 0) && ((l > 0) || (hm == NULL))) {
815 IP6_INC(&np->in_snip6);
816 }
817
818 natl = NULL;
819
820 if ((flags & IPN_TCPUDP) &&
821 ((np->in_redir & NAT_MAPBLK) == 0) &&
822 (np->in_flags & IPN_AUTOPORTMAP)) {
823 #ifdef NEED_128BIT_MATH
824 /*
825 * "ports auto" (without map-block)
826 */
827 if ((l > 0) && (l % np->in_ppip == 0)) {
828 if ((l > np->in_ppip) &&
829 !IP6_ISONES(&np->in_nsrcmsk)) {
830 IP6_INC(&np->in_snip6)
831 }
832 }
833 if (np->in_ppip != 0) {
834 port = ntohs(sport);
835 port += (l % np->in_ppip);
836 port %= np->in_ppip;
837 port += np->in_ppip *
838 (ntohl(fin->fin_src6) %
839 np->in_ippip);
840 port += MAPBLK_MINPORT;
841 port = htons(port);
842 }
843 #endif
844
845 } else if (((np->in_redir & NAT_MAPBLK) == 0) &&
846 (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
847 /*
848 * Standard port translation. Select next port.
849 */
850 if (np->in_flags & IPN_SEQUENTIAL) {
851 port = np->in_spnext;
852 } else {
853 port = ipf_random() % (np->in_spmax -
854 np->in_spmin + 1);
855 port += np->in_spmin;
856 }
857 port = htons(port);
858 np->in_spnext++;
859
860 if (np->in_spnext > np->in_spmax) {
861 np->in_spnext = np->in_spmin;
862 if (!IP6_ISONES(&np->in_nsrcmsk6)) {
863 IP6_INC(&np->in_snip6);
864 }
865 }
866 }
867
868 if (np->in_flags & IPN_SIPRANGE) {
869 if (IP6_GT(&np->in_snip, &np->in_nsrcmsk))
870 np->in_snip6 = np->in_nsrcip6;
871 } else {
872 i6addr_t a1, a2;
873
874 a1 = np->in_snip6;
875 IP6_INC(&a1);
876 IP6_AND(&a1, &np->in_nsrcmsk6, &a2);
877
878 if (!IP6_ISONES(&np->in_nsrcmsk6) &&
879 IP6_GT(&a2, &np->in_nsrcip6)) {
880 IP6_ADD(&np->in_nsrcip6, 1, &np->in_snip6);
881 }
882 }
883
884 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
885 port = sport;
886
887 /*
888 * Here we do a lookup of the connection as seen from
889 * the outside. If an IP# pair already exists, try
890 * again. So if you have A->B becomes C->B, you can
891 * also have D->E become C->E but not D->B causing
892 * another C->B. Also take protocol and ports into
893 * account when determining whether a pre-existing
894 * NAT setup will cause an external conflict where
895 * this is appropriate.
896 */
897 sp = fin->fin_data[0];
898 dp = fin->fin_data[1];
899 fin->fin_data[0] = fin->fin_data[1];
900 fin->fin_data[1] = ntohs(port);
901 natl = ipf_nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
902 (u_int)fin->fin_p, &fin->fin_dst6.in6,
903 &in.in6);
904 fin->fin_data[0] = sp;
905 fin->fin_data[1] = dp;
906
907 /*
908 * Has the search wrapped around and come back to the
909 * start ?
910 */
911 if ((natl != NULL) &&
912 (np->in_spnext != 0) && (st_port == np->in_spnext) &&
913 (!IP6_ISZERO(&np->in_snip6) &&
914 IP6_EQ(&st_ip, &np->in_snip6))) {
915 NBUMPSIDE6D(1, ns_wrap);
916 return -1;
917 }
918 l++;
919 } while (natl != NULL);
920
921 /* Setup the NAT table */
922 nat->nat_osrc6 = fin->fin_src6;
923 nat->nat_nsrc6 = in;
924 nat->nat_odst6 = fin->fin_dst6;
925 nat->nat_ndst6 = fin->fin_dst6;
926 if (nat->nat_hm == NULL)
927 nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
928 &fin->fin_dst6,
929 &nat->nat_nsrc6, 0);
930
931 if (flags & IPN_TCPUDP) {
932 nat->nat_osport = sport;
933 nat->nat_nsport = port; /* sport */
934 nat->nat_odport = dport;
935 nat->nat_ndport = dport;
936 ((tcphdr_t *)fin->fin_dp)->th_sport = port;
937 } else if (flags & IPN_ICMPQUERY) {
938 nat->nat_oicmpid = fin->fin_data[1];
939 ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port;
940 nat->nat_nicmpid = port;
941 }
942 return 0;
943 }
944
945
946 /* ------------------------------------------------------------------------ */
947 /* Function: ipf_nat6_newrdr */
948 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
949 /* allow rule to be moved if IPN_ROUNDR is set. */
950 /* Parameters: fin(I) - pointer to packet information */
951 /* nat(I) - pointer to NAT entry */
952 /* ni(I) - pointer to structure with misc. information needed */
953 /* to create new NAT entry. */
954 /* */
955 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
956 /* to the new IP address for the translation. */
957 /* ------------------------------------------------------------------------ */
958 int
959 ipf_nat6_newrdr(fin, nat, ni)
960 fr_info_t *fin;
961 nat_t *nat;
962 natinfo_t *ni;
963 {
964 ipf_main_softc_t *softc = fin->fin_main_soft;
965 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
966 u_short nport, dport, sport;
967 u_short sp, dp;
968 hostmap_t *hm;
969 u_32_t flags;
970 i6addr_t in;
971 ipnat_t *np;
972 nat_t *natl;
973 int move;
974
975 move = 1;
976 hm = NULL;
977 in.i6[0] = 0;
978 in.i6[1] = 0;
979 in.i6[2] = 0;
980 in.i6[3] = 0;
981 np = ni->nai_np;
982 flags = nat->nat_flags;
983
984 if (flags & IPN_ICMPQUERY) {
985 dport = fin->fin_data[1];
986 sport = 0;
987 } else {
988 sport = htons(fin->fin_data[0]);
989 dport = htons(fin->fin_data[1]);
990 }
991
992 /* TRACE sport, dport */
993
994
995 /*
996 * If the matching rule has IPN_STICKY set, then we want to have the
997 * same rule kick in as before. Why would this happen? If you have
998 * a collection of rdr rules with "round-robin sticky", the current
999 * packet might match a different one to the previous connection but
1000 * we want the same destination to be used.
1001 */
1002 if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
1003 ((np->in_flags & IPN_STICKY) != 0)) {
1004 hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
1005 &fin->fin_dst6, &in, (u_32_t)dport);
1006 if (hm != NULL) {
1007 in = hm->hm_ndstip6;
1008 np = hm->hm_ipnat;
1009 ni->nai_np = np;
1010 move = 0;
1011 }
1012 }
1013
1014 /*
1015 * Otherwise, it's an inbound packet. Most likely, we don't
1016 * want to rewrite source ports and source addresses. Instead,
1017 * we want to rewrite to a fixed internal address and fixed
1018 * internal port.
1019 */
1020 if (np->in_flags & IPN_SPLIT) {
1021 in = np->in_dnip6;
1022
1023 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
1024 hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
1025 &fin->fin_dst6, &in,
1026 (u_32_t)dport);
1027 if (hm != NULL) {
1028 in = hm->hm_ndstip6;
1029 move = 0;
1030 }
1031 }
1032
1033 if (hm == NULL || hm->hm_ref == 1) {
1034 if (IP6_EQ(&np->in_ndstip6, &in)) {
1035 np->in_dnip6 = np->in_ndstmsk6;
1036 move = 0;
1037 } else {
1038 np->in_dnip6 = np->in_ndstip6;
1039 }
1040 }
1041
1042 } else if (IP6_ISZERO(&np->in_ndstaddr) &&
1043 IP6_ISONES(&np->in_ndstmsk)) {
1044 /*
1045 * 0/32 - use the interface's IP address.
1046 */
1047 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
1048 &in, NULL) == -1) {
1049 NBUMPSIDE6DX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
1050 return -1;
1051 }
1052
1053 } else if (IP6_ISZERO(&np->in_ndstip6) &&
1054 IP6_ISZERO(&np->in_ndstmsk6)) {
1055 /*
1056 * 0/0 - use the original destination address/port.
1057 */
1058 in = fin->fin_dst6;
1059
1060 } else if (np->in_redir == NAT_BIMAP &&
1061 IP6_EQ(&np->in_ndstmsk6, &np->in_odstmsk6)) {
1062 i6addr_t temp;
1063 /*
1064 * map the address block in a 1:1 fashion
1065 */
1066 temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_osrcmsk6.i6[0];
1067 temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_osrcmsk6.i6[1];
1068 temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_osrcmsk6.i6[0];
1069 temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_osrcmsk6.i6[3];
1070 in = np->in_ndstip6;
1071 IP6_MERGE(&in, &temp, &np->in_ndstmsk6);
1072 } else {
1073 in = np->in_ndstip6;
1074 }
1075
1076 if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
1077 nport = dport;
1078 else {
1079 /*
1080 * Whilst not optimized for the case where
1081 * pmin == pmax, the gain is not significant.
1082 */
1083 if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
1084 (np->in_odport != np->in_dtop)) {
1085 nport = ntohs(dport) - np->in_odport + np->in_dpmax;
1086 nport = htons(nport);
1087 } else {
1088 nport = htons(np->in_dpnext);
1089 np->in_dpnext++;
1090 if (np->in_dpnext > np->in_dpmax)
1091 np->in_dpnext = np->in_dpmin;
1092 }
1093 }
1094
1095 /*
1096 * When the redirect-to address is set to 0.0.0.0, just
1097 * assume a blank `forwarding' of the packet. We don't
1098 * setup any translation for this either.
1099 */
1100 if (IP6_ISZERO(&in)) {
1101 if (nport == dport) {
1102 NBUMPSIDE6D(0, ns_xlate_null);
1103 return -1;
1104 }
1105 in = fin->fin_dst6;
1106 }
1107
1108 /*
1109 * Check to see if this redirect mapping already exists and if
1110 * it does, return "failure" (allowing it to be created will just
1111 * cause one or both of these "connections" to stop working.)
1112 */
1113 sp = fin->fin_data[0];
1114 dp = fin->fin_data[1];
1115 fin->fin_data[1] = fin->fin_data[0];
1116 fin->fin_data[0] = ntohs(nport);
1117 natl = ipf_nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
1118 (u_int)fin->fin_p, &in.in6,
1119 &fin->fin_src6.in6);
1120 fin->fin_data[0] = sp;
1121 fin->fin_data[1] = dp;
1122 if (natl != NULL) {
1123 NBUMPSIDE6D(0, ns_xlate_exists);
1124 return -1;
1125 }
1126
1127 nat->nat_ndst6 = in;
1128 nat->nat_odst6 = fin->fin_dst6;
1129 nat->nat_nsrc6 = fin->fin_src6;
1130 nat->nat_osrc6 = fin->fin_src6;
1131 if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
1132 nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
1133 &fin->fin_dst6, &in,
1134 (u_32_t)dport);
1135
1136 if (flags & IPN_TCPUDP) {
1137 nat->nat_odport = dport;
1138 nat->nat_ndport = nport;
1139 nat->nat_osport = sport;
1140 nat->nat_nsport = sport;
1141 ((tcphdr_t *)fin->fin_dp)->th_dport = nport;
1142 } else if (flags & IPN_ICMPQUERY) {
1143 nat->nat_oicmpid = fin->fin_data[1];
1144 ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport;
1145 nat->nat_nicmpid = nport;
1146 }
1147
1148 return move;
1149 }
1150
1151 /* ------------------------------------------------------------------------ */
1152 /* Function: ipf_nat6_add */
1153 /* Returns: nat6_t* - NULL == failure to create new NAT structure, */
1154 /* else pointer to new NAT structure */
1155 /* Parameters: fin(I) - pointer to packet information */
1156 /* np(I) - pointer to NAT rule */
1157 /* natsave(I) - pointer to where to store NAT struct pointer */
1158 /* flags(I) - flags describing the current packet */
1159 /* direction(I) - direction of packet (in/out) */
1160 /* Write Lock: ipf_nat */
1161 /* */
1162 /* Attempts to create a new NAT entry. Does not actually change the packet */
1163 /* in any way. */
1164 /* */
1165 /* This fucntion is in three main parts: (1) deal with creating a new NAT */
1166 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */
1167 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
1168 /* and (3) building that structure and putting it into the NAT table(s). */
1169 /* */
1170 /* NOTE: natsave should NOT be used top point back to an ipstate_t struct */
1171 /* as it can result in memory being corrupted. */
1172 /* ------------------------------------------------------------------------ */
1173 nat_t *
1174 ipf_nat6_add(fin, np, natsave, flags, direction)
1175 fr_info_t *fin;
1176 ipnat_t *np;
1177 nat_t **natsave;
1178 u_int flags;
1179 int direction;
1180 {
1181 ipf_main_softc_t *softc = fin->fin_main_soft;
1182 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1183 hostmap_t *hm = NULL;
1184 nat_t *nat, *natl;
1185 u_int nflags;
1186 natinfo_t ni;
1187 int move;
1188 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
1189 qpktinfo_t *qpi = fin->fin_qpi;
1190 #endif
1191
1192 if ((softn->ipf_nat_stats.ns_active * 100 / softn->ipf_nat_table_max) >
1193 softn->ipf_nat_table_wm_high) {
1194 softn->ipf_nat_doflush = 1;
1195 }
1196
1197 if (softn->ipf_nat_stats.ns_active >= softn->ipf_nat_table_max) {
1198 NBUMPSIDE6(fin->fin_out, ns_table_max);
1199 return NULL;
1200 }
1201
1202 move = 1;
1203 nflags = np->in_flags & flags;
1204 nflags &= NAT_FROMRULE;
1205
1206 ni.nai_np = np;
1207 ni.nai_dport = 0;
1208 ni.nai_sport = 0;
1209
1210 /* Give me a new nat */
1211 KMALLOC(nat, nat_t *);
1212 if (nat == NULL) {
1213 NBUMPSIDE6(fin->fin_out, ns_memfail);
1214 /*
1215 * Try to automatically tune the max # of entries in the
1216 * table allowed to be less than what will cause kmem_alloc()
1217 * to fail and try to eliminate panics due to out of memory
1218 * conditions arising.
1219 */
1220 if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
1221 (softn->ipf_nat_stats.ns_active > 100)) {
1222 softn->ipf_nat_table_max =
1223 softn->ipf_nat_stats.ns_active - 100;
1224 printf("table_max reduced to %d\n",
1225 softn->ipf_nat_table_max);
1226 }
1227 return NULL;
1228 }
1229
1230 if (flags & IPN_ICMPQUERY) {
1231 /*
1232 * In the ICMP query NAT code, we translate the ICMP id fields
1233 * to make them unique. This is indepedent of the ICMP type
1234 * (e.g. in the unlikely event that a host sends an echo and
1235 * an tstamp request with the same id, both packets will have
1236 * their ip address/id field changed in the same way).
1237 */
1238 /* The icmp6_id field is used by the sender to identify the
1239 * process making the icmp request. (the receiver justs
1240 * copies it back in its response). So, it closely matches
1241 * the concept of source port. We overlay sport, so we can
1242 * maximally reuse the existing code.
1243 */
1244 ni.nai_sport = fin->fin_data[1];
1245 ni.nai_dport = 0;
1246 }
1247
1248 bzero((char *)nat, sizeof(*nat));
1249 nat->nat_flags = flags;
1250 nat->nat_redir = np->in_redir;
1251 nat->nat_dir = direction;
1252 nat->nat_pr[0] = fin->fin_p;
1253 nat->nat_pr[1] = fin->fin_p;
1254
1255 /*
1256 * Search the current table for a match and create a new mapping
1257 * if there is none found.
1258 */
1259 if (np->in_redir & (NAT_ENCAP|NAT_DIVERTUDP)) {
1260 move = ipf_nat6_newdivert(fin, nat, &ni);
1261
1262 } else if (np->in_redir & NAT_REWRITE) {
1263 move = ipf_nat6_newrewrite(fin, nat, &ni);
1264
1265 } else if (direction == NAT_OUTBOUND) {
1266 /*
1267 * We can now arrange to call this for the same connection
1268 * because ipf_nat6_new doesn't protect the code path into
1269 * this function.
1270 */
1271 natl = ipf_nat6_outlookup(fin, nflags, (u_int)fin->fin_p,
1272 &fin->fin_src6.in6,
1273 &fin->fin_dst6.in6);
1274 if (natl != NULL) {
1275 KFREE(nat);
1276 nat = natl;
1277 goto done;
1278 }
1279
1280 move = ipf_nat6_newmap(fin, nat, &ni);
1281 } else {
1282 /*
1283 * NAT_INBOUND is used for redirects rules
1284 */
1285 natl = ipf_nat6_inlookup(fin, nflags, (u_int)fin->fin_p,
1286 &fin->fin_src6.in6,
1287 &fin->fin_dst6.in6);
1288 if (natl != NULL) {
1289 KFREE(nat);
1290 nat = natl;
1291 goto done;
1292 }
1293
1294 move = ipf_nat6_newrdr(fin, nat, &ni);
1295 }
1296 if (move == -1)
1297 goto badnat;
1298
1299 np = ni.nai_np;
1300
1301 nat->nat_mssclamp = np->in_mssclamp;
1302 nat->nat_me = natsave;
1303 nat->nat_fr = fin->fin_fr;
1304 nat->nat_rev = fin->fin_rev;
1305 nat->nat_ptr = np;
1306
1307 #ifdef IPF_V6_PROXIES
1308 if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0))
1309 if (appr_new(fin, nat) == -1)
1310 goto badnat;
1311 #endif
1312
1313 nat->nat_ifps[0] = np->in_ifps[0];
1314 if (np->in_ifps[0] != NULL) {
1315 COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
1316 }
1317
1318 nat->nat_ifps[1] = np->in_ifps[1];
1319 if (np->in_ifps[1] != NULL) {
1320 COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
1321 }
1322
1323 if (ipf_nat6_finalise(fin, nat) == -1) {
1324 goto badnat;
1325 }
1326
1327 np->in_use++;
1328
1329 if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
1330 if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
1331 ipf_nat6_delrdr(softn, np);
1332 ipf_nat6_addrdr(softn, np);
1333 } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
1334 ipf_nat6_delmap(softn, np);
1335 ipf_nat6_addmap(softn, np);
1336 }
1337 }
1338
1339 if (flags & SI_WILDP)
1340 softn->ipf_nat_stats.ns_wilds++;
1341 softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]++;
1342
1343 goto done;
1344 badnat:
1345 NBUMPSIDE6(fin->fin_out, ns_badnatnew);
1346 if ((hm = nat->nat_hm) != NULL)
1347 ipf_nat_hostmapdel(&hm);
1348 KFREE(nat);
1349 nat = NULL;
1350 done:
1351 return nat;
1352 }
1353
1354
1355 /* ------------------------------------------------------------------------ */
1356 /* Function: ipf_nat6_finalise */
1357 /* Returns: int - 0 == sucess, -1 == failure */
1358 /* Parameters: fin(I) - pointer to packet information */
1359 /* nat(I) - pointer to NAT entry */
1360 /* Write Lock: ipf_nat */
1361 /* */
1362 /* This is the tail end of constructing a new NAT entry and is the same */
1363 /* for both IPv4 and IPv6. */
1364 /* ------------------------------------------------------------------------ */
1365 /*ARGSUSED*/
1366 int
1367 ipf_nat6_finalise(fin, nat)
1368 fr_info_t *fin;
1369 nat_t *nat;
1370 {
1371 ipf_main_softc_t *softc = fin->fin_main_soft;
1372 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1373 u_32_t sum1, sum2, sumd;
1374 frentry_t *fr;
1375 u_32_t flags;
1376
1377 flags = nat->nat_flags;
1378
1379 switch (fin->fin_p)
1380 {
1381 case IPPROTO_ICMPV6 :
1382 sum1 = LONG_SUM(ntohs(nat->nat_osport));
1383 sum2 = LONG_SUM(ntohs(nat->nat_nsport));
1384 CALC_SUMD(sum1, sum2, sumd);
1385 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1386
1387 break;
1388
1389 default :
1390 sum1 = LONG_SUM6(&nat->nat_osrc6);
1391 sum1 += ntohs(nat->nat_osport);
1392 sum2 = LONG_SUM6(&nat->nat_nsrc6);
1393 sum2 += ntohs(nat->nat_nsport);
1394 CALC_SUMD(sum1, sum2, sumd);
1395 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1396
1397 sum1 = LONG_SUM6(&nat->nat_odst6);
1398 sum1 += ntohs(nat->nat_odport);
1399 sum2 = LONG_SUM6(&nat->nat_ndst6);
1400 sum2 += ntohs(nat->nat_ndport);
1401 CALC_SUMD(sum1, sum2, sumd);
1402 nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
1403 break;
1404 }
1405
1406 nat->nat_sumd[1] = nat->nat_sumd[0];
1407
1408 if ((nat->nat_flags & SI_CLONE) == 0)
1409 nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
1410
1411 if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
1412 nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
1413 }
1414
1415 if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
1416 nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
1417 }
1418
1419 nat->nat_v[0] = 6;
1420 nat->nat_v[1] = 6;
1421
1422 if (ipf_nat6_insert(softc, softn, nat) == 0) {
1423 if (softn->ipf_nat_logging)
1424 ipf_nat_log(softc, softn, nat, NL_NEW);
1425 fr = nat->nat_fr;
1426 if (fr != NULL) {
1427 MUTEX_ENTER(&fr->fr_lock);
1428 fr->fr_ref++;
1429 MUTEX_EXIT(&fr->fr_lock);
1430 }
1431 return 0;
1432 }
1433
1434 NBUMPSIDE6D(fin->fin_out, ns_unfinalised);
1435 /*
1436 * nat6_insert failed, so cleanup time...
1437 */
1438 return -1;
1439 }
1440
1441
1442 /* ------------------------------------------------------------------------ */
1443 /* Function: ipf_nat6_insert */
1444 /* Returns: int - 0 == sucess, -1 == failure */
1445 /* Parameters: nat(I) - pointer to NAT structure */
1446 /* rev(I) - flag indicating forward/reverse direction of packet */
1447 /* Write Lock: ipf_nat */
1448 /* */
1449 /* Insert a NAT entry into the hash tables for searching and add it to the */
1450 /* list of active NAT entries. Adjust global counters when complete. */
1451 /* ------------------------------------------------------------------------ */
1452 static int
1453 ipf_nat6_insert(softc, softn, nat)
1454 ipf_main_softc_t *softc;
1455 ipf_nat_softc_t *softn;
1456 nat_t *nat;
1457 {
1458 u_int hv1, hv2;
1459 nat_t **natp;
1460 ipnat_t *in;
1461
1462 /*
1463 * Try and return an error as early as possible, so calculate the hash
1464 * entry numbers first and then proceed.
1465 */
1466 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
1467 hv1 = NAT_HASH_FN6(&nat->nat_osrc6, nat->nat_osport,
1468 0xffffffff);
1469 hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1 + nat->nat_odport,
1470 softn->ipf_nat_table_sz);
1471
1472 /*
1473 * TRACE nat6_osrc6, nat6_osport, nat6_odst6,
1474 * nat6_odport, hv1
1475 */
1476
1477 hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, nat->nat_nsport,
1478 0xffffffff);
1479 hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2 + nat->nat_ndport,
1480 softn->ipf_nat_table_sz);
1481 /*
1482 * TRACE nat6_nsrcaddr, nat6_nsport, nat6_ndstaddr,
1483 * nat6_ndport, hv1
1484 */
1485 } else {
1486 hv1 = NAT_HASH_FN6(&nat->nat_osrc6, 0, 0xffffffff);
1487 hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1,
1488 softn->ipf_nat_table_sz);
1489 /* TRACE nat6_osrcip6, nat6_odstip6, hv1 */
1490
1491 hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, 0, 0xffffffff);
1492 hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2,
1493 softn->ipf_nat_table_sz);
1494 /* TRACE nat6_nsrcip6, nat6_ndstip6, hv2 */
1495 }
1496
1497 if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv1] >=
1498 softn->ipf_nat_maxbucket) {
1499 NBUMPSIDE6D(0, ns_bucket_max);
1500 return -1;
1501 }
1502
1503 if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv2] >=
1504 softn->ipf_nat_maxbucket) {
1505 NBUMPSIDE6D(1, ns_bucket_max);
1506 return -1;
1507 }
1508 if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_ENCAPIN ||
1509 nat->nat_dir == NAT_DIVERTIN) {
1510 u_int swap;
1511
1512 swap = hv2;
1513 hv2 = hv1;
1514 hv1 = swap;
1515 }
1516 nat->nat_hv[0] = hv1;
1517 nat->nat_hv[1] = hv2;
1518
1519 MUTEX_INIT(&nat->nat_lock, "nat entry lock");
1520
1521 in = nat->nat_ptr;
1522 nat->nat_ref = 1;
1523 nat->nat_bytes[0] = 0;
1524 nat->nat_pkts[0] = 0;
1525 nat->nat_bytes[1] = 0;
1526 nat->nat_pkts[1] = 0;
1527
1528 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
1529 nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0],
1530 nat->nat_v[0]);
1531
1532 if (nat->nat_ifnames[1][0] != '\0') {
1533 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1534 nat->nat_ifps[1] = ipf_resolvenic(softc, nat->nat_ifnames[1],
1535 nat->nat_v[1]);
1536 } else if (in->in_ifnames[1] != -1) {
1537 char *name;
1538
1539 name = in->in_names + in->in_ifnames[1];
1540 if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
1541 (void) strncpy(nat->nat_ifnames[1],
1542 nat->nat_ifnames[0], LIFNAMSIZ);
1543 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1544 nat->nat_ifps[1] = nat->nat_ifps[0];
1545 }
1546 }
1547 if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
1548 nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
1549 }
1550 if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
1551 nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
1552 }
1553
1554 nat->nat_next = softn->ipf_nat_instances;
1555 nat->nat_pnext = &softn->ipf_nat_instances;
1556 if (softn->ipf_nat_instances)
1557 softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
1558 softn->ipf_nat_instances = nat;
1559
1560 natp = &softn->ipf_nat_table[0][hv1];
1561 if (*natp)
1562 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
1563 else
1564 NBUMPSIDE6(0, ns_inuse);
1565 nat->nat_phnext[0] = natp;
1566 nat->nat_hnext[0] = *natp;
1567 *natp = nat;
1568 softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv1]++;
1569
1570 natp = &softn->ipf_nat_table[1][hv2];
1571 if (*natp)
1572 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
1573 else
1574 NBUMPSIDE6(1, ns_inuse);
1575 nat->nat_phnext[1] = natp;
1576 nat->nat_hnext[1] = *natp;
1577 *natp = nat;
1578 softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv2]++;
1579
1580 ipf_nat_setqueue(softc, softn, nat);
1581
1582 softn->ipf_nat_stats.ns_side[1].ns_added++;
1583 softn->ipf_nat_stats.ns_active++;
1584 return 0;
1585 }
1586
1587
1588 /* ------------------------------------------------------------------------ */
1589 /* Function: ipf_nat6_icmperrorlookup */
1590 /* Returns: nat6_t* - point to matching NAT structure */
1591 /* Parameters: fin(I) - pointer to packet information */
1592 /* dir(I) - direction of packet (in/out) */
1593 /* */
1594 /* Check if the ICMP error message is related to an existing TCP, UDP or */
1595 /* ICMP query nat entry. It is assumed that the packet is already of the */
1596 /* the required length. */
1597 /* ------------------------------------------------------------------------ */
1598 nat_t *
1599 ipf_nat6_icmperrorlookup(fin, dir)
1600 fr_info_t *fin;
1601 int dir;
1602 {
1603 ipf_main_softc_t *softc = fin->fin_main_soft;
1604 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1605 struct icmp6_hdr *icmp6, *orgicmp;
1606 int flags = 0, type, minlen;
1607 nat_stat_side_t *nside;
1608 tcphdr_t *tcp = NULL;
1609 u_short data[2];
1610 ip6_t *oip6;
1611 nat_t *nat;
1612 u_int p;
1613
1614 minlen = 40;
1615 icmp6 = fin->fin_dp;
1616 type = icmp6->icmp6_type;
1617 nside = &softn->ipf_nat_stats.ns_side6[fin->fin_out];
1618 /*
1619 * Does it at least have the return (basic) IP header ?
1620 * Only a basic IP header (no options) should be with an ICMP error
1621 * header. Also, if it's not an error type, then return.
1622 */
1623 if (!(fin->fin_flx & FI_ICMPERR)) {
1624 ATOMIC_INCL(nside->ns_icmp_basic);
1625 return NULL;
1626 }
1627
1628 /*
1629 * Check packet size
1630 */
1631 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) {
1632 ATOMIC_INCL(nside->ns_icmp_size);
1633 return NULL;
1634 }
1635 oip6 = (ip6_t *)((char *)fin->fin_dp + 8);
1636
1637 /*
1638 * Is the buffer big enough for all of it ? It's the size of the IP
1639 * header claimed in the encapsulated part which is of concern. It
1640 * may be too big to be in this buffer but not so big that it's
1641 * outside the ICMP packet, leading to TCP deref's causing problems.
1642 * This is possible because we don't know how big oip_hl is when we
1643 * do the pullup early in ipf_check() and thus can't gaurantee it is
1644 * all here now.
1645 */
1646 #ifdef ipf_nat6_KERNEL
1647 {
1648 mb_t *m;
1649
1650 m = fin->fin_m;
1651 # if defined(MENTAT)
1652 if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
1653 (char *)m->b_wptr) {
1654 ATOMIC_INCL(nside->ns_icmp_mbuf);
1655 return NULL;
1656 }
1657 # else
1658 if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
1659 (char *)fin->fin_ip + M_LEN(m)) {
1660 ATOMIC_INCL(nside->ns_icmp_mbuf);
1661 return NULL;
1662 }
1663 # endif
1664 }
1665 #endif
1666
1667 if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src)) {
1668 ATOMIC_INCL(nside->ns_icmp_address);
1669 return NULL;
1670 }
1671
1672 p = oip6->ip6_nxt;
1673 if (p == IPPROTO_TCP)
1674 flags = IPN_TCP;
1675 else if (p == IPPROTO_UDP)
1676 flags = IPN_UDP;
1677 else if (p == IPPROTO_ICMPV6) {
1678 orgicmp = (struct icmp6_hdr *)(oip6 + 1);
1679
1680 /* see if this is related to an ICMP query */
1681 if (ipf_nat6_icmpquerytype(orgicmp->icmp6_type)) {
1682 data[0] = fin->fin_data[0];
1683 data[1] = fin->fin_data[1];
1684 fin->fin_data[0] = 0;
1685 fin->fin_data[1] = orgicmp->icmp6_id;
1686
1687 flags = IPN_ICMPERR|IPN_ICMPQUERY;
1688 /*
1689 * NOTE : dir refers to the direction of the original
1690 * ip packet. By definition the icmp error
1691 * message flows in the opposite direction.
1692 */
1693 if (dir == NAT_INBOUND)
1694 nat = ipf_nat6_inlookup(fin, flags, p,
1695 &oip6->ip6_dst,
1696 &oip6->ip6_src);
1697 else
1698 nat = ipf_nat6_outlookup(fin, flags, p,
1699 &oip6->ip6_dst,
1700 &oip6->ip6_src);
1701 fin->fin_data[0] = data[0];
1702 fin->fin_data[1] = data[1];
1703 return nat;
1704 }
1705 }
1706
1707 if (flags & IPN_TCPUDP) {
1708 minlen += 8; /* + 64bits of data to get ports */
1709 /* TRACE (fin,minlen) */
1710 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
1711 ATOMIC_INCL(nside->ns_icmp_short);
1712 return NULL;
1713 }
1714
1715 data[0] = fin->fin_data[0];
1716 data[1] = fin->fin_data[1];
1717 tcp = (tcphdr_t *)(oip6 + 1);
1718 fin->fin_data[0] = ntohs(tcp->th_dport);
1719 fin->fin_data[1] = ntohs(tcp->th_sport);
1720
1721 if (dir == NAT_INBOUND) {
1722 nat = ipf_nat6_inlookup(fin, flags, p, &oip6->ip6_dst,
1723 &oip6->ip6_src);
1724 } else {
1725 nat = ipf_nat6_outlookup(fin, flags, p, &oip6->ip6_dst,
1726 &oip6->ip6_src);
1727 }
1728 fin->fin_data[0] = data[0];
1729 fin->fin_data[1] = data[1];
1730 return nat;
1731 }
1732 if (dir == NAT_INBOUND)
1733 nat = ipf_nat6_inlookup(fin, 0, p, &oip6->ip6_dst,
1734 &oip6->ip6_src);
1735 else
1736 nat = ipf_nat6_outlookup(fin, 0, p, &oip6->ip6_dst,
1737 &oip6->ip6_src);
1738
1739 return nat;
1740 }
1741
1742
1743 /* result = ip1 - ip2 */
1744 u_32_t
1745 ipf_nat6_ip6subtract(ip1, ip2)
1746 i6addr_t *ip1, *ip2;
1747 {
1748 i6addr_t l1, l2, d;
1749 u_short *s1, *s2, *ds;
1750 u_32_t r;
1751 int i, neg;
1752
1753 neg = 0;
1754 l1 = *ip1;
1755 l2 = *ip2;
1756 s1 = (u_short *)&l1;
1757 s2 = (u_short *)&l2;
1758 ds = (u_short *)&d;
1759
1760 for (i = 7; i > 0; i--) {
1761 if (s1[i] > s2[i]) {
1762 ds[i] = s2[i] + 0x10000 - s1[i];
1763 s2[i - 1] += 0x10000;
1764 } else {
1765 ds[i] = s2[i] - s1[i];
1766 }
1767 }
1768 if (s2[0] > s1[0]) {
1769 ds[0] = s2[0] + 0x10000 - s1[0];
1770 neg = 1;
1771 } else {
1772 ds[0] = s2[0] - s1[0];
1773 }
1774
1775 for (i = 0, r = 0; i < 8; i++) {
1776 r += ds[i];
1777 }
1778
1779 return r;
1780 }
1781
1782
1783 /* ------------------------------------------------------------------------ */
1784 /* Function: ipf_nat6_icmperror */
1785 /* Returns: nat6_t* - point to matching NAT structure */
1786 /* Parameters: fin(I) - pointer to packet information */
1787 /* nflags(I) - NAT flags for this packet */
1788 /* dir(I) - direction of packet (in/out) */
1789 /* */
1790 /* Fix up an ICMP packet which is an error message for an existing NAT */
1791 /* session. This will correct both packet header data and checksums. */
1792 /* */
1793 /* This should *ONLY* be used for incoming ICMP error packets to make sure */
1794 /* a NAT'd ICMP packet gets correctly recognised. */
1795 /* ------------------------------------------------------------------------ */
1796 nat_t *
1797 ipf_nat6_icmperror(fin, nflags, dir)
1798 fr_info_t *fin;
1799 u_int *nflags;
1800 int dir;
1801 {
1802 ipf_main_softc_t *softc = fin->fin_main_soft;
1803 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1804 u_32_t sum1, sum2, sumd, sumd2;
1805 i6addr_t a1, a2, a3, a4;
1806 struct icmp6_hdr *icmp6;
1807 int flags, dlen, odst;
1808 u_short *csump;
1809 tcphdr_t *tcp;
1810 ip6_t *oip6;
1811 nat_t *nat;
1812 void *dp;
1813
1814 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
1815 NBUMPSIDE6D(fin->fin_out, ns_icmp_short);
1816 return NULL;
1817 }
1818
1819 /*
1820 * ipf_nat6_icmperrorlookup() will return NULL for `defective' packets.
1821 */
1822 if ((fin->fin_v != 6) || !(nat = ipf_nat6_icmperrorlookup(fin, dir))) {
1823 NBUMPSIDE6D(fin->fin_out, ns_icmp_notfound);
1824 return NULL;
1825 }
1826
1827 if (nat->nat_dir == NAT_ENCAPIN || nat->nat_dir == NAT_ENCAPOUT) {
1828 /*
1829 * For ICMP replies to encapsulated packets, we need to
1830 * rebuild the ICMP reply completely to match the original
1831 * packet...
1832 */
1833 if (ipf_nat6_rebuildencapicmp(fin, nat) == 0)
1834 return nat;
1835 NBUMPSIDE6D(fin->fin_out, ns_icmp_rebuild);
1836 return NULL;
1837 }
1838
1839 tcp = NULL;
1840 csump = NULL;
1841 flags = 0;
1842 sumd2 = 0;
1843 *nflags = IPN_ICMPERR;
1844 icmp6 = fin->fin_dp;
1845 oip6 = (ip6_t *)((u_char *)icmp6 + sizeof(*icmp6));
1846 dp = (u_char *)oip6 + sizeof(*oip6);
1847 if (oip6->ip6_nxt == IPPROTO_TCP) {
1848 tcp = (tcphdr_t *)dp;
1849 csump = (u_short *)&tcp->th_sum;
1850 flags = IPN_TCP;
1851 } else if (oip6->ip6_nxt == IPPROTO_UDP) {
1852 udphdr_t *udp;
1853
1854 udp = (udphdr_t *)dp;
1855 tcp = (tcphdr_t *)dp;
1856 csump = (u_short *)&udp->uh_sum;
1857 flags = IPN_UDP;
1858 } else if (oip6->ip6_nxt == IPPROTO_ICMPV6)
1859 flags = IPN_ICMPQUERY;
1860 dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
1861
1862 /*
1863 * Need to adjust ICMP header to include the real IP#'s and
1864 * port #'s. Only apply a checksum change relative to the
1865 * IP address change as it will be modified again in ipf_nat6_checkout
1866 * for both address and port. Two checksum changes are
1867 * necessary for the two header address changes. Be careful
1868 * to only modify the checksum once for the port # and twice
1869 * for the IP#.
1870 */
1871
1872 /*
1873 * Step 1
1874 * Fix the IP addresses in the offending IP packet. You also need
1875 * to adjust the IP header checksum of that offending IP packet.
1876 *
1877 * Normally, you would expect that the ICMP checksum of the
1878 * ICMP error message needs to be adjusted as well for the
1879 * IP address change in oip.
1880 * However, this is a NOP, because the ICMP checksum is
1881 * calculated over the complete ICMP packet, which includes the
1882 * changed oip IP addresses and oip6->ip6_sum. However, these
1883 * two changes cancel each other out (if the delta for
1884 * the IP address is x, then the delta for ip_sum is minus x),
1885 * so no change in the icmp_cksum is necessary.
1886 *
1887 * Inbound ICMP
1888 * ------------
1889 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
1890 * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
1891 * - OIP_SRC(c)=nat6_newsrcip, OIP_DST(b)=nat6_newdstip
1892 *=> OIP_SRC(c)=nat6_oldsrcip, OIP_DST(b)=nat6_olddstip
1893 *
1894 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
1895 * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
1896 * - OIP_SRC(b)=nat6_olddstip, OIP_DST(a)=nat6_oldsrcip
1897 *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
1898 *
1899 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
1900 * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
1901 * - OIP_SRC(c)=nat6_newsrcip, OIP_DST(d)=nat6_newdstip
1902 *=> OIP_SRC(c)=nat6_oldsrcip, OIP_DST(d)=nat6_olddstip
1903 *
1904 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
1905 * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
1906 * - OIP_SRC(b)=nat6_olddstip, OIP_DST(a)=nat6_oldsrcip
1907 *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
1908 *
1909 * Outbound ICMP
1910 * -------------
1911 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
1912 * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
1913 * - OIP_SRC(b)=nat6_olddstip, OIP_DST(a)=nat6_oldsrcip
1914 *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
1915 *
1916 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
1917 * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
1918 * - OIP_SRC(a)=nat6_newsrcip, OIP_DST(c)=nat6_newdstip
1919 *=> OIP_SRC(a)=nat6_oldsrcip, OIP_DST(c)=nat6_olddstip
1920 *
1921 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
1922 * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
1923 * - OIP_SRC(c)=nat6_olddstip, OIP_DST(d)=nat6_oldsrcip
1924 *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
1925 *
1926 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
1927 * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
1928 * - OIP_SRC(b)=nat6_newsrcip, OIP_DST(a)=nat6_newdstip
1929 *=> OIP_SRC(a)=nat6_oldsrcip, OIP_DST(c)=nat6_olddstip
1930 */
1931
1932 if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
1933 ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
1934 a1 = nat->nat_osrc6;
1935 a4.in6 = oip6->ip6_src;
1936 a3 = nat->nat_odst6;
1937 a2.in6 = oip6->ip6_dst;
1938 oip6->ip6_src = a1.in6;
1939 oip6->ip6_dst = a3.in6;
1940 odst = 1;
1941 } else {
1942 a1 = nat->nat_ndst6;
1943 a2.in6 = oip6->ip6_dst;
1944 a3 = nat->nat_nsrc6;
1945 a4.in6 = oip6->ip6_src;
1946 oip6->ip6_dst = a3.in6;
1947 oip6->ip6_src = a1.in6;
1948 odst = 0;
1949 }
1950
1951 sumd = 0;
1952 if (IP6_NEQ(&a3, &a2) || IP6_NEQ(&a1, &a4)) {
1953 if (IP6_GT(&a3, &a2)) {
1954 sumd = ipf_nat6_ip6subtract(&a2, &a3);
1955 sumd--;
1956 } else {
1957 sumd = ipf_nat6_ip6subtract(&a2, &a3);
1958 }
1959 if (IP6_GT(&a1, &a4)) {
1960 sumd += ipf_nat6_ip6subtract(&a4, &a1);
1961 sumd--;
1962 } else {
1963 sumd += ipf_nat6_ip6subtract(&a4, &a1);
1964 }
1965 sumd = ~sumd;
1966 }
1967
1968 sumd2 = sumd;
1969 sum1 = 0;
1970 sum2 = 0;
1971
1972 /*
1973 * Fix UDP pseudo header checksum to compensate for the
1974 * IP address change.
1975 */
1976 if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
1977 u_32_t sum3, sum4;
1978 /*
1979 * Step 2 :
1980 * For offending TCP/UDP IP packets, translate the ports as
1981 * well, based on the NAT specification. Of course such
1982 * a change may be reflected in the ICMP checksum as well.
1983 *
1984 * Since the port fields are part of the TCP/UDP checksum
1985 * of the offending IP packet, you need to adjust that checksum
1986 * as well... except that the change in the port numbers should
1987 * be offset by the checksum change. However, the TCP/UDP
1988 * checksum will also need to change if there has been an
1989 * IP address change.
1990 */
1991 if (odst == 1) {
1992 sum1 = ntohs(nat->nat_osport);
1993 sum4 = ntohs(tcp->th_sport);
1994 sum3 = ntohs(nat->nat_odport);
1995 sum2 = ntohs(tcp->th_dport);
1996
1997 tcp->th_sport = htons(sum1);
1998 tcp->th_dport = htons(sum3);
1999 } else {
2000 sum1 = ntohs(nat->nat_ndport);
2001 sum2 = ntohs(tcp->th_dport);
2002 sum3 = ntohs(nat->nat_nsport);
2003 sum4 = ntohs(tcp->th_sport);
2004
2005 tcp->th_dport = htons(sum3);
2006 tcp->th_sport = htons(sum1);
2007 }
2008 sumd += sum1 - sum4;
2009 sumd += sum3 - sum2;
2010
2011 if (sumd != 0 || sumd2 != 0) {
2012 /*
2013 * At this point, sumd is the delta to apply to the
2014 * TCP/UDP header, given the changes in both the IP
2015 * address and the ports and sumd2 is the delta to
2016 * apply to the ICMP header, given the IP address
2017 * change delta that may need to be applied to the
2018 * TCP/UDP checksum instead.
2019 *
2020 * If we will both the IP and TCP/UDP checksums
2021 * then the ICMP checksum changes by the address
2022 * delta applied to the TCP/UDP checksum. If we
2023 * do not change the TCP/UDP checksum them we
2024 * apply the delta in ports to the ICMP checksum.
2025 */
2026 if (oip6->ip6_nxt == IPPROTO_UDP) {
2027 if ((dlen >= 8) && (*csump != 0)) {
2028 ipf_fix_datacksum(csump, sumd);
2029 } else {
2030 sumd2 = sum4 - sum1;
2031 if (sum1 > sum4)
2032 sumd2--;
2033 sumd2 += sum2 - sum3;
2034 if (sum3 > sum2)
2035 sumd2--;
2036 }
2037 } else if (oip6->ip6_nxt == IPPROTO_TCP) {
2038 if (dlen >= 18) {
2039 ipf_fix_datacksum(csump, sumd);
2040 } else {
2041 sumd2 = sum4 - sum1;
2042 if (sum1 > sum4)
2043 sumd2--;
2044 sumd2 += sum2 - sum3;
2045 if (sum3 > sum2)
2046 sumd2--;
2047 }
2048 }
2049 if (sumd2 != 0) {
2050 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
2051 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
2052 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
2053 ipf_fix_incksum(fin, &icmp6->icmp6_cksum,
2054 sumd2);
2055 }
2056 }
2057 } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
2058 struct icmp6_hdr *orgicmp;
2059
2060 /*
2061 * XXX - what if this is bogus hl and we go off the end ?
2062 * In this case, ipf_nat6_icmperrorlookup() will have
2063 * returned NULL.
2064 */
2065 orgicmp = (struct icmp6_hdr *)dp;
2066
2067 if (odst == 1) {
2068 if (orgicmp->icmp6_id != nat->nat_osport) {
2069
2070 /*
2071 * Fix ICMP checksum (of the offening ICMP
2072 * query packet) to compensate the change
2073 * in the ICMP id of the offending ICMP
2074 * packet.
2075 *
2076 * Since you modify orgicmp->icmp6_id with
2077 * a delta (say x) and you compensate that
2078 * in origicmp->icmp6_cksum with a delta
2079 * minus x, you don't have to adjust the
2080 * overall icmp->icmp6_cksum
2081 */
2082 sum1 = ntohs(orgicmp->icmp6_id);
2083 sum2 = ntohs(nat->nat_osport);
2084 CALC_SUMD(sum1, sum2, sumd);
2085 orgicmp->icmp6_id = nat->nat_oicmpid;
2086 ipf_fix_datacksum(&orgicmp->icmp6_cksum, sumd);
2087 }
2088 } /* nat6_dir == NAT_INBOUND is impossible for icmp queries */
2089 }
2090 return nat;
2091 }
2092
2093
2094 /*
2095 * MAP-IN MAP-OUT RDR-IN RDR-OUT
2096 * osrc X == src == src X
2097 * odst X == dst == dst X
2098 * nsrc == dst X X == dst
2099 * ndst == src X X == src
2100 * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
2101 */
2102 /*
2103 * NB: these lookups don't lock access to the list, it assumed that it has
2104 * already been done!
2105 */
2106 /* ------------------------------------------------------------------------ */
2107 /* Function: ipf_nat6_inlookup */
2108 /* Returns: nat6_t* - NULL == no match, */
2109 /* else pointer to matching NAT entry */
2110 /* Parameters: fin(I) - pointer to packet information */
2111 /* flags(I) - NAT flags for this packet */
2112 /* p(I) - protocol for this packet */
2113 /* src(I) - source IP address */
2114 /* mapdst(I) - destination IP address */
2115 /* */
2116 /* Lookup a nat entry based on the mapped destination ip address/port and */
2117 /* real source address/port. We use this lookup when receiving a packet, */
2118 /* we're looking for a table entry, based on the destination address. */
2119 /* */
2120 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
2121 /* */
2122 /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */
2123 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
2124 /* */
2125 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
2126 /* the packet is of said protocol */
2127 /* ------------------------------------------------------------------------ */
2128 nat_t *
2129 ipf_nat6_inlookup(fin, flags, p, src, mapdst)
2130 fr_info_t *fin;
2131 u_int flags, p;
2132 struct in6_addr *src , *mapdst;
2133 {
2134 ipf_main_softc_t *softc = fin->fin_main_soft;
2135 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2136 u_short sport, dport;
2137 grehdr_t *gre;
2138 ipnat_t *ipn;
2139 u_int sflags;
2140 nat_t *nat;
2141 int nflags;
2142 i6addr_t dst;
2143 void *ifp;
2144 u_int hv;
2145
2146 ifp = fin->fin_ifp;
2147 sport = 0;
2148 dport = 0;
2149 gre = NULL;
2150 dst.in6 = *mapdst;
2151 sflags = flags & NAT_TCPUDPICMP;
2152
2153 switch (p)
2154 {
2155 case IPPROTO_TCP :
2156 case IPPROTO_UDP :
2157 sport = htons(fin->fin_data[0]);
2158 dport = htons(fin->fin_data[1]);
2159 break;
2160 case IPPROTO_ICMPV6 :
2161 if (flags & IPN_ICMPERR)
2162 sport = fin->fin_data[1];
2163 else
2164 dport = fin->fin_data[1];
2165 break;
2166 default :
2167 break;
2168 }
2169
2170
2171 if ((flags & SI_WILDP) != 0)
2172 goto find_in_wild_ports;
2173
2174 hv = NAT_HASH_FN6(&dst, dport, 0xffffffff);
2175 hv = NAT_HASH_FN6(src, hv + sport, softn->ipf_nat_table_sz);
2176 nat = softn->ipf_nat_table[1][hv];
2177 /* TRACE dst, dport, src, sport, hv, nat */
2178
2179 for (; nat; nat = nat->nat_hnext[1]) {
2180 if (nat->nat_ifps[0] != NULL) {
2181 if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
2182 continue;
2183 }
2184
2185 if (nat->nat_pr[0] != p)
2186 continue;
2187
2188 switch (nat->nat_dir)
2189 {
2190 case NAT_INBOUND :
2191 if (nat->nat_v[0] != 6)
2192 continue;
2193 if (IP6_NEQ(&nat->nat_osrc6, src) ||
2194 IP6_NEQ(&nat->nat_odst6, &dst))
2195 continue;
2196 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
2197 if (nat->nat_osport != sport)
2198 continue;
2199 if (nat->nat_odport != dport)
2200 continue;
2201
2202 } else if (p == IPPROTO_ICMPV6) {
2203 if (nat->nat_osport != dport) {
2204 continue;
2205 }
2206 }
2207 break;
2208 case NAT_OUTBOUND :
2209 if (nat->nat_v[1] != 6)
2210 continue;
2211 if (IP6_NEQ(&nat->nat_ndst6, src) ||
2212 IP6_NEQ(&nat->nat_nsrc6, &dst))
2213 continue;
2214 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
2215 if (nat->nat_ndport != sport)
2216 continue;
2217 if (nat->nat_nsport != dport)
2218 continue;
2219
2220 } else if (p == IPPROTO_ICMPV6) {
2221 if (nat->nat_osport != dport) {
2222 continue;
2223 }
2224 }
2225 break;
2226 }
2227
2228
2229 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
2230 ipn = nat->nat_ptr;
2231 #ifdef IPF_V6_PROXIES
2232 if ((ipn != NULL) && (nat->nat_aps != NULL))
2233 if (appr_match(fin, nat) != 0)
2234 continue;
2235 #endif
2236 }
2237 if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
2238 nat->nat_ifps[0] = ifp;
2239 nat->nat_mtu[0] = GETIFMTU_6(ifp);
2240 }
2241 return nat;
2242 }
2243
2244 /*
2245 * So if we didn't find it but there are wildcard members in the hash
2246 * table, go back and look for them. We do this search and update here
2247 * because it is modifying the NAT table and we want to do this only
2248 * for the first packet that matches. The exception, of course, is
2249 * for "dummy" (FI_IGNORE) lookups.
2250 */
2251 find_in_wild_ports:
2252 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
2253 NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_1);
2254 return NULL;
2255 }
2256 if (softn->ipf_nat_stats.ns_wilds == 0) {
2257 NBUMPSIDE6D(0, ns_lookup_nowild);
2258 return NULL;
2259 }
2260
2261 RWLOCK_EXIT(&softc->ipf_nat);
2262
2263 hv = NAT_HASH_FN6(&dst, 0, 0xffffffff);
2264 hv = NAT_HASH_FN6(src, hv, softn->ipf_nat_table_sz);
2265 WRITE_ENTER(&softc->ipf_nat);
2266
2267 nat = softn->ipf_nat_table[1][hv];
2268 /* TRACE dst, src, hv, nat */
2269 for (; nat; nat = nat->nat_hnext[1]) {
2270 if (nat->nat_ifps[0] != NULL) {
2271 if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
2272 continue;
2273 }
2274
2275 if (nat->nat_pr[0] != fin->fin_p)
2276 continue;
2277
2278 switch (nat->nat_dir)
2279 {
2280 case NAT_INBOUND :
2281 if (nat->nat_v[0] != 6)
2282 continue;
2283 if (IP6_NEQ(&nat->nat_osrc6, src) ||
2284 IP6_NEQ(&nat->nat_odst6, &dst))
2285 continue;
2286 break;
2287 case NAT_OUTBOUND :
2288 if (nat->nat_v[1] != 6)
2289 continue;
2290 if (IP6_NEQ(&nat->nat_ndst6, src) ||
2291 IP6_NEQ(&nat->nat_nsrc6, &dst))
2292 continue;
2293 break;
2294 }
2295
2296 nflags = nat->nat_flags;
2297 if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
2298 continue;
2299
2300 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
2301 NAT_INBOUND) == 1) {
2302 if ((fin->fin_flx & FI_IGNORE) != 0)
2303 break;
2304 if ((nflags & SI_CLONE) != 0) {
2305 nat = ipf_nat_clone(fin, nat);
2306 if (nat == NULL)
2307 break;
2308 } else {
2309 MUTEX_ENTER(&softn->ipf_nat_new);
2310 softn->ipf_nat_stats.ns_wilds--;
2311 MUTEX_EXIT(&softn->ipf_nat_new);
2312 }
2313
2314 if (nat->nat_dir == NAT_INBOUND) {
2315 if (nat->nat_osport == 0) {
2316 nat->nat_osport = sport;
2317 nat->nat_nsport = sport;
2318 }
2319 if (nat->nat_odport == 0) {
2320 nat->nat_odport = dport;
2321 nat->nat_ndport = dport;
2322 }
2323 } else {
2324 if (nat->nat_osport == 0) {
2325 nat->nat_osport = dport;
2326 nat->nat_nsport = dport;
2327 }
2328 if (nat->nat_odport == 0) {
2329 nat->nat_odport = sport;
2330 nat->nat_ndport = sport;
2331 }
2332 }
2333 if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
2334 nat->nat_ifps[0] = ifp;
2335 nat->nat_mtu[0] = GETIFMTU_6(ifp);
2336 }
2337 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
2338 ipf_nat6_tabmove(softn, nat);
2339 break;
2340 }
2341 }
2342
2343 MUTEX_DOWNGRADE(&softc->ipf_nat);
2344
2345 if (nat == NULL) {
2346 NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_2);
2347 }
2348 return nat;
2349 }
2350
2351
2352 /* ------------------------------------------------------------------------ */
2353 /* Function: ipf_nat6_tabmove */
2354 /* Returns: Nil */
2355 /* Parameters: nat(I) - pointer to NAT structure */
2356 /* Write Lock: ipf_nat */
2357 /* */
2358 /* This function is only called for TCP/UDP NAT table entries where the */
2359 /* original was placed in the table without hashing on the ports and we now */
2360 /* want to include hashing on port numbers. */
2361 /* ------------------------------------------------------------------------ */
2362 static void
2363 ipf_nat6_tabmove(softn, nat)
2364 ipf_nat_softc_t *softn;
2365 nat_t *nat;
2366 {
2367 nat_t **natp;
2368 u_int hv0, hv1;
2369
2370 if (nat->nat_flags & SI_CLONE)
2371 return;
2372
2373 /*
2374 * Remove the NAT entry from the old location
2375 */
2376 if (nat->nat_hnext[0])
2377 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
2378 *nat->nat_phnext[0] = nat->nat_hnext[0];
2379 softn->ipf_nat_stats.ns_side[0].ns_bucketlen[nat->nat_hv[0]]--;
2380
2381 if (nat->nat_hnext[1])
2382 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
2383 *nat->nat_phnext[1] = nat->nat_hnext[1];
2384 softn->ipf_nat_stats.ns_side[1].ns_bucketlen[nat->nat_hv[1]]--;
2385
2386 /*
2387 * Add into the NAT table in the new position
2388 */
2389 hv0 = NAT_HASH_FN6(&nat->nat_osrc6, nat->nat_osport, 0xffffffff);
2390 hv0 = NAT_HASH_FN6(&nat->nat_odst6, hv0 + nat->nat_odport,
2391 softn->ipf_nat_table_sz);
2392 hv1 = NAT_HASH_FN6(&nat->nat_nsrc6, nat->nat_nsport, 0xffffffff);
2393 hv1 = NAT_HASH_FN6(&nat->nat_ndst6, hv1 + nat->nat_ndport,
2394 softn->ipf_nat_table_sz);
2395
2396 if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_ENCAPIN ||
2397 nat->nat_dir == NAT_DIVERTIN) {
2398 u_int swap;
2399
2400 swap = hv0;
2401 hv0 = hv1;
2402 hv1 = swap;
2403 }
2404
2405 /* TRACE nat_osrc6, nat_osport, nat_odst6, nat_odport, hv0 */
2406 /* TRACE nat_nsrc6, nat_nsport, nat_ndst6, nat_ndport, hv1 */
2407
2408 nat->nat_hv[0] = hv0;
2409 natp = &softn->ipf_nat_table[0][hv0];
2410 if (*natp)
2411 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
2412 nat->nat_phnext[0] = natp;
2413 nat->nat_hnext[0] = *natp;
2414 *natp = nat;
2415 softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]++;
2416
2417 nat->nat_hv[1] = hv1;
2418 natp = &softn->ipf_nat_table[1][hv1];
2419 if (*natp)
2420 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
2421 nat->nat_phnext[1] = natp;
2422 nat->nat_hnext[1] = *natp;
2423 *natp = nat;
2424 softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]++;
2425 }
2426
2427
2428 /* ------------------------------------------------------------------------ */
2429 /* Function: ipf_nat6_outlookup */
2430 /* Returns: nat6_t* - NULL == no match, */
2431 /* else pointer to matching NAT entry */
2432 /* Parameters: fin(I) - pointer to packet information */
2433 /* flags(I) - NAT flags for this packet */
2434 /* p(I) - protocol for this packet */
2435 /* src(I) - source IP address */
2436 /* dst(I) - destination IP address */
2437 /* rw(I) - 1 == write lock on held, 0 == read lock. */
2438 /* */
2439 /* Lookup a nat entry based on the source 'real' ip address/port and */
2440 /* destination address/port. We use this lookup when sending a packet out, */
2441 /* we're looking for a table entry, based on the source address. */
2442 /* */
2443 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
2444 /* */
2445 /* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */
2446 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
2447 /* */
2448 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
2449 /* the packet is of said protocol */
2450 /* ------------------------------------------------------------------------ */
2451 nat_t *
2452 ipf_nat6_outlookup(fin, flags, p, src, dst)
2453 fr_info_t *fin;
2454 u_int flags, p;
2455 struct in6_addr *src , *dst;
2456 {
2457 ipf_main_softc_t *softc = fin->fin_main_soft;
2458 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2459 u_short sport, dport;
2460 u_int sflags;
2461 ipnat_t *ipn;
2462 nat_t *nat;
2463 void *ifp;
2464 u_int hv;
2465
2466 ifp = fin->fin_ifp;
2467 sflags = flags & IPN_TCPUDPICMP;
2468 sport = 0;
2469 dport = 0;
2470
2471 switch (p)
2472 {
2473 case IPPROTO_TCP :
2474 case IPPROTO_UDP :
2475 sport = htons(fin->fin_data[0]);
2476 dport = htons(fin->fin_data[1]);
2477 break;
2478 case IPPROTO_ICMPV6 :
2479 if (flags & IPN_ICMPERR)
2480 sport = fin->fin_data[1];
2481 else
2482 dport = fin->fin_data[1];
2483 break;
2484 default :
2485 break;
2486 }
2487
2488 if ((flags & SI_WILDP) != 0)
2489 goto find_out_wild_ports;
2490
2491 hv = NAT_HASH_FN6(src, sport, 0xffffffff);
2492 hv = NAT_HASH_FN6(dst, hv + dport, softn->ipf_nat_table_sz);
2493 nat = softn->ipf_nat_table[0][hv];
2494
2495 /* TRACE src, sport, dst, dport, hv, nat */
2496
2497 for (; nat; nat = nat->nat_hnext[0]) {
2498 if (nat->nat_ifps[1] != NULL) {
2499 if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
2500 continue;
2501 }
2502
2503 if (nat->nat_pr[1] != p)
2504 continue;
2505
2506 switch (nat->nat_dir)
2507 {
2508 case NAT_INBOUND :
2509 if (nat->nat_v[1] != 6)
2510 continue;
2511 if (IP6_NEQ(&nat->nat_ndst6, src) ||
2512 IP6_NEQ(&nat->nat_nsrc6, dst))
2513 continue;
2514
2515 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
2516 if (nat->nat_ndport != sport)
2517 continue;
2518 if (nat->nat_nsport != dport)
2519 continue;
2520
2521 } else if (p == IPPROTO_ICMPV6) {
2522 if (nat->nat_osport != dport) {
2523 continue;
2524 }
2525 }
2526 break;
2527 case NAT_OUTBOUND :
2528 if (nat->nat_v[0] != 6)
2529 continue;
2530 if (IP6_NEQ(&nat->nat_osrc6, src) ||
2531 IP6_NEQ(&nat->nat_odst6, dst))
2532 continue;
2533
2534 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
2535 if (nat->nat_odport != dport)
2536 continue;
2537 if (nat->nat_osport != sport)
2538 continue;
2539
2540 } else if (p == IPPROTO_ICMPV6) {
2541 if (nat->nat_osport != dport) {
2542 continue;
2543 }
2544 }
2545 break;
2546 }
2547
2548 ipn = nat->nat_ptr;
2549 #ifdef IPF_V6_PROXIES
2550 if ((ipn != NULL) && (nat->nat_aps != NULL))
2551 if (appr_match(fin, nat) != 0)
2552 continue;
2553 #endif
2554
2555 if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
2556 nat->nat_ifps[1] = ifp;
2557 nat->nat_mtu[1] = GETIFMTU_6(ifp);
2558 }
2559 return nat;
2560 }
2561
2562 /*
2563 * So if we didn't find it but there are wildcard members in the hash
2564 * table, go back and look for them. We do this search and update here
2565 * because it is modifying the NAT table and we want to do this only
2566 * for the first packet that matches. The exception, of course, is
2567 * for "dummy" (FI_IGNORE) lookups.
2568 */
2569 find_out_wild_ports:
2570 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
2571 NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_3);
2572 return NULL;
2573 }
2574 if (softn->ipf_nat_stats.ns_wilds == 0) {
2575 NBUMPSIDE6D(1, ns_lookup_nowild);
2576 return NULL;
2577 }
2578
2579 RWLOCK_EXIT(&softc->ipf_nat);
2580
2581 hv = NAT_HASH_FN6(src, 0, 0xffffffff);
2582 hv = NAT_HASH_FN6(dst, hv, softn->ipf_nat_table_sz);
2583
2584 WRITE_ENTER(&softc->ipf_nat);
2585
2586 nat = softn->ipf_nat_table[0][hv];
2587 for (; nat; nat = nat->nat_hnext[0]) {
2588 if (nat->nat_ifps[1] != NULL) {
2589 if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
2590 continue;
2591 }
2592
2593 if (nat->nat_pr[1] != fin->fin_p)
2594 continue;
2595
2596 switch (nat->nat_dir)
2597 {
2598 case NAT_INBOUND :
2599 if (nat->nat_v[1] != 6)
2600 continue;
2601 if (IP6_NEQ(&nat->nat_ndst6, src) ||
2602 IP6_NEQ(&nat->nat_nsrc6, dst))
2603 continue;
2604 break;
2605 case NAT_OUTBOUND :
2606 if (nat->nat_v[0] != 6)
2607 continue;
2608 if (IP6_NEQ(&nat->nat_osrc6, src) ||
2609 IP6_NEQ(&nat->nat_odst6, dst))
2610 continue;
2611 break;
2612 }
2613
2614 if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
2615 continue;
2616
2617 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
2618 NAT_OUTBOUND) == 1) {
2619 if ((fin->fin_flx & FI_IGNORE) != 0)
2620 break;
2621 if ((nat->nat_flags & SI_CLONE) != 0) {
2622 nat = ipf_nat_clone(fin, nat);
2623 if (nat == NULL)
2624 break;
2625 } else {
2626 MUTEX_ENTER(&softn->ipf_nat_new);
2627 softn->ipf_nat_stats.ns_wilds--;
2628 MUTEX_EXIT(&softn->ipf_nat_new);
2629 }
2630
2631 if (nat->nat_dir == NAT_OUTBOUND) {
2632 if (nat->nat_osport == 0) {
2633 nat->nat_osport = sport;
2634 nat->nat_nsport = sport;
2635 }
2636 if (nat->nat_odport == 0) {
2637 nat->nat_odport = dport;
2638 nat->nat_ndport = dport;
2639 }
2640 } else {
2641 if (nat->nat_osport == 0) {
2642 nat->nat_osport = dport;
2643 nat->nat_nsport = dport;
2644 }
2645 if (nat->nat_odport == 0) {
2646 nat->nat_odport = sport;
2647 nat->nat_ndport = sport;
2648 }
2649 }
2650 if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
2651 nat->nat_ifps[1] = ifp;
2652 nat->nat_mtu[1] = GETIFMTU_6(ifp);
2653 }
2654 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
2655 ipf_nat6_tabmove(softn, nat);
2656 break;
2657 }
2658 }
2659
2660 MUTEX_DOWNGRADE(&softc->ipf_nat);
2661
2662 if (nat == NULL) {
2663 NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_4);
2664 }
2665 return nat;
2666 }
2667
2668
2669 /* ------------------------------------------------------------------------ */
2670 /* Function: ipf_nat6_lookupredir */
2671 /* Returns: nat6_t* - NULL == no match, */
2672 /* else pointer to matching NAT entry */
2673 /* Parameters: np(I) - pointer to description of packet to find NAT table */
2674 /* entry for. */
2675 /* */
2676 /* Lookup the NAT tables to search for a matching redirect */
2677 /* The contents of natlookup_t should imitate those found in a packet that */
2678 /* would be translated - ie a packet coming in for RDR or going out for MAP.*/
2679 /* We can do the lookup in one of two ways, imitating an inbound or */
2680 /* outbound packet. By default we assume outbound, unless IPN_IN is set. */
2681 /* For IN, the fields are set as follows: */
2682 /* nl_real* = source information */
2683 /* nl_out* = destination information (translated) */
2684 /* For an out packet, the fields are set like this: */
2685 /* nl_in* = source information (untranslated) */
2686 /* nl_out* = destination information (translated) */
2687 /* ------------------------------------------------------------------------ */
2688 nat_t *
2689 ipf_nat6_lookupredir(np)
2690 natlookup_t *np;
2691 {
2692 fr_info_t fi;
2693 nat_t *nat;
2694
2695 bzero((char *)&fi, sizeof(fi));
2696 if (np->nl_flags & IPN_IN) {
2697 fi.fin_data[0] = ntohs(np->nl_realport);
2698 fi.fin_data[1] = ntohs(np->nl_outport);
2699 } else {
2700 fi.fin_data[0] = ntohs(np->nl_inport);
2701 fi.fin_data[1] = ntohs(np->nl_outport);
2702 }
2703 if (np->nl_flags & IPN_TCP)
2704 fi.fin_p = IPPROTO_TCP;
2705 else if (np->nl_flags & IPN_UDP)
2706 fi.fin_p = IPPROTO_UDP;
2707 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
2708 fi.fin_p = IPPROTO_ICMPV6;
2709
2710 /*
2711 * We can do two sorts of lookups:
2712 * - IPN_IN: we have the `real' and `out' address, look for `in'.
2713 * - default: we have the `in' and `out' address, look for `real'.
2714 */
2715 if (np->nl_flags & IPN_IN) {
2716 if ((nat = ipf_nat6_inlookup(&fi, np->nl_flags, fi.fin_p,
2717 &np->nl_realip6,
2718 &np->nl_outip6))) {
2719 np->nl_inip6 = nat->nat_odst6.in6;
2720 np->nl_inport = nat->nat_odport;
2721 }
2722 } else {
2723 /*
2724 * If nl_inip is non null, this is a lookup based on the real
2725 * ip address. Else, we use the fake.
2726 */
2727 if ((nat = ipf_nat6_outlookup(&fi, np->nl_flags, fi.fin_p,
2728 &np->nl_inip6, &np->nl_outip6))) {
2729
2730 if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
2731 fr_info_t fin;
2732 bzero((char *)&fin, sizeof(fin));
2733 fin.fin_p = nat->nat_pr[0];
2734 fin.fin_data[0] = ntohs(nat->nat_ndport);
2735 fin.fin_data[1] = ntohs(nat->nat_nsport);
2736 if (ipf_nat6_inlookup(&fin, np->nl_flags,
2737 fin.fin_p,
2738 &nat->nat_ndst6.in6,
2739 &nat->nat_nsrc6.in6) !=
2740 NULL) {
2741 np->nl_flags &= ~IPN_FINDFORWARD;
2742 }
2743 }
2744
2745 np->nl_realip6 = nat->nat_ndst6.in6;
2746 np->nl_realport = nat->nat_ndport;
2747 }
2748 }
2749
2750 return nat;
2751 }
2752
2753
2754 /* ------------------------------------------------------------------------ */
2755 /* Function: ipf_nat6_match */
2756 /* Returns: int - 0 == no match, 1 == match */
2757 /* Parameters: fin(I) - pointer to packet information */
2758 /* np(I) - pointer to NAT rule */
2759 /* */
2760 /* Pull the matching of a packet against a NAT rule out of that complex */
2761 /* loop inside ipf_nat6_checkin() and lay it out properly in its own */
2762 /* function. */
2763 /* ------------------------------------------------------------------------ */
2764 static int
2765 ipf_nat6_match(fin, np)
2766 fr_info_t *fin;
2767 ipnat_t *np;
2768 {
2769 frtuc_t *ft;
2770 int match;
2771
2772 if ((fin->fin_p == IPPROTO_IPIP) && (np->in_redir & NAT_ENCAP))
2773 return ipf_nat6_matchencap(fin, np);
2774
2775 match = 0;
2776 switch (np->in_osrcatype)
2777 {
2778 case FRI_NORMAL :
2779 match = IP6_MASKNEQ(&fin->fin_src6, &np->in_osrcmsk6,
2780 &np->in_osrcip6);
2781 break;
2782 case FRI_LOOKUP :
2783 match = (*np->in_osrcfunc)(fin->fin_main_soft, np->in_osrcptr,
2784 6, &fin->fin_src6, fin->fin_plen);
2785 break;
2786 }
2787 match ^= ((np->in_flags & IPN_NOTSRC) != 0);
2788 if (match)
2789 return 0;
2790
2791 match = 0;
2792 switch (np->in_odstatype)
2793 {
2794 case FRI_NORMAL :
2795 match = IP6_MASKNEQ(&fin->fin_dst6, &np->in_odstmsk6,
2796 &np->in_odstip6);
2797 break;
2798 case FRI_LOOKUP :
2799 match = (*np->in_odstfunc)(fin->fin_main_soft, np->in_odstptr,
2800 6, &fin->fin_dst6, fin->fin_plen);
2801 break;
2802 }
2803
2804 match ^= ((np->in_flags & IPN_NOTDST) != 0);
2805 if (match)
2806 return 0;
2807
2808 ft = &np->in_tuc;
2809 if (!(fin->fin_flx & FI_TCPUDP) ||
2810 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
2811 if (ft->ftu_scmp || ft->ftu_dcmp)
2812 return 0;
2813 return 1;
2814 }
2815
2816 return ipf_tcpudpchk(&fin->fin_fi, ft);
2817 }
2818
2819
2820 /* ------------------------------------------------------------------------ */
2821 /* Function: ipf_nat6_ipfout */
2822 /* Returns: frentry_t* - NULL (packet may have been translated, let it */
2823 /* pass), &ipfnatblock - block/drop the packet. */
2824 /* Parameters: fin(I) - pointer to packet information */
2825 /* passp(I) - point to filtering result flags */
2826 /* */
2827 /* This is purely and simply a wrapper around ipf_nat6_checkout for the sole*/
2828 /* reason of being able to activate NAT from an ipf rule using "call-now". */
2829 /* ------------------------------------------------------------------------ */
2830 frentry_t *
2831 ipf_nat6_ipfout(fin, passp)
2832 fr_info_t *fin;
2833 u_32_t *passp;
2834 {
2835 frentry_t *fr = fin->fin_fr;
2836
2837 switch (ipf_nat6_checkout(fin, passp))
2838 {
2839 case -1 :
2840 fr = &ipfnatblock;
2841 MUTEX_ENTER(&fr->fr_lock);
2842 fr->fr_ref++;
2843 MUTEX_EXIT(&fr->fr_lock);
2844 return fr;
2845
2846 case 0 :
2847 break;
2848
2849 case 1 :
2850 /*
2851 * Returing NULL causes this rule to be "ignored" but
2852 * it has actually had an influence on the packet so we
2853 * increment counters for it.
2854 */
2855 MUTEX_ENTER(&fr->fr_lock);
2856 fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
2857 fr->fr_hits++;
2858 MUTEX_EXIT(&fr->fr_lock);
2859 break;
2860 }
2861
2862 return NULL;
2863 }
2864
2865
2866 /* ------------------------------------------------------------------------ */
2867 /* Function: ipf_nat6_checkout */
2868 /* Returns: int - -1 == packet failed NAT checks so block it, */
2869 /* 0 == no packet translation occurred, */
2870 /* 1 == packet was successfully translated. */
2871 /* Parameters: fin(I) - pointer to packet information */
2872 /* passp(I) - pointer to filtering result flags */
2873 /* */
2874 /* Check to see if an outcoming packet should be changed. ICMP packets are */
2875 /* first checked to see if they match an existing entry (if an error), */
2876 /* otherwise a search of the current NAT table is made. If neither results */
2877 /* in a match then a search for a matching NAT rule is made. Create a new */
2878 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */
2879 /* packet header(s) as required. */
2880 /* ------------------------------------------------------------------------ */
2881 int
2882 ipf_nat6_checkout(fin, passp)
2883 fr_info_t *fin;
2884 u_32_t *passp;
2885 {
2886 ipf_main_softc_t *softc = fin->fin_main_soft;
2887 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2888 struct icmp6_hdr *icmp6 = NULL;
2889 struct ifnet *ifp, *sifp;
2890 tcphdr_t *tcp = NULL;
2891 int rval, natfailed;
2892 ipnat_t *np = NULL;
2893 u_int nflags = 0;
2894 i6addr_t ipa, iph;
2895 int natadd = 1;
2896 frentry_t *fr;
2897 nat_t *nat;
2898
2899 if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
2900 return 0;
2901
2902 natfailed = 0;
2903 fr = fin->fin_fr;
2904 sifp = fin->fin_ifp;
2905 if (fr != NULL) {
2906 ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
2907 if ((ifp != NULL) && (ifp != (void *)-1))
2908 fin->fin_ifp = ifp;
2909 }
2910 ifp = fin->fin_ifp;
2911
2912 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2913 switch (fin->fin_p)
2914 {
2915 case IPPROTO_TCP :
2916 nflags = IPN_TCP;
2917 break;
2918 case IPPROTO_UDP :
2919 nflags = IPN_UDP;
2920 break;
2921 case IPPROTO_ICMPV6 :
2922 icmp6 = fin->fin_dp;
2923
2924 /*
2925 * This is an incoming packet, so the destination is
2926 * the icmp6_id and the source port equals 0
2927 */
2928 if ((fin->fin_flx & FI_ICMPQUERY) != 0)
2929 nflags = IPN_ICMPQUERY;
2930 break;
2931 default :
2932 break;
2933 }
2934
2935 if ((nflags & IPN_TCPUDP))
2936 tcp = fin->fin_dp;
2937 }
2938
2939 ipa = fin->fin_src6;
2940
2941 READ_ENTER(&softc->ipf_nat);
2942
2943 if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
2944 (nat = ipf_nat6_icmperror(fin, &nflags, NAT_OUTBOUND)))
2945 /*EMPTY*/;
2946 else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
2947 natadd = 0;
2948 else if ((nat = ipf_nat6_outlookup(fin, nflags|NAT_SEARCH,
2949 (u_int)fin->fin_p,
2950 &fin->fin_src6.in6,
2951 &fin->fin_dst6.in6))) {
2952 nflags = nat->nat_flags;
2953 } else if (fin->fin_off == 0) {
2954 u_32_t hv, nmsk = 0;
2955 i6addr_t *msk;
2956
2957 /*
2958 * If there is no current entry in the nat table for this IP#,
2959 * create one for it (if there is a matching rule).
2960 */
2961 maskloop:
2962 msk = &softn->ipf_nat6_map_active_masks[nmsk];
2963 IP6_AND(&ipa, msk, &iph);
2964 hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_maprules_sz);
2965 for (np = softn->ipf_nat_map_rules[hv]; np; np = np->in_mnext) {
2966 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
2967 continue;
2968 if (np->in_v[0] != 6)
2969 continue;
2970 if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
2971 continue;
2972 if ((np->in_flags & IPN_RF) &&
2973 !(np->in_flags & nflags))
2974 continue;
2975 if (np->in_flags & IPN_FILTER) {
2976 switch (ipf_nat6_match(fin, np))
2977 {
2978 case 0 :
2979 continue;
2980 case -1 :
2981 rval = -1;
2982 goto outmatchfail;
2983 case 1 :
2984 default :
2985 break;
2986 }
2987 } else if (!IP6_MASKEQ(&ipa, &np->in_osrcmsk,
2988 &np->in_osrcip6))
2989 continue;
2990
2991 if ((fr != NULL) &&
2992 !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
2993 continue;
2994
2995 #ifdef IPF_V6_PROXIES
2996 if (np->in_plabel != -1) {
2997 if (((np->in_flags & IPN_FILTER) == 0) &&
2998 (np->in_odport != fin->fin_data[1]))
2999 continue;
3000 if (appr_ok(fin, tcp, np) == 0)
3001 continue;
3002 }
3003 #endif
3004
3005 if (np->in_flags & IPN_NO) {
3006 np->in_hits++;
3007 break;
3008 }
3009
3010 MUTEX_ENTER(&softn->ipf_nat_new);
3011 nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_OUTBOUND);
3012 MUTEX_EXIT(&softn->ipf_nat_new);
3013 if (nat != NULL) {
3014 np->in_hits++;
3015 break;
3016 }
3017 natfailed = -1;
3018 }
3019 if ((np == NULL) && (nmsk < softn->ipf_nat6_map_max)) {
3020 nmsk++;
3021 goto maskloop;
3022 }
3023 }
3024
3025 if (nat != NULL) {
3026 rval = ipf_nat6_out(fin, nat, natadd, nflags);
3027 if (rval == 1) {
3028 MUTEX_ENTER(&nat->nat_lock);
3029 ipf_nat_update(fin, nat);
3030 nat->nat_bytes[1] += fin->fin_plen;
3031 nat->nat_pkts[1]++;
3032 MUTEX_EXIT(&nat->nat_lock);
3033 }
3034 } else
3035 rval = natfailed;
3036 outmatchfail:
3037 RWLOCK_EXIT(&softc->ipf_nat);
3038
3039 switch (rval)
3040 {
3041 case -1 :
3042 if (passp != NULL) {
3043 NBUMPSIDE6D(1, ns_drop);
3044 *passp = FR_BLOCK;
3045 fin->fin_reason = FRB_NATV6OUT;
3046 }
3047 fin->fin_flx |= FI_BADNAT;
3048 NBUMPSIDE6D(1, ns_badnat);
3049 break;
3050 case 0 :
3051 NBUMPSIDE6D(1, ns_ignored);
3052 break;
3053 case 1 :
3054 NBUMPSIDE6D(1, ns_translated);
3055 break;
3056 }
3057 fin->fin_ifp = sifp;
3058 return rval;
3059 }
3060
3061 /* ------------------------------------------------------------------------ */
3062 /* Function: ipf_nat6_out */
3063 /* Returns: int - -1 == packet failed NAT checks so block it, */
3064 /* 1 == packet was successfully translated. */
3065 /* Parameters: fin(I) - pointer to packet information */
3066 /* nat(I) - pointer to NAT structure */
3067 /* natadd(I) - flag indicating if it is safe to add frag cache */
3068 /* nflags(I) - NAT flags set for this packet */
3069 /* */
3070 /* Translate a packet coming "out" on an interface. */
3071 /* ------------------------------------------------------------------------ */
3072 static int
3073 ipf_nat6_out(fin, nat, natadd, nflags)
3074 fr_info_t *fin;
3075 nat_t *nat;
3076 int natadd;
3077 u_32_t nflags;
3078 {
3079 ipf_main_softc_t *softc = fin->fin_main_soft;
3080 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3081 struct icmp6_hdr *icmp6;
3082 u_short *csump;
3083 tcphdr_t *tcp;
3084 ipnat_t *np;
3085 int skip;
3086 int i;
3087
3088 tcp = NULL;
3089 icmp6 = NULL;
3090 csump = NULL;
3091 np = nat->nat_ptr;
3092
3093 if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
3094 (void) ipf_frag_natnew(softc, fin, 0, nat);
3095
3096 /*
3097 * Address assignment is after the checksum modification because
3098 * we are using the address in the packet for determining the
3099 * correct checksum offset (the ICMP error could be coming from
3100 * anyone...)
3101 */
3102 switch (nat->nat_dir)
3103 {
3104 case NAT_OUTBOUND :
3105 fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
3106 fin->fin_src6 = nat->nat_nsrc6;
3107 fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
3108 fin->fin_dst6 = nat->nat_ndst6;
3109 break;
3110
3111 case NAT_INBOUND :
3112 fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
3113 fin->fin_src6 = nat->nat_ndst6;
3114 fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
3115 fin->fin_dst6 = nat->nat_nsrc6;
3116 break;
3117
3118 case NAT_ENCAPIN :
3119 fin->fin_flx |= FI_ENCAP;
3120 case NAT_DIVERTIN :
3121 {
3122 mb_t *m;
3123
3124 skip = ipf_nat6_decap(fin, nat);
3125 if (skip <= 0) {
3126 NBUMPSIDE6D(1, ns_decap_fail);
3127 return -1;
3128 }
3129
3130 m = fin->fin_m;
3131
3132 #if defined(MENTAT) && defined(_KERNEL)
3133 m->b_rptr += skip;
3134 #else
3135 m->m_data += skip;
3136 m->m_len -= skip;
3137
3138 # ifdef M_PKTHDR
3139 if (m->m_flags & M_PKTHDR)
3140 m->m_pkthdr.len -= skip;
3141 # endif
3142 #endif
3143
3144 MUTEX_ENTER(&nat->nat_lock);
3145 ipf_nat_update(fin, nat);
3146 MUTEX_EXIT(&nat->nat_lock);
3147 fin->fin_flx |= FI_NATED;
3148 if (np != NULL && np->in_tag.ipt_num[0] != 0)
3149 fin->fin_nattag = &np->in_tag;
3150 return 1;
3151 /* NOTREACHED */
3152 }
3153
3154 case NAT_ENCAPOUT :
3155 {
3156 ip6_t *ip6;
3157 mb_t *m;
3158
3159 if (ipf_nat6_encapok(fin, nat) == -1)
3160 return -1;
3161
3162 m = M_DUP(np->in_divmp);
3163 if (m == NULL) {
3164 NBUMPSIDE6D(1, ns_encap_dup);
3165 return -1;
3166 }
3167
3168 ip6 = MTOD(m, ip6_t *);
3169 /* TRACE (fin,ip) */
3170 ip6->ip6_plen = htons(fin->fin_plen + sizeof(ip6_t));
3171
3172 /* TRACE (ip) */
3173
3174 PREP_MB_T(fin, m);
3175
3176 fin->fin_ip6 = ip6;
3177 fin->fin_plen += sizeof(ip6_t); /* UDP + new IPv6 hdr */
3178 fin->fin_dlen += sizeof(ip6_t); /* UDP + old IPv6 hdr */
3179 fin->fin_flx |= FI_ENCAP;
3180
3181 nflags &= ~IPN_TCPUDPICMP;
3182
3183 break;
3184 }
3185 case NAT_DIVERTOUT :
3186 {
3187 udphdr_t *uh;
3188 ip6_t *ip6;
3189 mb_t *m;
3190
3191 m = M_DUP(np->in_divmp);
3192 if (m == NULL) {
3193 NBUMPSIDE6D(1, ns_divert_dup);
3194 return -1;
3195 }
3196
3197 ip6 = MTOD(m, ip6_t *);
3198
3199 ip6->ip6_plen = htons(fin->fin_plen + 8);
3200
3201 uh = (udphdr_t *)(ip6 + 1);
3202 uh->uh_ulen = htons(fin->fin_plen);
3203
3204 PREP_MB_T(fin, m);
3205
3206 fin->fin_ip6 = ip6;
3207 fin->fin_plen += sizeof(ip6_t) + 8; /* UDP + new IPv4 hdr */
3208 fin->fin_dlen += sizeof(ip6_t) + 8; /* UDP + old IPv4 hdr */
3209
3210 nflags &= ~IPN_TCPUDPICMP;
3211
3212 break;
3213 }
3214
3215 default :
3216 break;
3217 }
3218
3219 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
3220 if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
3221 tcp = fin->fin_dp;
3222
3223 switch (nat->nat_dir)
3224 {
3225 case NAT_OUTBOUND :
3226 tcp->th_sport = nat->nat_nsport;
3227 fin->fin_data[0] = ntohs(nat->nat_nsport);
3228 tcp->th_dport = nat->nat_ndport;
3229 fin->fin_data[0] = ntohs(nat->nat_ndport);
3230 break;
3231
3232 case NAT_INBOUND :
3233 tcp->th_sport = nat->nat_odport;
3234 fin->fin_data[0] = ntohs(nat->nat_odport);
3235 tcp->th_dport = nat->nat_osport;
3236 fin->fin_data[0] = ntohs(nat->nat_osport);
3237 break;
3238 }
3239 }
3240
3241 if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
3242 icmp6 = fin->fin_dp;
3243 icmp6->icmp6_id = nat->nat_nicmpid;
3244 }
3245
3246 csump = ipf_nat_proto(fin, nat, nflags);
3247 }
3248
3249 /*
3250 * The above comments do not hold for layer 4 (or higher) checksums...
3251 */
3252 if (csump != NULL) {
3253 if (nat->nat_dir == NAT_OUTBOUND)
3254 ipf_fix_outcksum(fin, csump, nat->nat_sumd[1]);
3255 else
3256 ipf_fix_incksum(fin, csump, nat->nat_sumd[1]);
3257 }
3258 ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
3259 /* ------------------------------------------------------------- */
3260 /* A few quick notes: */
3261 /* Following are test conditions prior to calling the */
3262 /* appr_check routine. */
3263 /* */
3264 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
3265 /* with a redirect rule, we attempt to match the packet's */
3266 /* source port against in_dport, otherwise we'd compare the */
3267 /* packet's destination. */
3268 /* ------------------------------------------------------------- */
3269 if ((np != NULL) && (np->in_apr != NULL)) {
3270 #ifdef IPF_V6_PROXIES
3271 i = appr_check(fin, nat);
3272 if (i == 0)
3273 i = 1;
3274 else if (i == -1) {
3275 NBUMPSIDE6D(1, ns_appr_fail);
3276 }
3277 #else
3278 i = 1;
3279 #endif
3280 } else {
3281 i = 1;
3282 }
3283 fin->fin_flx |= FI_NATED;
3284 return i;
3285 }
3286
3287
3288 /* ------------------------------------------------------------------------ */
3289 /* Function: ipf_nat6_ipfin */
3290 /* Returns: frentry_t* - NULL (packet may have been translated, let it */
3291 /* pass), &ipfnatblock - block/drop the packet. */
3292 /* Parameters: fin(I) - pointer to packet information */
3293 /* passp(I) - point to filtering result flags */
3294 /* */
3295 /* This is purely and simply a wrapper around ipf_nat6_checkin for the sole */
3296 /* reason of being able to activate NAT from an ipf rule using "call-now". */
3297 /* ------------------------------------------------------------------------ */
3298 frentry_t *
3299 ipf_nat6_ipfin(fin, passp)
3300 fr_info_t *fin;
3301 u_32_t *passp;
3302 {
3303 frentry_t *fr = fin->fin_fr;
3304
3305 switch (ipf_nat6_checkin(fin, passp))
3306 {
3307 case -1 :
3308 fr = &ipfnatblock;
3309 MUTEX_ENTER(&fr->fr_lock);
3310 fr->fr_ref++;
3311 MUTEX_EXIT(&fr->fr_lock);
3312 return fr;
3313
3314 case 0 :
3315 return NULL;
3316
3317 case 1 :
3318 /*
3319 * Returing NULL causes this rule to be "ignored" but
3320 * it has actually had an influence on the packet so we
3321 * increment counters for it.
3322 */
3323 MUTEX_ENTER(&fr->fr_lock);
3324 fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
3325 fr->fr_hits++;
3326 MUTEX_EXIT(&fr->fr_lock);
3327 return NULL;
3328 }
3329
3330 return NULL;
3331 }
3332
3333
3334 /* ------------------------------------------------------------------------ */
3335 /* Function: ipf_nat6_checkin */
3336 /* Returns: int - -1 == packet failed NAT checks so block it, */
3337 /* 0 == no packet translation occurred, */
3338 /* 1 == packet was successfully translated. */
3339 /* Parameters: fin(I) - pointer to packet information */
3340 /* passp(I) - pointer to filtering result flags */
3341 /* */
3342 /* Check to see if an incoming packet should be changed. ICMP packets are */
3343 /* first checked to see if they match an existing entry (if an error), */
3344 /* otherwise a search of the current NAT table is made. If neither results */
3345 /* in a match then a search for a matching NAT rule is made. Create a new */
3346 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */
3347 /* packet header(s) as required. */
3348 /* ------------------------------------------------------------------------ */
3349 int
3350 ipf_nat6_checkin(fin, passp)
3351 fr_info_t *fin;
3352 u_32_t *passp;
3353 {
3354 ipf_main_softc_t *softc = fin->fin_main_soft;
3355 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3356 struct icmp6_hdr *icmp6;
3357 u_int nflags, natadd;
3358 int rval, natfailed;
3359 struct ifnet *ifp;
3360 i6addr_t ipa, iph;
3361 tcphdr_t *tcp;
3362 u_short dport;
3363 ipnat_t *np;
3364 nat_t *nat;
3365
3366 if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
3367 return 0;
3368
3369 tcp = NULL;
3370 icmp6 = NULL;
3371 dport = 0;
3372 natadd = 1;
3373 nflags = 0;
3374 natfailed = 0;
3375 ifp = fin->fin_ifp;
3376
3377 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
3378 switch (fin->fin_p)
3379 {
3380 case IPPROTO_TCP :
3381 nflags = IPN_TCP;
3382 break;
3383 case IPPROTO_UDP :
3384 nflags = IPN_UDP;
3385 break;
3386 case IPPROTO_ICMPV6 :
3387 icmp6 = fin->fin_dp;
3388
3389 /*
3390 * This is an incoming packet, so the destination is
3391 * the icmp6_id and the source port equals 0
3392 */
3393 if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
3394 nflags = IPN_ICMPQUERY;
3395 dport = icmp6->icmp6_id;
3396 } break;
3397 default :
3398 break;
3399 }
3400
3401 if ((nflags & IPN_TCPUDP)) {
3402 tcp = fin->fin_dp;
3403 dport = fin->fin_data[1];
3404 }
3405 }
3406
3407 ipa = fin->fin_dst6;
3408
3409 READ_ENTER(&softc->ipf_nat);
3410
3411 if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
3412 (nat = ipf_nat6_icmperror(fin, &nflags, NAT_INBOUND)))
3413 /*EMPTY*/;
3414 else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
3415 natadd = 0;
3416 else if ((nat = ipf_nat6_inlookup(fin, nflags|NAT_SEARCH,
3417 (u_int)fin->fin_p,
3418 &fin->fin_src6.in6, &ipa.in6))) {
3419 nflags = nat->nat_flags;
3420 } else if (fin->fin_off == 0) {
3421 u_32_t hv, rmsk = 0;
3422 i6addr_t *msk;
3423
3424 /*
3425 * If there is no current entry in the nat table for this IP#,
3426 * create one for it (if there is a matching rule).
3427 */
3428 maskloop:
3429 msk = &softn->ipf_nat6_rdr_active_masks[rmsk];
3430 IP6_AND(&ipa, msk, &iph);
3431 hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_rdrrules_sz);
3432 for (np = softn->ipf_nat_rdr_rules[hv]; np; np = np->in_rnext) {
3433 if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
3434 continue;
3435 if (np->in_v[0] != 6)
3436 continue;
3437 if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
3438 continue;
3439 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
3440 continue;
3441 if (np->in_flags & IPN_FILTER) {
3442 switch (ipf_nat6_match(fin, np))
3443 {
3444 case 0 :
3445 continue;
3446 case -1 :
3447 rval = -1;
3448 goto inmatchfail;
3449 case 1 :
3450 default :
3451 break;
3452 }
3453 } else {
3454 if (!IP6_MASKEQ(&ipa, &np->in_odstmsk6,
3455 &np->in_odstip6)) {
3456 continue;
3457 }
3458 if (np->in_odport &&
3459 ((np->in_dtop < dport) ||
3460 (dport < np->in_odport)))
3461 continue;
3462 }
3463
3464 #ifdef IPF_V6_PROXIES
3465 if (np->in_plabel != -1) {
3466 if (!appr_ok(fin, tcp, np)) {
3467 continue;
3468 }
3469 }
3470 #endif
3471
3472 if (np->in_flags & IPN_NO) {
3473 np->in_hits++;
3474 break;
3475 }
3476
3477 MUTEX_ENTER(&softn->ipf_nat_new);
3478 nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_INBOUND);
3479 MUTEX_EXIT(&softn->ipf_nat_new);
3480 if (nat != NULL) {
3481 np->in_hits++;
3482 break;
3483 }
3484 natfailed = -1;
3485 }
3486
3487 if ((np == NULL) && (rmsk < softn->ipf_nat6_rdr_max)) {
3488 rmsk++;
3489 goto maskloop;
3490 }
3491 }
3492 if (nat != NULL) {
3493 rval = ipf_nat6_in(fin, nat, natadd, nflags);
3494 if (rval == 1) {
3495 MUTEX_ENTER(&nat->nat_lock);
3496 ipf_nat_update(fin, nat);
3497 nat->nat_bytes[0] += fin->fin_plen;
3498 nat->nat_pkts[0]++;
3499 MUTEX_EXIT(&nat->nat_lock);
3500 }
3501 } else
3502 rval = natfailed;
3503 inmatchfail:
3504 RWLOCK_EXIT(&softc->ipf_nat);
3505
3506 switch (rval)
3507 {
3508 case -1 :
3509 if (passp != NULL) {
3510 NBUMPSIDE6D(0, ns_drop);
3511 *passp = FR_BLOCK;
3512 fin->fin_reason = FRB_NATV6IN;
3513 }
3514 fin->fin_flx |= FI_BADNAT;
3515 NBUMPSIDE6D(0, ns_badnat);
3516 break;
3517 case 0 :
3518 NBUMPSIDE6D(0, ns_ignored);
3519 break;
3520 case 1 :
3521 NBUMPSIDE6D(0, ns_translated);
3522 break;
3523 }
3524 return rval;
3525 }
3526
3527
3528 /* ------------------------------------------------------------------------ */
3529 /* Function: ipf_nat6_in */
3530 /* Returns: int - -1 == packet failed NAT checks so block it, */
3531 /* 1 == packet was successfully translated. */
3532 /* Parameters: fin(I) - pointer to packet information */
3533 /* nat(I) - pointer to NAT structure */
3534 /* natadd(I) - flag indicating if it is safe to add frag cache */
3535 /* nflags(I) - NAT flags set for this packet */
3536 /* Locks Held: (READ) */
3537 /* */
3538 /* Translate a packet coming "in" on an interface. */
3539 /* ------------------------------------------------------------------------ */
3540 static int
3541 ipf_nat6_in(fin, nat, natadd, nflags)
3542 fr_info_t *fin;
3543 nat_t *nat;
3544 int natadd;
3545 u_32_t nflags;
3546 {
3547 ipf_main_softc_t *softc = fin->fin_main_soft;
3548 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3549 struct icmp6_hdr *icmp6;
3550 u_short *csump;
3551 tcphdr_t *tcp;
3552 ipnat_t *np;
3553 int skip;
3554
3555 tcp = NULL;
3556 csump = NULL;
3557 np = nat->nat_ptr;
3558 fin->fin_fr = nat->nat_fr;
3559
3560 if (np != NULL) {
3561 if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
3562 (void) ipf_frag_natnew(softc, fin, 0, nat);
3563
3564 /* ------------------------------------------------------------- */
3565 /* A few quick notes: */
3566 /* Following are test conditions prior to calling the */
3567 /* appr_check routine. */
3568 /* */
3569 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
3570 /* with a map rule, we attempt to match the packet's */
3571 /* source port against in_dport, otherwise we'd compare the */
3572 /* packet's destination. */
3573 /* ------------------------------------------------------------- */
3574 if (np->in_apr != NULL) {
3575 #ifdef IPF_V6_PROXIES
3576 i = appr_check(fin, nat);
3577 if (i == -1) {
3578 NBUMPSIDE6D(0, ns_appr_fail);
3579 return -1;
3580 }
3581 #endif
3582 }
3583 }
3584
3585 ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
3586
3587 /*
3588 * Fix up checksums, not by recalculating them, but
3589 * simply computing adjustments.
3590 * Why only do this for some platforms on inbound packets ?
3591 * Because for those that it is done, IP processing is yet to happen
3592 * and so the IPv4 header checksum has not yet been evaluated.
3593 * Perhaps it should always be done for the benefit of things like
3594 * fast forwarding (so that it doesn't need to be recomputed) but with
3595 * header checksum offloading, perhaps it is a moot point.
3596 */
3597
3598 switch (nat->nat_dir)
3599 {
3600 case NAT_INBOUND :
3601 if ((fin->fin_flx & FI_ICMPERR) == 0) {
3602 fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
3603 fin->fin_src6 = nat->nat_nsrc6;
3604 }
3605 fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
3606 fin->fin_dst6 = nat->nat_ndst6;
3607 break;
3608
3609 case NAT_OUTBOUND :
3610 if ((fin->fin_flx & FI_ICMPERR) == 0) {
3611 fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
3612 fin->fin_src6 = nat->nat_odst6;
3613 }
3614 fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
3615 fin->fin_dst6 = nat->nat_osrc6;
3616 break;
3617
3618 case NAT_ENCAPIN :
3619 {
3620 ip6_t *ip6;
3621 mb_t *m;
3622
3623 /*
3624 * XXX
3625 * This is not necessarily true. What we need to know here
3626 * is the MTU of the interface out which the packets will go
3627 * and this won't be nat6_ifps[1] because that is where we
3628 * send packets after stripping off stuff - what's needed
3629 * here is the MTU of the interface for the route to the
3630 * destination of the outer header.
3631 */
3632 if (ipf_nat6_encapok(fin, nat) == -1)
3633 return -1;
3634
3635 m = M_DUP(np->in_divmp);
3636 if (m == NULL) {
3637 NBUMPSIDE6D(0, ns_encap_dup);
3638 return -1;
3639 }
3640
3641 ip6 = MTOD(m, ip6_t *);
3642 ip6->ip6_plen = htons(fin->fin_plen + 8);
3643
3644 PREP_MB_T(fin, m);
3645
3646 fin->fin_ip6 = ip6;
3647 fin->fin_plen += sizeof(ip6_t) + 8; /* UDP + new IPv6 hdr */
3648 fin->fin_dlen += sizeof(ip6_t) + 8; /* UDP + old IPv6 hdr */
3649 fin->fin_flx |= FI_ENCAP;
3650
3651 nflags &= ~IPN_TCPUDPICMP;
3652
3653 break;
3654 }
3655
3656 case NAT_DIVERTIN :
3657 {
3658 udphdr_t *uh;
3659 ip6_t *ip6;
3660 mb_t *m;
3661
3662 m = M_DUP(np->in_divmp);
3663 if (m == NULL) {
3664 NBUMPSIDE6D(0, ns_divert_dup);
3665 return -1;
3666 }
3667
3668 ip6 = MTOD(m, ip6_t *);
3669 ip6->ip6_plen = htons(fin->fin_plen + sizeof(udphdr_t));
3670
3671 uh = (udphdr_t *)(ip6 + 1);
3672 uh->uh_ulen = ntohs(fin->fin_plen);
3673
3674 PREP_MB_T(fin, m);
3675
3676 fin->fin_ip6 = ip6;
3677 fin->fin_plen += sizeof(ip6_t) + 8; /* UDP + new IPv6 hdr */
3678 fin->fin_dlen += sizeof(ip6_t) + 8; /* UDP + old IPv6 hdr */
3679
3680 nflags &= ~IPN_TCPUDPICMP;
3681
3682 break;
3683 }
3684
3685 case NAT_ENCAPOUT :
3686 fin->fin_flx |= FI_ENCAP;
3687 case NAT_DIVERTOUT :
3688 {
3689 mb_t *m;
3690
3691 skip = ipf_nat6_decap(fin, nat);
3692 if (skip <= 0) {
3693 NBUMPSIDE6D(0, ns_decap_fail);
3694 return -1;
3695 }
3696
3697 m = fin->fin_m;
3698
3699 #if defined(MENTAT) && defined(_KERNEL)
3700 m->b_rptr += skip;
3701 #else
3702 m->m_data += skip;
3703 m->m_len -= skip;
3704
3705 # ifdef M_PKTHDR
3706 if (m->m_flags & M_PKTHDR)
3707 m->m_pkthdr.len -= skip;
3708 # endif
3709 #endif
3710
3711 ipf_nat_update(fin, nat);
3712 fin->fin_flx |= FI_NATED;
3713 if (np != NULL && np->in_tag.ipt_num[0] != 0)
3714 fin->fin_nattag = &np->in_tag;
3715 return 1;
3716 /* NOTREACHED */
3717 }
3718 }
3719 if (nflags & IPN_TCPUDP)
3720 tcp = fin->fin_dp;
3721
3722 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
3723 if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
3724 switch (nat->nat_dir)
3725 {
3726 case NAT_INBOUND :
3727 tcp->th_sport = nat->nat_nsport;
3728 fin->fin_data[0] = ntohs(nat->nat_nsport);
3729 tcp->th_dport = nat->nat_ndport;
3730 fin->fin_data[1] = ntohs(nat->nat_ndport);
3731 break;
3732
3733 case NAT_OUTBOUND :
3734 tcp->th_sport = nat->nat_odport;
3735 fin->fin_data[0] = ntohs(nat->nat_odport);
3736 tcp->th_dport = nat->nat_osport;
3737 fin->fin_data[1] = ntohs(nat->nat_osport);
3738 break;
3739 }
3740 }
3741
3742
3743 if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
3744 icmp6 = fin->fin_dp;
3745
3746 icmp6->icmp6_id = nat->nat_nicmpid;
3747 }
3748
3749 csump = ipf_nat_proto(fin, nat, nflags);
3750 }
3751
3752 /*
3753 * The above comments do not hold for layer 4 (or higher) checksums...
3754 */
3755 if (csump != NULL) {
3756 if (nat->nat_dir == NAT_OUTBOUND)
3757 ipf_fix_incksum(fin, csump, nat->nat_sumd[0]);
3758 else
3759 ipf_fix_outcksum(fin, csump, nat->nat_sumd[0]);
3760 }
3761 fin->fin_flx |= FI_NATED;
3762 if (np != NULL && np->in_tag.ipt_num[0] != 0)
3763 fin->fin_nattag = &np->in_tag;
3764 return 1;
3765 }
3766
3767
3768 /* ------------------------------------------------------------------------ */
3769 /* Function: ipf_nat6_newrewrite */
3770 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
3771 /* allow rule to be moved if IPN_ROUNDR is set. */
3772 /* Parameters: fin(I) - pointer to packet information */
3773 /* nat(I) - pointer to NAT entry */
3774 /* ni(I) - pointer to structure with misc. information needed */
3775 /* to create new NAT entry. */
3776 /* Write Lock: ipf_nat */
3777 /* */
3778 /* This function is responsible for setting up an active NAT session where */
3779 /* we are changing both the source and destination parameters at the same */
3780 /* time. The loop in here works differently to elsewhere - each iteration */
3781 /* is responsible for changing a single parameter that can be incremented. */
3782 /* So one pass may increase the source IP#, next source port, next dest. IP#*/
3783 /* and the last destination port for a total of 4 iterations to try each. */
3784 /* This is done to try and exhaustively use the translation space available.*/
3785 /* ------------------------------------------------------------------------ */
3786 int
3787 ipf_nat6_newrewrite(fin, nat, nai)
3788 fr_info_t *fin;
3789 nat_t *nat;
3790 natinfo_t *nai;
3791 {
3792 int src_search = 1;
3793 int dst_search = 1;
3794 fr_info_t frnat;
3795 u_32_t flags;
3796 u_short swap;
3797 ipnat_t *np;
3798 nat_t *natl;
3799 int l = 0;
3800 int changed;
3801
3802 natl = NULL;
3803 changed = -1;
3804 np = nai->nai_np;
3805 flags = nat->nat_flags;
3806 bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
3807
3808 nat->nat_hm = NULL;
3809
3810 do {
3811 changed = -1;
3812 /* TRACE (l, src_search, dst_search, np) */
3813
3814 if ((src_search == 0) && (np->in_spnext == 0) &&
3815 (dst_search == 0) && (np->in_dpnext == 0)) {
3816 if (l > 0)
3817 return -1;
3818 }
3819
3820 /*
3821 * Find a new source address
3822 */
3823 if (ipf_nat6_nextaddr(fin, &np->in_nsrc, &frnat.fin_src6,
3824 &frnat.fin_src6) == -1) {
3825 return -1;
3826 }
3827
3828 if (IP6_ISZERO(&np->in_nsrcip6) &&
3829 IP6_ISONES(&np->in_nsrcmsk6)) {
3830 src_search = 0;
3831 if (np->in_stepnext == 0)
3832 np->in_stepnext = 1;
3833
3834 } else if (IP6_ISZERO(&np->in_nsrcip6) &&
3835 IP6_ISZERO(&np->in_nsrcmsk6)) {
3836 src_search = 0;
3837 if (np->in_stepnext == 0)
3838 np->in_stepnext = 1;
3839
3840 } else if (IP6_ISONES(&np->in_nsrcmsk)) {
3841 src_search = 0;
3842 if (np->in_stepnext == 0)
3843 np->in_stepnext = 1;
3844
3845 } else if (!IP6_ISONES(&np->in_nsrcmsk6)) {
3846 if (np->in_stepnext == 0 && changed == -1) {
3847 IP6_INC(&np->in_snip);
3848 np->in_stepnext++;
3849 changed = 0;
3850 }
3851 }
3852
3853 if ((flags & IPN_TCPUDPICMP) != 0) {
3854 if (np->in_spnext != 0)
3855 frnat.fin_data[0] = np->in_spnext;
3856
3857 /*
3858 * Standard port translation. Select next port.
3859 */
3860 if ((flags & IPN_FIXEDSPORT) != 0) {
3861 np->in_stepnext = 2;
3862 } else if ((np->in_stepnext == 1) &&
3863 (changed == -1) && (natl != NULL)) {
3864 np->in_spnext++;
3865 np->in_stepnext++;
3866 changed = 1;
3867 if (np->in_spnext > np->in_spmax)
3868 np->in_spnext = np->in_spmin;
3869 }
3870 } else {
3871 np->in_stepnext = 2;
3872 }
3873 np->in_stepnext &= 0x3;
3874
3875 /*
3876 * Find a new destination address
3877 */
3878 /* TRACE (fin, np, l, frnat) */
3879
3880 if (ipf_nat6_nextaddr(fin, &np->in_ndst, &frnat.fin_dst6,
3881 &frnat.fin_dst6) == -1)
3882 return -1;
3883
3884 if (IP6_ISZERO(&np->in_ndstip6) &&
3885 IP6_ISONES(&np->in_ndstmsk6)) {
3886 dst_search = 0;
3887 if (np->in_stepnext == 2)
3888 np->in_stepnext = 3;
3889
3890 } else if (IP6_ISZERO(&np->in_ndstip6) &&
3891 IP6_ISZERO(&np->in_ndstmsk6)) {
3892 dst_search = 0;
3893 if (np->in_stepnext == 2)
3894 np->in_stepnext = 3;
3895
3896 } else if (IP6_ISONES(&np->in_ndstmsk6)) {
3897 dst_search = 0;
3898 if (np->in_stepnext == 2)
3899 np->in_stepnext = 3;
3900
3901 } else if (!IP6_ISONES(&np->in_ndstmsk6)) {
3902 if ((np->in_stepnext == 2) && (changed == -1) &&
3903 (natl != NULL)) {
3904 changed = 2;
3905 np->in_stepnext++;
3906 IP6_INC(&np->in_dnip6);
3907 }
3908 }
3909
3910 if ((flags & IPN_TCPUDPICMP) != 0) {
3911 if (np->in_dpnext != 0)
3912 frnat.fin_data[1] = np->in_dpnext;
3913
3914 /*
3915 * Standard port translation. Select next port.
3916 */
3917 if ((flags & IPN_FIXEDDPORT) != 0) {
3918 np->in_stepnext = 0;
3919 } else if (np->in_stepnext == 3 && changed == -1) {
3920 np->in_dpnext++;
3921 np->in_stepnext++;
3922 changed = 3;
3923 if (np->in_dpnext > np->in_dpmax)
3924 np->in_dpnext = np->in_dpmin;
3925 }
3926 } else {
3927 if (np->in_stepnext == 3)
3928 np->in_stepnext = 0;
3929 }
3930
3931 /* TRACE (frnat) */
3932
3933 /*
3934 * Here we do a lookup of the connection as seen from
3935 * the outside. If an IP# pair already exists, try
3936 * again. So if you have A->B becomes C->B, you can
3937 * also have D->E become C->E but not D->B causing
3938 * another C->B. Also take protocol and ports into
3939 * account when determining whether a pre-existing
3940 * NAT setup will cause an external conflict where
3941 * this is appropriate.
3942 *
3943 * fin_data[] is swapped around because we are doing a
3944 * lookup of the packet is if it were moving in the opposite
3945 * direction of the one we are working with now.
3946 */
3947 if (flags & IPN_TCPUDP) {
3948 swap = frnat.fin_data[0];
3949 frnat.fin_data[0] = frnat.fin_data[1];
3950 frnat.fin_data[1] = swap;
3951 }
3952 if (fin->fin_out == 1) {
3953 natl = ipf_nat6_inlookup(&frnat,
3954 flags & ~(SI_WILDP|NAT_SEARCH),
3955 (u_int)frnat.fin_p,
3956 &frnat.fin_dst6.in6,
3957 &frnat.fin_src6.in6);
3958
3959 } else {
3960 natl = ipf_nat6_outlookup(&frnat,
3961 flags & ~(SI_WILDP|NAT_SEARCH),
3962 (u_int)frnat.fin_p,
3963 &frnat.fin_dst6.in6,
3964 &frnat.fin_src6.in6);
3965 }
3966 if (flags & IPN_TCPUDP) {
3967 swap = frnat.fin_data[0];
3968 frnat.fin_data[0] = frnat.fin_data[1];
3969 frnat.fin_data[1] = swap;
3970 }
3971
3972 /* TRACE natl, in_stepnext, l */
3973
3974 if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */
3975 return -1;
3976
3977 np->in_stepnext &= 0x3;
3978
3979 l++;
3980 changed = -1;
3981 } while (natl != NULL);
3982 nat->nat_osrc6 = fin->fin_src6;
3983 nat->nat_odst6 = fin->fin_dst6;
3984 nat->nat_nsrc6 = frnat.fin_src6;
3985 nat->nat_ndst6 = frnat.fin_dst6;
3986
3987 if ((flags & IPN_TCPUDPICMP) != 0) {
3988 nat->nat_osport = htons(fin->fin_data[0]);
3989 nat->nat_odport = htons(fin->fin_data[1]);
3990 nat->nat_nsport = htons(frnat.fin_data[0]);
3991 nat->nat_ndport = htons(frnat.fin_data[1]);
3992 }
3993
3994 return 0;
3995 }
3996
3997
3998 /* ------------------------------------------------------------------------ */
3999 /* Function: ipf_nat6_newdivert */
4000 /* Returns: int - -1 == error, 0 == success */
4001 /* Parameters: fin(I) - pointer to packet information */
4002 /* nat(I) - pointer to NAT entry */
4003 /* ni(I) - pointer to structure with misc. information needed */
4004 /* to create new NAT entry. */
4005 /* Write Lock: ipf_nat */
4006 /* */
4007 /* Create a new NAT encap/divert session as defined by the NAT rule. This */
4008 /* is somewhat different to other NAT session creation routines because we */
4009 /* do not iterate through either port numbers or IP addresses, searching */
4010 /* for a unique mapping, however, a complimentary duplicate check is made. */
4011 /* ------------------------------------------------------------------------ */
4012 int
4013 ipf_nat6_newdivert(fin, nat, nai)
4014 fr_info_t *fin;
4015 nat_t *nat;
4016 natinfo_t *nai;
4017 {
4018 ipf_main_softc_t *softc = fin->fin_main_soft;
4019 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4020 fr_info_t frnat;
4021 ipnat_t *np;
4022 nat_t *natl;
4023 int p;
4024
4025 np = nai->nai_np;
4026 bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
4027
4028 nat->nat_pr[0] = 0;
4029 nat->nat_osrc6 = fin->fin_src6;
4030 nat->nat_odst6 = fin->fin_dst6;
4031 nat->nat_osport = htons(fin->fin_data[0]);
4032 nat->nat_odport = htons(fin->fin_data[1]);
4033 frnat.fin_src6 = np->in_snip6;
4034 frnat.fin_dst6 = np->in_dnip6;
4035
4036 if (np->in_redir & NAT_DIVERTUDP) {
4037 frnat.fin_data[0] = np->in_spnext;
4038 frnat.fin_data[1] = np->in_dpnext;
4039 frnat.fin_flx |= FI_TCPUDP;
4040 p = IPPROTO_UDP;
4041 } else {
4042 frnat.fin_flx &= ~FI_TCPUDP;
4043 p = IPPROTO_IPIP;
4044 }
4045
4046 if (fin->fin_out == 1) {
4047 natl = ipf_nat6_inlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
4048 &frnat.fin_src6.in6);
4049
4050 } else {
4051 natl = ipf_nat6_outlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
4052 &frnat.fin_src6.in6);
4053 }
4054
4055 if (natl != NULL) {
4056 NBUMPSIDE6D(fin->fin_out, ns_divert_exist);
4057 return -1;
4058 }
4059
4060 nat->nat_nsrc6 = frnat.fin_src6;
4061 nat->nat_ndst6 = frnat.fin_dst6;
4062 if (np->in_redir & NAT_DIVERTUDP) {
4063 nat->nat_nsport = htons(frnat.fin_data[0]);
4064 nat->nat_ndport = htons(frnat.fin_data[1]);
4065 }
4066 nat->nat_pr[fin->fin_out] = fin->fin_p;
4067 nat->nat_pr[1 - fin->fin_out] = p;
4068
4069 if (np->in_redir & NAT_ENCAP) {
4070 if (np->in_redir & NAT_REDIRECT)
4071 nat->nat_dir = NAT_ENCAPIN;
4072 else
4073 nat->nat_dir = NAT_ENCAPOUT;
4074 } else {
4075 if (np->in_redir & NAT_REDIRECT)
4076 nat->nat_dir = NAT_DIVERTIN;
4077 else
4078 nat->nat_dir = NAT_DIVERTOUT;
4079 }
4080
4081 return 0;
4082 }
4083
4084
4085 /* ------------------------------------------------------------------------ */
4086 /* Function: nat6_builddivertmp */
4087 /* Returns: int - -1 == error, 0 == success */
4088 /* Parameters: np(I) - pointer to a NAT rule */
4089 /* */
4090 /* For encap/divert rules, a skeleton packet representing what will be */
4091 /* prepended to the real packet is created. Even though we don't have the */
4092 /* full packet here, a checksum is calculated that we update later when we */
4093 /* fill in the final details. At present a 0 checksum for UDP is being set */
4094 /* here because it is expected that divert will be used for localhost. */
4095 /* ------------------------------------------------------------------------ */
4096 static int
4097 ipf_nat6_builddivertmp(softn, np)
4098 ipf_nat_softc_t *softn;
4099 ipnat_t *np;
4100 {
4101 udphdr_t *uh;
4102 size_t len;
4103 ip6_t *ip6;
4104
4105 if ((np->in_redir & NAT_DIVERTUDP) != 0)
4106 len = sizeof(ip6_t) + sizeof(udphdr_t);
4107 else
4108 len = sizeof(ip6_t);
4109
4110 ALLOC_MB_T(np->in_divmp, len);
4111 if (np->in_divmp == NULL) {
4112 ATOMIC_INCL(softn->ipf_nat_stats.ns_divert_build);
4113 return -1;
4114 }
4115
4116 /*
4117 * First, the header to get the packet diverted to the new destination
4118 */
4119 ip6 = MTOD(np->in_divmp, ip6_t *);
4120 ip6->ip6_vfc = 0x60;
4121 if ((np->in_redir & NAT_DIVERTUDP) != 0)
4122 ip6->ip6_nxt = IPPROTO_UDP;
4123 else
4124 ip6->ip6_nxt = IPPROTO_IPIP;
4125 ip6->ip6_hlim = 255;
4126 ip6->ip6_plen = 0;
4127 ip6->ip6_src = np->in_snip6.in6;
4128 ip6->ip6_dst = np->in_dnip6.in6;
4129
4130 if (np->in_redir & NAT_DIVERTUDP) {
4131 uh = (udphdr_t *)((u_char *)ip6 + sizeof(*ip6));
4132 uh->uh_sum = 0;
4133 uh->uh_ulen = 8;
4134 uh->uh_sport = htons(np->in_spnext);
4135 uh->uh_dport = htons(np->in_dpnext);
4136 }
4137
4138 return 0;
4139 }
4140
4141
4142 #define MINDECAP (sizeof(ip6_t) + sizeof(udphdr_t) + sizeof(ip6_t))
4143
4144 /* ------------------------------------------------------------------------ */
4145 /* Function: nat6_decap */
4146 /* Returns: int - -1 == error, 0 == success */
4147 /* Parameters: fin(I) - pointer to packet information */
4148 /* nat(I) - pointer to current NAT session */
4149 /* */
4150 /* This function is responsible for undoing a packet's encapsulation in the */
4151 /* reverse of an encap/divert rule. After removing the outer encapsulation */
4152 /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
4153 /* match the "new" packet as it may still be used by IPFilter elsewhere. */
4154 /* We use "dir" here as the basis for some of the expectations about the */
4155 /* outer header. If we return an error, the goal is to leave the original */
4156 /* packet information undisturbed - this falls short at the end where we'd */
4157 /* need to back a backup copy of "fin" - expensive. */
4158 /* ------------------------------------------------------------------------ */
4159 static int
4160 ipf_nat6_decap(fin, nat)
4161 fr_info_t *fin;
4162 nat_t *nat;
4163 {
4164 ipf_main_softc_t *softc = fin->fin_main_soft;
4165 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4166 char *hdr;
4167 int skip;
4168 mb_t *m;
4169
4170 if ((fin->fin_flx & FI_ICMPERR) != 0) {
4171 return 0;
4172 }
4173
4174 m = fin->fin_m;
4175 skip = fin->fin_hlen;
4176
4177 switch (nat->nat_dir)
4178 {
4179 case NAT_DIVERTIN :
4180 case NAT_DIVERTOUT :
4181 if (fin->fin_plen < MINDECAP)
4182 return -1;
4183 skip += sizeof(udphdr_t);
4184 break;
4185
4186 case NAT_ENCAPIN :
4187 case NAT_ENCAPOUT :
4188 if (fin->fin_plen < (skip + sizeof(ip6_t)))
4189 return -1;
4190 break;
4191 default :
4192 return -1;
4193 /* NOTREACHED */
4194 }
4195
4196 /*
4197 * The aim here is to keep the original packet details in "fin" for
4198 * as long as possible so that returning with an error is for the
4199 * original packet and there is little undoing work to do.
4200 */
4201 if (M_LEN(m) < skip + sizeof(ip6_t)) {
4202 if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1)
4203 return -1;
4204 }
4205
4206 hdr = MTOD(fin->fin_m, char *);
4207 fin->fin_ip6 = (ip6_t *)(hdr + skip);
4208
4209 if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1) {
4210 NBUMPSIDE6D(fin->fin_out, ns_decap_pullup);
4211 return -1;
4212 }
4213
4214 fin->fin_hlen = sizeof(ip6_t);
4215 fin->fin_dlen -= skip;
4216 fin->fin_plen -= skip;
4217 fin->fin_ipoff += skip;
4218
4219 if (ipf_makefrip(sizeof(ip6_t), (ip_t *)hdr, fin) == -1) {
4220 NBUMPSIDE6D(fin->fin_out, ns_decap_bad);
4221 return -1;
4222 }
4223
4224 return skip;
4225 }
4226
4227
4228 /* ------------------------------------------------------------------------ */
4229 /* Function: nat6_matchencap */
4230 /* Returns: int - -1 == packet error, 1 == success, 0 = no match */
4231 /* Parameters: fin(I) - pointer to packet information */
4232 /* np(I) - pointer to a NAT rule */
4233 /* */
4234 /* To properly compare a packet travelling in the reverse direction to an */
4235 /* encap rule, it needs to be pseudo-decapsulated so we can check if a */
4236 /* reply to it would be encapsulated. In doing this, we have to be careful */
4237 /* so as not to actually do any decapsulation nor affect any of the current */
4238 /* stored parameters in "fin" so that we can continue processing it else- */
4239 /* where if it doesn't match. */
4240 /* ------------------------------------------------------------------------ */
4241 static int
4242 ipf_nat6_matchencap(fin, np)
4243 fr_info_t *fin;
4244 ipnat_t *np;
4245 {
4246 ipf_main_softc_t *softc = fin->fin_main_soft;
4247 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4248 int match, skip;
4249 u_short *ports;
4250 frtuc_t *ft;
4251 fr_ip_t fi;
4252 ip6_t *ip6;
4253 char *hdr;
4254 mb_t *m;
4255
4256 /*
4257 * This function is only for matching packets that are appearing from
4258 * the reverse direction against "encap" rules.
4259 */
4260 if (fin->fin_out == 1) {
4261 if ((np->in_redir & NAT_REDIRECT) == 0)
4262 return 0;
4263 } else {
4264 if ((np->in_redir & NAT_MAP) == 0)
4265 return 0;
4266 }
4267 if (np->in_pr[fin->fin_out] != fin->fin_p)
4268 return 0;
4269
4270 /*
4271 * The aim here is to keep the original packet details in "fin" for
4272 * as long as possible so that returning with an error is for the
4273 * original packet and there is little undoing work to do.
4274 */
4275 m = fin->fin_m;
4276 skip = fin->fin_hlen;
4277 if (M_LEN(m) < skip + sizeof(ip6_t)) {
4278 if (ipf_pr_pullup(fin, sizeof(ip6_t)) == -1) {
4279 NBUMPSIDE6D(fin->fin_out, ns_encap_pullup);
4280 return -1;
4281 }
4282 }
4283
4284 hdr = MTOD(fin->fin_m, char *);
4285 ip6 = (ip6_t *)(hdr + skip);
4286
4287 match = 1;
4288
4289 /*
4290 * Now we should have the entire innder header, so match up the
4291 * address fields - easy enough. Reverse matching of source and
4292 * destination because this is purportedly a "reply" to an encap rule.
4293 */
4294 switch (np->in_osrcatype)
4295 {
4296 case FRI_NORMAL :
4297 match = IP6_MASKNEQ(&ip6->ip6_dst, &np->in_osrcmsk6,
4298 &np->in_osrcip6);
4299 break;
4300 case FRI_LOOKUP :
4301 match = (*np->in_osrcfunc)(softc, np->in_osrcptr, np->in_v[0],
4302 &ip6->ip6_dst, fin->fin_plen);
4303 break;
4304 }
4305 if (match)
4306 return 0;
4307
4308 switch (np->in_odstatype)
4309 {
4310 case FRI_NORMAL :
4311 match = IP6_MASKNEQ(&ip6->ip6_src, &np->in_odstmsk6,
4312 &np->in_odstip6);
4313 break;
4314 case FRI_LOOKUP :
4315 match = (*np->in_odstfunc)(softc, np->in_odstptr, np->in_v[0],
4316 &ip6->ip6_src, fin->fin_plen);
4317 break;
4318 }
4319 if (match)
4320 return 0;
4321
4322 ft = &np->in_tuc;
4323
4324 switch (ip6->ip6_nxt)
4325 {
4326 case IPPROTO_TCP :
4327 case IPPROTO_UDP :
4328 /*
4329 * Only need to fetch port numbers for NAT
4330 */
4331 if (ipf_pr_pullup(fin, sizeof(ip6_t) + 4) == -1) {
4332 NBUMPSIDE6(fin->fin_out, ns_encap_pullup);
4333 return -1;
4334 }
4335
4336 ports = (u_short *)((char *)ip6 + sizeof(ip6_t));
4337
4338 fi.fi_tcpf = 0;
4339 /*
4340 * And again, because we're simulating a reply, put the port
4341 * numbers in the revese place to where they are now.
4342 */
4343 fi.fi_ports[0] = ntohs(ports[1]);
4344 fi.fi_ports[1] = ntohs(ports[0]);
4345 return ipf_tcpudpchk(&fi, ft);
4346
4347 /* NOTREACHED */
4348
4349 default :
4350 if (ft->ftu_scmp || ft->ftu_dcmp)
4351 return 0;
4352 break;
4353 }
4354
4355 return 1;
4356 }
4357
4358
4359 /* ------------------------------------------------------------------------ */
4360 /* Function: nat6_nextaddr */
4361 /* Returns: int - -1 == bad input (no new address), */
4362 /* 0 == success and dst has new address */
4363 /* Parameters: fin(I) - pointer to packet information */
4364 /* na(I) - how to generate new address */
4365 /* old(I) - original address being replaced */
4366 /* dst(O) - where to put the new address */
4367 /* Write Lock: ipf_nat */
4368 /* */
4369 /* This function uses the contents of the "na" structure, in combination */
4370 /* with "old" to produce a new address to store in "dst". Not all of the */
4371 /* possible uses of "na" will result in a new address. */
4372 /* ------------------------------------------------------------------------ */
4373 static int
4374 ipf_nat6_nextaddr(fin, na, old, dst)
4375 fr_info_t *fin;
4376 nat_addr_t *na;
4377 i6addr_t *old, *dst;
4378 {
4379 ipf_main_softc_t *softc = fin->fin_main_soft;
4380 ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4381 i6addr_t newip, new;
4382 u_32_t amin, amax;
4383 int error;
4384
4385 new.i6[0] = 0;
4386 new.i6[1] = 0;
4387 new.i6[2] = 0;
4388 new.i6[3] = 0;
4389 amin = na->na_addr[0].in4.s_addr;
4390
4391 switch (na->na_atype)
4392 {
4393 case FRI_RANGE :
4394 amax = na->na_addr[1].in4.s_addr;
4395 break;
4396
4397 case FRI_NETMASKED :
4398 case FRI_DYNAMIC :
4399 case FRI_NORMAL :
4400 /*
4401 * Compute the maximum address by adding the inverse of the
4402 * netmask to the minimum address.
4403 */
4404 amax = ~na->na_addr[1].in4.s_addr;
4405 amax |= amin;
4406 break;
4407
4408 case FRI_LOOKUP :
4409 break;
4410
4411 case FRI_BROADCAST :
4412 case FRI_PEERADDR :
4413 case FRI_NETWORK :
4414 default :
4415 return -1;
4416 }
4417
4418 error = -1;
4419 switch (na->na_function)
4420 {
4421 case IPLT_DSTLIST :
4422 error = ipf_dstlist_select_node(fin, na->na_ptr, dst->i6,
4423 NULL);
4424 break;
4425
4426 case IPLT_NONE :
4427 /*
4428 * 0/0 as the new address means leave it alone.
4429 */
4430 if (na->na_addr[0].in4.s_addr == 0 &&
4431 na->na_addr[1].in4.s_addr == 0) {
4432 new = *old;
4433
4434 /*
4435 * 0/32 means get the interface's address
4436 */
4437 } else if (IP6_ISZERO(&na->na_addr[0].in6) &&
4438 IP6_ISONES(&na->na_addr[1].in6)) {
4439 if (ipf_ifpaddr(softc, 6, na->na_atype,
4440 fin->fin_ifp, &newip, NULL) == -1) {
4441 NBUMPSIDE6(fin->fin_out, ns_ifpaddrfail);
4442 return -1;
4443 }
4444 new = newip;
4445 } else {
4446 new.in6 = na->na_nextip6;
4447 }
4448 *dst = new;
4449 break;
4450
4451 default :
4452 NBUMPSIDE6(fin->fin_out, ns_badnextaddr);
4453 break;
4454 }
4455
4456 return error;
4457 }
4458
4459
4460 /* ------------------------------------------------------------------------ */
4461 /* Function: ipf_nat6_nextaddrinit */
4462 /* Returns: int - 0 == success, else error number */
4463 /* Parameters: na(I) - NAT address information for generating new addr*/
4464 /* base(I) - start of where to find strings */
4465 /* initial(I) - flag indicating if it is the first call for */
4466 /* this "na" structure. */
4467 /* ifp(I) - network interface to derive address */
4468 /* information from. */
4469 /* */
4470 /* This function is expected to be called in two scenarious: when a new NAT */
4471 /* rule is loaded into the kernel and when the list of NAT rules is sync'd */
4472 /* up with the valid network interfaces (possibly due to them changing.) */
4473 /* To distinguish between these, the "initial" parameter is used. If it is */
4474 /* 1 then this indicates the rule has just been reloaded and 0 for when we */
4475 /* are updating information. This difference is important because in */
4476 /* instances where we are not updating address information associated with */
4477 /* a network interface, we don't want to disturb what the "next" address to */
4478 /* come out of ipf_nat6_nextaddr() will be. */
4479 /* ------------------------------------------------------------------------ */
4480 static int
4481 ipf_nat6_nextaddrinit(softc, base, na, initial, ifp)
4482 ipf_main_softc_t *softc;
4483 char *base;
4484 nat_addr_t *na;
4485 int initial;
4486 void *ifp;
4487 {
4488 switch (na->na_atype)
4489 {
4490 case FRI_LOOKUP :
4491 if (na->na_subtype == 0) {
4492 na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
4493 na->na_type,
4494 na->na_num,
4495 &na->na_func);
4496 } else if (na->na_subtype == 1) {
4497 na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
4498 na->na_type,
4499 base + na->na_num,
4500 &na->na_func);
4501 }
4502 if (na->na_func == NULL) {
4503 IPFERROR(60072);
4504 return ESRCH;
4505 }
4506 if (na->na_ptr == NULL) {
4507 IPFERROR(60073);
4508 return ESRCH;
4509 }
4510 break;
4511 case FRI_DYNAMIC :
4512 case FRI_BROADCAST :
4513 case FRI_NETWORK :
4514 case FRI_NETMASKED :
4515 case FRI_PEERADDR :
4516 if (ifp != NULL)
4517 (void )ipf_ifpaddr(softc, 6, na->na_atype, ifp,
4518 &na->na_addr[0],
4519 &na->na_addr[1]);
4520 break;
4521
4522 case FRI_SPLIT :
4523 case FRI_RANGE :
4524 if (initial)
4525 na->na_nextip6 = na->na_addr[0].in6;
4526 break;
4527
4528 case FRI_NONE :
4529 IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
4530 return 0;
4531
4532 case FRI_NORMAL :
4533 IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
4534 break;
4535
4536 default :
4537 IPFERROR(60074);
4538 return EINVAL;
4539 }
4540
4541 if (initial && (na->na_atype == FRI_NORMAL)) {
4542 if (IP6_ISZERO(&na->na_addr[0].in6)) {
4543 if (IP6_ISONES(&na->na_addr[1].in6) ||
4544 IP6_ISZERO(&na->na_addr[1].in6)) {
4545 return 0;
4546 }
4547 }
4548
4549 na->na_nextip6 = na->na_addr[0].in6;
4550 if (!IP6_ISONES(&na->na_addr[1].in6)) {
4551 IP6_INC(&na->na_nextip6);
4552 }
4553 }
4554
4555 return 0;
4556 }
4557
4558
4559 /* ------------------------------------------------------------------------ */
4560 /* Function: nat6_encapok */
4561 /* Returns: int - -1 == MTU not big enough, 0 == ok to send packet */
4562 /* Parameters: fin(I) - pointer to packet information */
4563 /* nat(I) - pointer to current NAT session */
4564 /* */
4565 /* The purpose of this function is to determine whether or not a packet can */
4566 /* be sent out of a network interface after it has been encapsulated, before*/
4567 /* the actual encapsulation happens. If it cannot - because the "Don't */
4568 /* fragment" bit has been set - then generate an ICMP error message back to */
4569 /* the origin of the packet, informing it that the packet is too big and */
4570 /* what the actual MTU out for the connection is. */
4571 /* */
4572 /* At present the only question this would leave for strange behaviour is */
4573 /* with local connections that will go out an encapsulation as sending of */
4574 /* ICMP messages to local destinations isn't considered robust. */
4575 /* ------------------------------------------------------------------------ */
4576 static int
4577 ipf_nat6_encapok(fin, nat)
4578 fr_info_t *fin;
4579 nat_t *nat;
4580 {
4581 #ifdef INSTANCES
4582 ipf_main_softc_t *softc = fin->fin_main_soft; /* For GETIFMTU_6 */
4583 #endif
4584 void *sifp;
4585 ipnat_t *n;
4586 int extra;
4587 int mtu;
4588
4589 n = nat->nat_ptr;
4590
4591 if (n->in_redir & NAT_ENCAP) {
4592 extra = sizeof(ip6_t);
4593
4594 } else {
4595 return 0;
4596 }
4597
4598 mtu = GETIFMTU_6(nat->nat_ifps[1]);
4599
4600 if (fin->fin_plen + extra < mtu)
4601 return 0;
4602
4603 sifp = fin->fin_ifp;
4604 fin->fin_ifp = NULL;
4605 fin->fin_icode = 0;
4606 fin->fin_mtu = mtu - extra;
4607
4608 (void) ipf_send_icmp_err(ICMP6_PACKET_TOO_BIG, fin, 1);
4609
4610 fin->fin_mtu = 0;
4611
4612 return -1;
4613 }
4614
4615
4616 /* ------------------------------------------------------------------------ */
4617 /* Function: ipf_nat6_rebuildencapicmp */
4618 /* Returns: int - -1 == error, 0 == success */
4619 /* Parameters: fin(I) - pointer to packet information */
4620 /* nat(I) - pointer to current NAT session */
4621 /* */
4622 /* For ICMP replies received in response to packets we've encapsulated on */
4623 /* the way out, we need to replace all of the addressing fields found in */
4624 /* the data section of the ICMP header. The ICMP packet is going to */
4625 /* contain the the IP packet we sent out (IPENCAP) plus at least 64 bits of */
4626 /* the original IP packet - not something that will be of use to the origin */
4627 /* of the offending packet. */
4628 /* ------------------------------------------------------------------------ */
4629 static nat_t *
4630 ipf_nat6_rebuildencapicmp(fin, nat)
4631 fr_info_t *fin;
4632 nat_t *nat;
4633 {
4634 struct icmp6_hdr *icmp6;
4635 udphdr_t *udp;
4636 ip6_t *oip6;
4637 int p;
4638
4639 icmp6 = fin->fin_dp;
4640 oip6 = (ip6_t *)((u_char *)icmp6 + sizeof(*icmp6));
4641
4642 if (fin->fin_out == 0) {
4643 if (nat->nat_dir == NAT_ENCAPIN) {
4644 oip6->ip6_src = nat->nat_odst6.in6;
4645 oip6->ip6_dst = nat->nat_osrc6.in6;
4646 } else {
4647 oip6->ip6_src = nat->nat_osrc6.in6;
4648 oip6->ip6_dst = nat->nat_odst6.in6;
4649 }
4650 } else {
4651 if (nat->nat_dir == NAT_ENCAPIN) {
4652 oip6->ip6_src = nat->nat_osrc6.in6;
4653 oip6->ip6_dst = nat->nat_odst6.in6;
4654 } else {
4655 oip6->ip6_src = nat->nat_odst6.in6;
4656 oip6->ip6_dst = nat->nat_osrc6.in6;
4657 }
4658 }
4659
4660 udp = (udphdr_t *)(oip6 + 1);
4661
4662 /*
4663 * We use nat6_p here because the original UDP header is quite likely
4664 * to have been lost - the error packet returned contains the outer
4665 * encapsulation header plus 64 bits of the inner IP header, no room
4666 * for a UDP or TCP header unless extra data is returned.
4667 *
4668 * XXX - If the entire original packet has been included (possible)
4669 * then we should be just stripping off the outer encapsulation.
4670 * This is a "todo" for the near future.
4671 */
4672 p = nat->nat_pr[1 - fin->fin_out];
4673
4674 switch (p)
4675 {
4676 case IPPROTO_UDP :
4677 udp->uh_sum = 0;
4678 break;
4679 case IPPROTO_TCP :
4680 /*
4681 * NAT doesn't track the sequence number so we can't pretend
4682 * to know what value this field should carry.
4683 */
4684 ((tcphdr_t *)udp)->th_seq = 0;
4685 break;
4686 default :
4687 break;
4688 }
4689
4690 if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
4691 if (fin->fin_out == 0) {
4692 if (nat->nat_dir == NAT_ENCAPIN) {
4693 udp->uh_sport = nat->nat_odport;
4694 udp->uh_dport = nat->nat_osport;
4695 } else {
4696 udp->uh_sport = nat->nat_osport;
4697 udp->uh_dport = nat->nat_odport;
4698 }
4699 } else {
4700 if (nat->nat_dir == NAT_ENCAPIN) {
4701 udp->uh_sport = nat->nat_osport;
4702 udp->uh_dport = nat->nat_odport;
4703 } else {
4704 udp->uh_sport = nat->nat_odport;
4705 udp->uh_dport = nat->nat_osport;
4706 }
4707 }
4708 }
4709
4710 /* TRACE (fin,oip,udp,icmp6) */
4711 oip6->ip6_nxt = nat->nat_pr[1 - fin->fin_out];
4712
4713 /*
4714 * Reduce the next MTU setting by the size of the encap header
4715 */
4716 if (icmp6->icmp6_type == ICMP6_PACKET_TOO_BIG) {
4717 icmp6->icmp6_mtu = ntohs(icmp6->icmp6_mtu);
4718 icmp6->icmp6_mtu -= sizeof(ip6_t);
4719 icmp6->icmp6_mtu = htons(icmp6->icmp6_mtu);
4720 }
4721
4722 icmp6->icmp6_cksum = 0;
4723 icmp6->icmp6_cksum = ipf_cksum((u_short *)icmp6, fin->fin_dlen);
4724
4725 /* TRACE (fin,oip,udp,icmp6) */
4726
4727 return 0;
4728 }
4729
4730
4731 /* ------------------------------------------------------------------------ */
4732 /* Function: ipf_nat6_icmpquerytype */
4733 /* Returns: int - 1 == success, 0 == failure */
4734 /* Parameters: icmptype(I) - ICMP type number */
4735 /* */
4736 /* Tests to see if the ICMP type number passed is a query/response type or */
4737 /* not. */
4738 /* ------------------------------------------------------------------------ */
4739 static int
4740 ipf_nat6_icmpquerytype(icmptype)
4741 int icmptype;
4742 {
4743
4744 /*
4745 * For the ICMP query NAT code, it is essential that both the query
4746 * and the reply match on the NAT rule. Because the NAT structure
4747 * does not keep track of the icmptype, and a single NAT structure
4748 * is used for all icmp types with the same src, dest and id, we
4749 * simply define the replies as queries as well. The funny thing is,
4750 * altough it seems silly to call a reply a query, this is exactly
4751 * as it is defined in the IPv4 specification
4752 */
4753
4754 switch (icmptype)
4755 {
4756
4757 case ICMP6_ECHO_REPLY:
4758 case ICMP6_ECHO_REQUEST:
4759 /* route aedvertisement/solliciation is currently unsupported: */
4760 /* it would require rewriting the ICMP data section */
4761 case ICMP6_MEMBERSHIP_QUERY:
4762 case ICMP6_MEMBERSHIP_REPORT:
4763 case ICMP6_MEMBERSHIP_REDUCTION:
4764 case ICMP6_WRUREQUEST:
4765 case ICMP6_WRUREPLY:
4766 case MLD6_MTRACE_RESP:
4767 case MLD6_MTRACE:
4768 return 1;
4769 default:
4770 return 0;
4771 }
4772 }
4773 #endif /* USE_INET6 */
4774