FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_nat.c
1 /*
2 * Copyright (C) 1995-1997 by Darren Reed.
3 *
4 * Redistribution and use in source and binary forms are permitted
5 * provided that this notice is preserved and due credit is given
6 * to the original author and the contributors.
7 *
8 * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
9 */
10 #if !defined(lint)
11 static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
12 static const char rcsid[] = "@(#)$FreeBSD$";
13 #endif
14
15 #include "opt_ipfilter.h"
16 #define __FreeBSD_version 300000 /* it's a hack, but close enough */
17
18 #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
19 #define _KERNEL
20 #endif
21
22 #if !defined(_KERNEL) && !defined(KERNEL)
23 # include <stdio.h>
24 # include <string.h>
25 # include <stdlib.h>
26 #endif
27 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/file.h>
32 #if defined(KERNEL) && (__FreeBSD_version >= 220000)
33 # include <sys/filio.h>
34 # include <sys/fcntl.h>
35 #else
36 # include <sys/ioctl.h>
37 #endif
38 #include <sys/fcntl.h>
39 #include <sys/uio.h>
40 #ifndef linux
41 # include <sys/protosw.h>
42 #endif
43 #include <sys/socket.h>
44 #if defined(_KERNEL) && !defined(linux)
45 # include <sys/systm.h>
46 #endif
47 #if !defined(__SVR4) && !defined(__svr4__)
48 # ifndef linux
49 # include <sys/mbuf.h>
50 # endif
51 #else
52 # include <sys/filio.h>
53 # include <sys/byteorder.h>
54 # include <sys/dditypes.h>
55 # include <sys/stream.h>
56 # include <sys/kmem.h>
57 #endif
58 #if __FreeBSD_version >= 300000
59 # include <sys/queue.h>
60 # include <sys/malloc.h>
61 #endif
62 #include <net/if.h>
63 #if __FreeBSD_version >= 300000
64 # include <net/if_var.h>
65 #endif
66 #ifdef sun
67 #include <net/af.h>
68 #endif
69 #include <net/route.h>
70 #include <netinet/in.h>
71 #include <netinet/in_systm.h>
72 #include <netinet/ip.h>
73
74 #ifdef __sgi
75 # ifdef IFF_DRVRLOCK /* IRIX6 */
76 #include <sys/hashing.h>
77 #include <netinet/in_var.h>
78 # endif
79 #endif
80
81 #ifdef RFC1825
82 #include <vpn/md5.h>
83 #include <vpn/ipsec.h>
84 extern struct ifnet vpnif;
85 #endif
86
87 #ifndef linux
88 # include <netinet/ip_var.h>
89 #endif
90 #include <netinet/tcp.h>
91 #include <netinet/udp.h>
92 #include <netinet/ip_icmp.h>
93 #include "netinet/ip_compat.h"
94 #include <netinet/tcpip.h>
95 #include "netinet/ip_fil.h"
96 #include "netinet/ip_proxy.h"
97 #include "netinet/ip_nat.h"
98 #include "netinet/ip_frag.h"
99 #include "netinet/ip_state.h"
100 #ifndef MIN
101 #define MIN(a,b) (((a)<(b))?(a):(b))
102 #endif
103 #undef SOCKADDR_IN
104 #define SOCKADDR_IN struct sockaddr_in
105
106 nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL;
107 static ipnat_t *nat_list = NULL;
108 u_long fr_defnatage = 1200, /* 10 minutes (600 seconds) */
109 fr_defnaticmpage = 6; /* 3 seconds */
110 static natstat_t nat_stats;
111 #if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
112 extern kmutex_t ipf_nat;
113 #endif
114
115 static int nat_flushtable __P((void));
116 static int nat_clearlist __P((void));
117 static void nat_delete __P((struct nat *));
118 static int nat_ifpaddr __P((nat_t *, void *, struct in_addr *));
119
120
121 #define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16))
122
123 #define CALC_SUMD(s1, s2, sd) { \
124 /* Do it twice */ \
125 (s1) = ((s1) & 0xffff) + ((s1) >> 16); \
126 (s1) = ((s1) & 0xffff) + ((s1) >> 16); \
127 /* Do it twice */ \
128 (s2) = ((s2) & 0xffff) + ((s2) >> 16); \
129 (s2) = ((s2) & 0xffff) + ((s2) >> 16); \
130 /* Because ~1 == -2, We really need ~1 == -1 */ \
131 if ((s1) > (s2)) (s2)--; \
132 (sd) = (s2) - (s1); \
133 (sd) = ((sd) & 0xffff) + ((sd) >> 16); }
134
135 void fix_outcksum(sp, n)
136 u_short *sp;
137 u_32_t n;
138 {
139 register u_short sumshort;
140 register u_32_t sum1;
141
142 if (!n)
143 return;
144 sum1 = (~ntohs(*sp)) & 0xffff;
145 sum1 += (n);
146 sum1 = (sum1 >> 16) + (sum1 & 0xffff);
147 /* Again */
148 sum1 = (sum1 >> 16) + (sum1 & 0xffff);
149 sumshort = ~(u_short)sum1;
150 *(sp) = htons(sumshort);
151 }
152
153
154 void fix_incksum(sp, n)
155 u_short *sp;
156 u_32_t n;
157 {
158 register u_short sumshort;
159 register u_32_t sum1;
160
161 if (!n)
162 return;
163 #ifdef sparc
164 sum1 = (~(*sp)) & 0xffff;
165 #else
166 sum1 = (~ntohs(*sp)) & 0xffff;
167 #endif
168 sum1 += ~(n) & 0xffff;
169 sum1 = (sum1 >> 16) + (sum1 & 0xffff);
170 /* Again */
171 sum1 = (sum1 >> 16) + (sum1 & 0xffff);
172 sumshort = ~(u_short)sum1;
173 *(sp) = htons(sumshort);
174 }
175
176
177 /*
178 * How the NAT is organised and works.
179 *
180 * Inside (interface y) NAT Outside (interface x)
181 * -------------------- -+- -------------------------------------
182 * Packet going | out, processsed by ip_natout() for x
183 * ------------> | ------------>
184 * src=10.1.1.1 | src=192.1.1.1
185 * |
186 * | in, processed by ip_natin() for x
187 * <------------ | <------------
188 * dst=10.1.1.1 | dst=192.1.1.1
189 * -------------------- -+- -------------------------------------
190 * ip_natout() - changes ip_src and if required, sport
191 * - creates a new mapping, if required.
192 * ip_natin() - changes ip_dst and if required, dport
193 *
194 * In the NAT table, internal source is recorded as "in" and externally
195 * seen as "out".
196 */
197
198 /*
199 * Handle ioctls which manipulate the NAT.
200 */
201 int nat_ioctl(data, cmd, mode)
202 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
203 u_long cmd;
204 #else
205 int cmd;
206 #endif
207 caddr_t data;
208 int mode;
209 {
210 register ipnat_t *nat, *n = NULL, **np = NULL;
211 ipnat_t natd;
212 int error = 0, ret;
213 #if defined(_KERNEL) && !SOLARIS
214 int s;
215 #endif
216
217 nat = NULL; /* XXX gcc -Wuninitialized */
218
219 /*
220 * For add/delete, look to see if the NAT entry is already present
221 */
222 SPL_NET(s);
223 MUTEX_ENTER(&ipf_nat);
224 if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
225 IRCOPY(data, (char *)&natd, sizeof(natd));
226 nat = &natd;
227 nat->in_inip &= nat->in_inmsk;
228 nat->in_outip &= nat->in_outmsk;
229 for (np = &nat_list; (n = *np); np = &n->in_next)
230 if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
231 IPN_CMPSIZ))
232 break;
233 }
234
235 switch (cmd)
236 {
237 case SIOCADNAT :
238 if (!(mode & FWRITE)) {
239 error = EPERM;
240 break;
241 }
242 if (n) {
243 error = EEXIST;
244 break;
245 }
246 KMALLOC(n, ipnat_t *, sizeof(*n));
247 if (n == NULL) {
248 error = ENOMEM;
249 break;
250 }
251 bcopy((char *)nat, (char *)n, sizeof(*n));
252 n->in_ifp = (void *)GETUNIT(n->in_ifname);
253 if (!n->in_ifp)
254 n->in_ifp = (void *)-1;
255 n->in_apr = ap_match(n->in_p, n->in_plabel);
256 n->in_next = *np;
257 n->in_use = 0;
258 n->in_space = ~(0xffffffff & ntohl(n->in_outmsk));
259 if (n->in_space) /* lose 2: broadcast + network address */
260 n->in_space -= 2;
261 else
262 n->in_space = 1; /* single IP# mapping */
263 if ((n->in_outmsk != 0xffffffff) && n->in_outmsk)
264 n->in_nip = ntohl(n->in_outip) + 1;
265 else
266 n->in_nip = ntohl(n->in_outip);
267 if (n->in_redir & NAT_MAP) {
268 n->in_pnext = ntohs(n->in_pmin);
269 /*
270 * Multiply by the number of ports made available.
271 */
272 if (ntohs(n->in_pmax) > ntohs(n->in_pmin))
273 n->in_space *= (ntohs(n->in_pmax) -
274 ntohs(n->in_pmin));
275 }
276 /* Otherwise, these fields are preset */
277 *np = n;
278 nat_stats.ns_rules++;
279 break;
280 case SIOCRMNAT :
281 if (!(mode & FWRITE)) {
282 error = EPERM;
283 break;
284 }
285 if (!n) {
286 error = ESRCH;
287 break;
288 }
289 *np = n->in_next;
290 if (!n->in_use) {
291 if (n->in_apr)
292 ap_free(n->in_apr);
293 KFREE(n);
294 nat_stats.ns_rules--;
295 } else {
296 n->in_flags |= IPN_DELETE;
297 n->in_next = NULL;
298 }
299 break;
300 case SIOCGNATS :
301 nat_stats.ns_table[0] = nat_table[0];
302 nat_stats.ns_table[1] = nat_table[1];
303 nat_stats.ns_list = nat_list;
304 IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats));
305 break;
306 case SIOCGNATL :
307 {
308 natlookup_t nl;
309
310 IRCOPY((char *)data, (char *)&nl, sizeof(nl));
311
312 if (nat_lookupredir(&nl)) {
313 IWCOPY((char *)&nl, (char *)data, sizeof(nl));
314 } else
315 error = ESRCH;
316 break;
317 }
318 case SIOCFLNAT :
319 if (!(mode & FWRITE)) {
320 error = EPERM;
321 break;
322 }
323 ret = nat_flushtable();
324 (void) ap_unload();
325 IWCOPY((caddr_t)&ret, data, sizeof(ret));
326 break;
327 case SIOCCNATL :
328 if (!(mode & FWRITE)) {
329 error = EPERM;
330 break;
331 }
332 ret = nat_clearlist();
333 IWCOPY((caddr_t)&ret, data, sizeof(ret));
334 break;
335 case FIONREAD :
336 #ifdef IPFILTER_LOG
337 IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data,
338 sizeof(iplused[IPL_LOGNAT]));
339 #endif
340 break;
341 }
342 MUTEX_EXIT(&ipf_nat);
343 SPL_X(s);
344 return error;
345 }
346
347
348 /*
349 * Delete a nat entry from the various lists and table.
350 */
351 static void nat_delete(natd)
352 struct nat *natd;
353 {
354 register struct nat **natp, *nat;
355 struct ipnat *ipn;
356
357 for (natp = natd->nat_hstart[0]; (nat = *natp);
358 natp = &nat->nat_hnext[0])
359 if (nat == natd) {
360 *natp = nat->nat_hnext[0];
361 break;
362 }
363
364 for (natp = natd->nat_hstart[1]; (nat = *natp);
365 natp = &nat->nat_hnext[1])
366 if (nat == natd) {
367 *natp = nat->nat_hnext[1];
368 break;
369 }
370
371 /*
372 * If there is an active reference from the nat entry to its parent
373 * rule, decrement the rule's reference count and free it too if no
374 * longer being used.
375 */
376 if ((ipn = natd->nat_ptr)) {
377 ipn->in_space++;
378 ipn->in_use--;
379 if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) {
380 if (ipn->in_apr)
381 ap_free(ipn->in_apr);
382 KFREE(ipn);
383 nat_stats.ns_rules--;
384 }
385 }
386
387 /*
388 * If there's a fragment table entry too for this nat entry, then
389 * dereference that as well.
390 */
391 ipfr_forget((void *)natd);
392 KFREE(natd);
393 }
394
395
396 /*
397 * nat_flushtable - clear the NAT table of all mapping entries.
398 */
399 static int nat_flushtable()
400 {
401 register nat_t *nat, **natp;
402 register int j = 0;
403
404 /*
405 * Everything will be deleted, so lets just make it the deletions
406 * quicker.
407 */
408 bzero((char *)nat_table[0], sizeof(nat_table[0]));
409 bzero((char *)nat_table[1], sizeof(nat_table[1]));
410
411 for (natp = &nat_instances; (nat = *natp); ) {
412 *natp = nat->nat_next;
413 nat_delete(nat);
414 j++;
415 }
416
417 return j;
418 }
419
420
421 /*
422 * nat_clearlist - delete all entries in the active NAT mapping list.
423 */
424 static int nat_clearlist()
425 {
426 register ipnat_t *n, **np = &nat_list;
427 int i = 0;
428
429 while ((n = *np)) {
430 *np = n->in_next;
431 if (!n->in_use) {
432 if (n->in_apr)
433 ap_free(n->in_apr);
434 KFREE(n);
435 nat_stats.ns_rules--;
436 i++;
437 } else {
438 n->in_flags |= IPN_DELETE;
439 n->in_next = NULL;
440 }
441 }
442 nat_stats.ns_inuse = 0;
443 return i;
444 }
445
446
447 /*
448 * return the first IP Address associated with an interface
449 */
450 static int nat_ifpaddr(nat, ifptr, inp)
451 nat_t *nat;
452 void *ifptr;
453 struct in_addr *inp;
454 {
455 #if SOLARIS
456 ill_t *ill = ifptr;
457 #else
458 struct ifnet *ifp = ifptr;
459 #endif
460 struct in_addr in;
461
462 #if SOLARIS
463 in.s_addr = ntohl(ill->ill_ipif->ipif_local_addr);
464 #else /* SOLARIS */
465 # if linux
466 ;
467 # else /* linux */
468 struct ifaddr *ifa;
469 struct sockaddr_in *sin;
470
471 # if (__FreeBSD_version >= 300000)
472 ifa = TAILQ_FIRST(&ifp->if_addrhead);
473 # else
474 # if defined(__NetBSD__) || defined(__OpenBSD__)
475 ifa = ifp->if_addrlist.tqh_first;
476 # else
477 # if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
478 ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa;
479 # else
480 ifa = ifp->if_addrlist;
481 # endif
482 # endif /* __NetBSD__ || __OpenBSD__ */
483 # endif /* __FreeBSD_version >= 300000 */
484 # if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK))
485 sin = (SOCKADDR_IN *)&ifa->ifa_addr;
486 # else
487 sin = (SOCKADDR_IN *)ifa->ifa_addr;
488 while (sin && ifa &&
489 sin->sin_family != AF_INET) {
490 # if (__FreeBSD_version >= 300000)
491 ifa = TAILQ_NEXT(ifa, ifa_link);
492 # else
493 # if defined(__NetBSD__) || defined(__OpenBSD__)
494 ifa = ifa->ifa_list.tqe_next;
495 # else
496 ifa = ifa->ifa_next;
497 # endif
498 # endif /* __FreeBSD_version >= 300000 */
499 if (ifa)
500 sin = (SOCKADDR_IN *)ifa->ifa_addr;
501 }
502 if (!ifa)
503 sin = NULL;
504 if (!sin) {
505 KFREE(nat);
506 return -1;
507 }
508 # endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */
509 in = sin->sin_addr;
510 in.s_addr = ntohl(in.s_addr);
511 # endif /* linux */
512 #endif /* SOLARIS */
513 *inp = in;
514 return 0;
515 }
516
517
518 /*
519 * Create a new NAT table entry.
520 */
521 nat_t *nat_new(np, ip, fin, flags, direction)
522 ipnat_t *np;
523 ip_t *ip;
524 fr_info_t *fin;
525 u_short flags;
526 int direction;
527 {
528 register u_32_t sum1, sum2, sumd, l;
529 u_short port = 0, sport = 0, dport = 0, nport = 0;
530 struct in_addr in;
531 tcphdr_t *tcp = NULL;
532 nat_t *nat, **natp;
533 u_short nflags;
534
535 nflags = flags & np->in_flags;
536 if (flags & IPN_TCPUDP) {
537 tcp = (tcphdr_t *)fin->fin_dp;
538 sport = tcp->th_sport;
539 dport = tcp->th_dport;
540 }
541
542 /* Give me a new nat */
543 KMALLOC(nat, nat_t *, sizeof(*nat));
544 if (nat == NULL)
545 return NULL;
546
547 bzero((char *)nat, sizeof(*nat));
548 nat->nat_flags = flags;
549
550 /*
551 * Search the current table for a match.
552 */
553 if (direction == NAT_OUTBOUND) {
554 /*
555 * If it's an outbound packet which doesn't match any existing
556 * record, then create a new port
557 */
558 l = 0;
559 do {
560 l++;
561 port = 0;
562 in.s_addr = np->in_nip;
563 if (!in.s_addr && (np->in_outmsk == 0xffffffff)) {
564 if ((l > 1) ||
565 nat_ifpaddr(nat, fin->fin_ifp, &in) == -1) {
566 KFREE(nat);
567 return NULL;
568 }
569 } else if (!in.s_addr && !np->in_outmsk) {
570 if (l > 1) {
571 KFREE(nat);
572 return NULL;
573 }
574 in.s_addr = ntohl(ip->ip_src.s_addr);
575 if (nflags & IPN_TCPUDP)
576 port = sport;
577 } else if (nflags & IPN_TCPUDP) {
578 port = htons(np->in_pnext++);
579 if (np->in_pnext >= ntohs(np->in_pmax)) {
580 np->in_pnext = ntohs(np->in_pmin);
581 np->in_space--;
582 if (np->in_outmsk != 0xffffffff)
583 np->in_nip++;
584 }
585 } else if (np->in_outmsk != 0xffffffff) {
586 np->in_space--;
587 np->in_nip++;
588 }
589
590 if (!port && (flags & IPN_TCPUDP))
591 port = sport;
592 if ((np->in_nip & ntohl(np->in_outmsk)) >
593 ntohl(np->in_outip))
594 np->in_nip = ntohl(np->in_outip) + 1;
595 } while (nat_inlookup(fin->fin_ifp, flags, ip->ip_dst,
596 dport, in, port));
597
598 /* Setup the NAT table */
599 nat->nat_inip = ip->ip_src;
600 nat->nat_outip.s_addr = htonl(in.s_addr);
601 nat->nat_oip = ip->ip_dst;
602
603 sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
604 (ntohl(ip->ip_src.s_addr) >> 16) + ntohs(sport);
605
606 sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(port);
607
608 if (flags & IPN_TCPUDP) {
609 nat->nat_inport = sport;
610 nat->nat_outport = port;
611 nat->nat_oport = dport;
612 }
613 } else {
614
615 /*
616 * Otherwise, it's an inbound packet. Most likely, we don't
617 * want to rewrite source ports and source addresses. Instead,
618 * we want to rewrite to a fixed internal address and fixed
619 * internal port.
620 */
621 in.s_addr = ntohl(np->in_inip);
622 if (!(nport = np->in_pnext))
623 nport = dport;
624
625 nat->nat_inip.s_addr = htonl(in.s_addr);
626 nat->nat_outip = ip->ip_dst;
627 nat->nat_oip = ip->ip_src;
628
629 sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
630 (ntohl(ip->ip_dst.s_addr) >> 16) + ntohs(dport);
631
632 sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport);
633
634 if (flags & IPN_TCPUDP) {
635 nat->nat_inport = nport;
636 nat->nat_outport = dport;
637 nat->nat_oport = sport;
638 }
639 }
640
641 /* Do it twice */
642 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
643 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
644
645 /* Do it twice */
646 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
647 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
648
649 if (sum1 > sum2)
650 sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
651 sumd = sum2 - sum1;
652 sumd = (sumd & 0xffff) + (sumd >> 16);
653 nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
654
655 if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {
656 if (direction == NAT_OUTBOUND)
657 sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
658 (ntohl(ip->ip_src.s_addr) >> 16);
659 else
660 sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
661 (ntohl(ip->ip_dst.s_addr) >> 16);
662
663 sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16);
664
665 /* Do it twice */
666 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
667 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
668
669 /* Do it twice */
670 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
671 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
672
673 if (sum1 > sum2)
674 sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
675 sumd = sum2 - sum1;
676 sumd = (sumd & 0xffff) + (sumd >> 16);
677 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
678 } else
679 nat->nat_ipsumd = nat->nat_sumd;
680
681 in.s_addr = htonl(in.s_addr);
682 nat->nat_next = nat_instances;
683 nat_instances = nat;
684 natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE];
685 nat->nat_hstart[0] = natp;
686 nat->nat_hnext[0] = *natp;
687 *natp = nat;
688 natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE];
689 nat->nat_hstart[1] = natp;
690 nat->nat_hnext[1] = *natp;
691 *natp = nat;
692 nat->nat_ptr = np;
693 nat->nat_bytes = 0;
694 nat->nat_pkts = 0;
695 nat->nat_ifp = fin->fin_ifp;
696 nat->nat_dir = direction;
697 if (direction == NAT_OUTBOUND) {
698 if (flags & IPN_TCPUDP)
699 tcp->th_sport = port;
700 } else {
701 if (flags & IPN_TCPUDP)
702 tcp->th_dport = nport;
703 }
704 nat_stats.ns_added++;
705 nat_stats.ns_inuse++;
706 np->in_use++;
707 return nat;
708 }
709
710
711 nat_t *nat_icmpinlookup(ip, fin)
712 ip_t *ip;
713 fr_info_t *fin;
714 {
715 icmphdr_t *icmp;
716 tcphdr_t *tcp = NULL;
717 ip_t *oip;
718 int flags = 0, type;
719
720 icmp = (icmphdr_t *)fin->fin_dp;
721 /*
722 * Does it at least have the return (basic) IP header ?
723 * Only a basic IP header (no options) should be with an ICMP error
724 * header.
725 */
726 if ((ip->ip_hl != 5) || (ip->ip_len < sizeof(*icmp) + sizeof(ip_t)))
727 return NULL;
728 type = icmp->icmp_type;
729 /*
730 * If it's not an error type, then return.
731 */
732 if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) &&
733 (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) &&
734 (type != ICMP_PARAMPROB))
735 return NULL;
736
737 oip = (ip_t *)((char *)fin->fin_dp + 8);
738 if (oip->ip_p == IPPROTO_TCP)
739 flags = IPN_TCP;
740 else if (oip->ip_p == IPPROTO_UDP)
741 flags = IPN_UDP;
742 if (flags & IPN_TCPUDP) {
743 tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
744 return nat_inlookup(fin->fin_ifp, flags, oip->ip_dst,
745 tcp->th_dport, oip->ip_src, tcp->th_sport);
746 }
747 return nat_inlookup(fin->fin_ifp, 0, oip->ip_src, 0, oip->ip_dst, 0);
748 }
749
750
751 /*
752 * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP
753 * packet gets correctly recognised.
754 */
755 nat_t *nat_icmpin(ip, fin, nflags)
756 ip_t *ip;
757 fr_info_t *fin;
758 int *nflags;
759 {
760 icmphdr_t *icmp;
761 nat_t *nat;
762 ip_t *oip;
763 int flags = 0;
764
765 if (!(nat = nat_icmpinlookup(ip, fin)))
766 return NULL;
767
768 *nflags = IPN_ICMPERR;
769 icmp = (icmphdr_t *)fin->fin_dp;
770 oip = (ip_t *)((char *)icmp + 8);
771 if (oip->ip_p == IPPROTO_TCP)
772 flags = IPN_TCP;
773 else if (oip->ip_p == IPPROTO_UDP)
774 flags = IPN_UDP;
775 /*
776 * Need to adjust ICMP header to include the real IP#'s and
777 * port #'s. Only apply a checksum change relative to the
778 * IP address change is it will be modified again in ip_natout
779 * for both address and port. Two checksum changes are
780 * necessary for the two header address changes. Be careful
781 * to only modify the checksum once for the port # and twice
782 * for the IP#.
783 */
784 if (flags & IPN_TCPUDP) {
785 tcphdr_t *tcp = (tcphdr_t *)(oip + 1);
786 u_32_t sum1, sum2, sumd;
787 struct in_addr in;
788
789 if (nat->nat_dir == NAT_OUTBOUND) {
790 sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
791 in = nat->nat_outip;
792 oip->ip_src = in;
793 tcp->th_sport = nat->nat_outport;
794 } else {
795 sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr));
796 in = nat->nat_inip;
797 oip->ip_dst = in;
798 tcp->th_dport = nat->nat_inport;
799 }
800
801 sum2 = LONG_SUM(in.s_addr);
802
803 CALC_SUMD(sum1, sum2, sumd);
804 sumd = (sumd & 0xffff) + (sumd >> 16);
805
806 if (nat->nat_dir == NAT_OUTBOUND) {
807 fix_incksum(&oip->ip_sum, sumd);
808 fix_incksum(&icmp->icmp_cksum, sumd);
809 } else {
810 fix_outcksum(&oip->ip_sum, sumd);
811 fix_outcksum(&icmp->icmp_cksum, sumd);
812 }
813
814 /*
815 * TCP checksum doesn't make it into the 1st eight
816 * bytes but UDP does.
817 */
818 if (ip->ip_p == IPPROTO_UDP) {
819 udphdr_t *udp = (udphdr_t *)tcp;
820
821 if (udp->uh_sum) {
822 if (nat->nat_dir == NAT_OUTBOUND)
823 fix_incksum(&udp->uh_sum,
824 nat->nat_sumd);
825 else
826 fix_outcksum(&udp->uh_sum,
827 nat->nat_sumd);
828 }
829 }
830 } else
831 ip->ip_dst = nat->nat_outip;
832 nat->nat_age = fr_defnaticmpage;
833 return nat;
834 }
835
836
837 /*
838 * NB: these lookups don't lock access to the list, it assume it has already
839 * been done!
840 */
841 /*
842 * Lookup a nat entry based on the mapped destination ip address/port and
843 * real source address/port. We use this lookup when receiving a packet,
844 * we're looking for a table entry, based on the destination address.
845 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
846 */
847 #ifdef __STDC__
848 nat_t *nat_inlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr mapdst, u_short mapdport)
849 #else
850 nat_t *nat_inlookup(ifp, flags, src, sport, mapdst, mapdport)
851 void *ifp;
852 register int flags;
853 struct in_addr src , mapdst;
854 u_short sport, mapdport;
855 #endif
856 {
857 register nat_t *nat;
858
859 flags &= IPN_TCPUDP;
860
861 nat = nat_table[1][mapdst.s_addr % NAT_SIZE];
862 for (; nat; nat = nat->nat_hnext[1])
863 if ((!ifp || ifp == nat->nat_ifp) &&
864 nat->nat_oip.s_addr == src.s_addr &&
865 nat->nat_outip.s_addr == mapdst.s_addr &&
866 flags == nat->nat_flags && (!flags ||
867 (nat->nat_oport == sport &&
868 nat->nat_outport == mapdport)))
869 return nat;
870 return NULL;
871 }
872
873
874 /*
875 * Lookup a nat entry based on the source 'real' ip address/port and
876 * destination address/port. We use this lookup when sending a packet out,
877 * we're looking for a table entry, based on the source address.
878 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
879 */
880 #ifdef __STDC__
881 nat_t *nat_outlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr dst, u_short dport)
882 #else
883 nat_t *nat_outlookup(ifp, flags, src, sport, dst, dport)
884 void *ifp;
885 register int flags;
886 struct in_addr src , dst;
887 u_short sport, dport;
888 #endif
889 {
890 register nat_t *nat;
891
892 flags &= IPN_TCPUDP;
893
894 nat = nat_table[0][src.s_addr % NAT_SIZE];
895 for (; nat; nat = nat->nat_hnext[0]) {
896 if ((!ifp || ifp == nat->nat_ifp) &&
897 nat->nat_inip.s_addr == src.s_addr &&
898 nat->nat_oip.s_addr == dst.s_addr &&
899 flags == nat->nat_flags && (!flags ||
900 (nat->nat_inport == sport && nat->nat_oport == dport)))
901 return nat;
902 }
903 return NULL;
904 }
905
906
907 /*
908 * Lookup a nat entry based on the mapped source ip address/port and
909 * real destination address/port. We use this lookup when sending a packet
910 * out, we're looking for a table entry, based on the source address.
911 */
912 #ifdef __STDC__
913 nat_t *nat_lookupmapip(void *ifp, int flags, struct in_addr mapsrc, u_short mapsport, struct in_addr dst, u_short dport)
914 #else
915 nat_t *nat_lookupmapip(ifp, flags, mapsrc, mapsport, dst, dport)
916 void *ifp;
917 register int flags;
918 struct in_addr mapsrc , dst;
919 u_short mapsport, dport;
920 #endif
921 {
922 register nat_t *nat;
923
924 flags &= IPN_TCPUDP;
925
926 nat = nat_table[1][mapsrc.s_addr % NAT_SIZE];
927 for (; nat; nat = nat->nat_hnext[0])
928 if ((!ifp || ifp == nat->nat_ifp) &&
929 nat->nat_oip.s_addr == dst.s_addr &&
930 nat->nat_outip.s_addr == mapsrc.s_addr &&
931 flags == nat->nat_flags && (!flags ||
932 (nat->nat_outport == mapsport &&
933 nat->nat_oport == dport)))
934 return nat;
935 return NULL;
936 }
937
938
939 /*
940 * Lookup the NAT tables to search for a matching redirect
941 */
942 nat_t *nat_lookupredir(np)
943 register natlookup_t *np;
944 {
945 nat_t *nat;
946
947 /*
948 * If nl_inip is non null, this is a lookup based on the real
949 * ip address. Else, we use the fake.
950 */
951 if ((nat = nat_outlookup(NULL, np->nl_flags, np->nl_inip,
952 np->nl_inport, np->nl_outip,
953 np->nl_outport))) {
954 np->nl_realip = nat->nat_outip;
955 np->nl_realport = nat->nat_outport;
956 }
957 return nat;
958 }
959
960
961 /*
962 * Packets going out on the external interface go through this.
963 * Here, the source address requires alteration, if anything.
964 */
965 int ip_natout(ip, hlen, fin)
966 ip_t *ip;
967 int hlen;
968 fr_info_t *fin;
969 {
970 register ipnat_t *np;
971 register u_32_t ipa;
972 tcphdr_t *tcp = NULL;
973 u_short nflags = 0, sport = 0, dport = 0, *csump = NULL;
974 struct ifnet *ifp;
975 frentry_t *fr;
976 nat_t *nat;
977 int natadd = 1;
978
979 if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
980 fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
981 ifp = fr->fr_tif.fd_ifp;
982 else
983 ifp = fin->fin_ifp;
984
985 if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
986 if (ip->ip_p == IPPROTO_TCP)
987 nflags = IPN_TCP;
988 else if (ip->ip_p == IPPROTO_UDP)
989 nflags = IPN_UDP;
990 if (nflags) {
991 tcp = (tcphdr_t *)fin->fin_dp;
992 sport = tcp->th_sport;
993 dport = tcp->th_dport;
994 }
995 }
996
997 ipa = ip->ip_src.s_addr;
998
999 MUTEX_ENTER(&ipf_nat);
1000 if ((ip->ip_off & (IP_OFFMASK|IP_MF)) &&
1001 (nat = ipfr_nat_knownfrag(ip, fin)))
1002 natadd = 0;
1003 else if ((nat = nat_outlookup(ifp, nflags, ip->ip_src, sport,
1004 ip->ip_dst, dport)))
1005 ;
1006 else
1007 /*
1008 * If there is no current entry in the nat table for this IP#,
1009 * create one for it (if there is a matching rule).
1010 */
1011 for (np = nat_list; np; np = np->in_next)
1012 if ((np->in_ifp == ifp) && np->in_space &&
1013 (!np->in_flags || (np->in_flags & nflags)) &&
1014 ((ipa & np->in_inmsk) == np->in_inip) &&
1015 ((np->in_redir & NAT_MAP) ||
1016 (np->in_pnext == sport))) {
1017 if (*np->in_plabel && !ap_ok(ip, tcp, np))
1018 continue;
1019 /*
1020 * If it's a redirection, then we don't want to
1021 * create new outgoing port stuff.
1022 * Redirections are only for incoming
1023 * connections.
1024 */
1025 if (!(np->in_redir & NAT_MAP))
1026 continue;
1027 if ((nat = nat_new(np, ip, fin, nflags,
1028 NAT_OUTBOUND)))
1029 #ifdef IPFILTER_LOG
1030 nat_log(nat, (u_short)np->in_redir);
1031 #else
1032 ;
1033 #endif
1034 break;
1035 }
1036
1037 if (nat) {
1038 if (natadd && fin->fin_fi.fi_fl & FI_FRAG)
1039 ipfr_nat_newfrag(ip, fin, 0, nat);
1040 nat->nat_age = fr_defnatage;
1041 ip->ip_src = nat->nat_outip;
1042 nat->nat_bytes += ip->ip_len;
1043 nat->nat_pkts++;
1044
1045 /*
1046 * Fix up checksums, not by recalculating them, but
1047 * simply computing adjustments.
1048 */
1049 #if SOLARIS || defined(__sgi)
1050 if (nat->nat_dir == NAT_OUTBOUND)
1051 fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
1052 else
1053 fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
1054 #endif
1055
1056 if (nflags && !(ip->ip_off & 0x1fff) &&
1057 !(fin->fin_fi.fi_fl & FI_SHORT)) {
1058
1059 if (nat->nat_outport)
1060 tcp->th_sport = nat->nat_outport;
1061
1062 if (ip->ip_p == IPPROTO_TCP) {
1063 csump = &tcp->th_sum;
1064 fr_tcp_age(&nat->nat_age,
1065 nat->nat_state, ip, fin,1);
1066 /*
1067 * Increase this because we may have
1068 * "keep state" following this too and
1069 * packet storms can occur if this is
1070 * removed too quickly.
1071 */
1072 if (nat->nat_age == fr_tcpclosed)
1073 nat->nat_age = fr_tcplastack;
1074 } else if (ip->ip_p == IPPROTO_UDP) {
1075 udphdr_t *udp = (udphdr_t *)tcp;
1076
1077 if (udp->uh_sum)
1078 csump = &udp->uh_sum;
1079 } else if (ip->ip_p == IPPROTO_ICMP) {
1080 icmphdr_t *ic = (icmphdr_t *)tcp;
1081
1082 csump = &ic->icmp_cksum;
1083 }
1084 if (csump) {
1085 if (nat->nat_dir == NAT_OUTBOUND)
1086 fix_outcksum(csump,
1087 nat->nat_sumd);
1088 else
1089 fix_incksum(csump,
1090 nat->nat_sumd);
1091 }
1092 }
1093 (void) ap_check(ip, tcp, fin, nat);
1094 nat_stats.ns_mapped[1]++;
1095 MUTEX_EXIT(&ipf_nat);
1096 return -2;
1097 }
1098 MUTEX_EXIT(&ipf_nat);
1099 return 0;
1100 }
1101
1102
1103 /*
1104 * Packets coming in from the external interface go through this.
1105 * Here, the destination address requires alteration, if anything.
1106 */
1107 int ip_natin(ip, hlen, fin)
1108 ip_t *ip;
1109 int hlen;
1110 fr_info_t *fin;
1111 {
1112 register ipnat_t *np;
1113 register struct in_addr in;
1114 struct ifnet *ifp = fin->fin_ifp;
1115 tcphdr_t *tcp = NULL;
1116 u_short sport = 0, dport = 0, *csump = NULL;
1117 nat_t *nat;
1118 int nflags = 0, natadd = 1;
1119
1120 if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
1121 if (ip->ip_p == IPPROTO_TCP)
1122 nflags = IPN_TCP;
1123 else if (ip->ip_p == IPPROTO_UDP)
1124 nflags = IPN_UDP;
1125 if (nflags) {
1126 tcp = (tcphdr_t *)((char *)ip + hlen);
1127 dport = tcp->th_dport;
1128 sport = tcp->th_sport;
1129 }
1130 }
1131
1132 in = ip->ip_dst;
1133
1134 MUTEX_ENTER(&ipf_nat);
1135
1136 if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmpin(ip, fin, &nflags)))
1137 ;
1138 else if ((ip->ip_off & IP_OFFMASK) &&
1139 (nat = ipfr_nat_knownfrag(ip, fin)))
1140 natadd = 0;
1141 else if ((nat = nat_inlookup(fin->fin_ifp, nflags, ip->ip_src, sport,
1142 ip->ip_dst, dport)))
1143 ;
1144 else
1145 /*
1146 * If there is no current entry in the nat table for this IP#,
1147 * create one for it (if there is a matching rule).
1148 */
1149 for (np = nat_list; np; np = np->in_next)
1150 if ((np->in_ifp == ifp) &&
1151 (!np->in_flags || (nflags & np->in_flags)) &&
1152 ((in.s_addr & np->in_outmsk) == np->in_outip) &&
1153 (np->in_redir & NAT_REDIRECT) &&
1154 (!np->in_pmin || np->in_pmin == dport)) {
1155 if ((nat = nat_new(np, ip, fin, nflags,
1156 NAT_INBOUND)))
1157 #ifdef IPFILTER_LOG
1158 nat_log(nat, (u_short)np->in_redir);
1159 #else
1160 ;
1161 #endif
1162 break;
1163 }
1164 if (nat) {
1165 if (natadd && fin->fin_fi.fi_fl & FI_FRAG)
1166 ipfr_nat_newfrag(ip, fin, 0, nat);
1167 (void) ap_check(ip, tcp, fin, nat);
1168
1169 if (nflags != IPN_ICMPERR)
1170 nat->nat_age = fr_defnatage;
1171
1172 ip->ip_dst = nat->nat_inip;
1173 nat->nat_bytes += ip->ip_len;
1174 nat->nat_pkts++;
1175
1176 /*
1177 * Fix up checksums, not by recalculating them, but
1178 * simply computing adjustments.
1179 */
1180 #if SOLARIS || defined(__sgi)
1181 if (nat->nat_dir == NAT_OUTBOUND)
1182 fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
1183 else
1184 fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
1185 #endif
1186 if ((nflags & IPN_TCPUDP) && !(ip->ip_off & 0x1fff) &&
1187 !(fin->fin_fi.fi_fl & FI_SHORT)) {
1188
1189 if (nat->nat_inport)
1190 tcp->th_dport = nat->nat_inport;
1191
1192 if (ip->ip_p == IPPROTO_TCP) {
1193 csump = &tcp->th_sum;
1194 fr_tcp_age(&nat->nat_age,
1195 nat->nat_state, ip, fin,0);
1196 /*
1197 * Increase this because we may have
1198 * "keep state" following this too and
1199 * packet storms can occur if this is
1200 * removed too quickly.
1201 */
1202 if (nat->nat_age == fr_tcpclosed)
1203 nat->nat_age = fr_tcplastack;
1204 } else if (ip->ip_p == IPPROTO_UDP) {
1205 udphdr_t *udp = (udphdr_t *)tcp;
1206
1207 if (udp->uh_sum)
1208 csump = &udp->uh_sum;
1209 } else if (ip->ip_p == IPPROTO_ICMP) {
1210 icmphdr_t *ic = (icmphdr_t *)tcp;
1211
1212 csump = &ic->icmp_cksum;
1213 }
1214 if (csump) {
1215 if (nat->nat_dir == NAT_OUTBOUND)
1216 fix_incksum(csump,
1217 nat->nat_sumd);
1218 else
1219 fix_outcksum(csump,
1220 nat->nat_sumd);
1221 }
1222 }
1223 nat_stats.ns_mapped[0]++;
1224 MUTEX_EXIT(&ipf_nat);
1225 return -2;
1226 }
1227 MUTEX_EXIT(&ipf_nat);
1228 return 0;
1229 }
1230
1231
1232 /*
1233 * Free all memory used by NAT structures allocated at runtime.
1234 */
1235 void ip_natunload()
1236 {
1237 MUTEX_ENTER(&ipf_nat);
1238 (void) nat_clearlist();
1239 (void) nat_flushtable();
1240 (void) ap_unload();
1241 MUTEX_EXIT(&ipf_nat);
1242 }
1243
1244
1245 /*
1246 * Slowly expire held state for NAT entries. Timeouts are set in
1247 * expectation of this being called twice per second.
1248 */
1249 void ip_natexpire()
1250 {
1251 register struct nat *nat, **natp;
1252 #if defined(_KERNEL) && !SOLARIS
1253 int s;
1254 #endif
1255
1256 SPL_NET(s);
1257 MUTEX_ENTER(&ipf_nat);
1258 for (natp = &nat_instances; (nat = *natp); ) {
1259 if (--nat->nat_age) {
1260 natp = &nat->nat_next;
1261 continue;
1262 }
1263 *natp = nat->nat_next;
1264 #ifdef IPFILTER_LOG
1265 nat_log(nat, NL_EXPIRE);
1266 #endif
1267 nat_delete(nat);
1268 nat_stats.ns_expire++;
1269 }
1270
1271 ap_expire();
1272
1273 MUTEX_EXIT(&ipf_nat);
1274 SPL_X(s);
1275 }
1276
1277
1278 /*
1279 */
1280 #ifdef __STDC__
1281 void ip_natsync(void *ifp)
1282 #else
1283 void ip_natsync(ifp)
1284 void *ifp;
1285 #endif
1286 {
1287 register nat_t *nat;
1288 register u_32_t sum1, sum2, sumd;
1289 struct in_addr in;
1290 ipnat_t *np;
1291 #if defined(_KERNEL) && !SOLARIS
1292 int s;
1293 #endif
1294
1295 SPL_NET(s);
1296 MUTEX_ENTER(&ipf_nat);
1297 for (nat = nat_instances; nat; nat = nat->nat_next)
1298 if ((ifp == nat->nat_ifp) && (np = nat->nat_ptr))
1299 if ((np->in_outmsk == 0xffffffff) && !np->in_nip) {
1300 /*
1301 * Change the map-to address to be the same
1302 * as the new one.
1303 */
1304 sum1 = nat->nat_outip.s_addr;
1305 if (nat_ifpaddr(nat, ifp, &in) == -1)
1306 nat->nat_outip.s_addr = htonl(in.s_addr);
1307 sum2 = nat->nat_outip.s_addr;
1308
1309 /*
1310 * Readjust the checksum adjustment to take
1311 * into account the new IP#.
1312 *
1313 * Do it twice
1314 */
1315 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
1316 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
1317
1318 /* Do it twice */
1319 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1320 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1321
1322 /* Because ~1 == -2, We really need ~1 == -1 */
1323 if (sum1 > sum2)
1324 sum2--;
1325 sumd = sum2 - sum1;
1326 sumd = (sumd & 0xffff) + (sumd >> 16);
1327 sumd += nat->nat_sumd;
1328 nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
1329 }
1330 MUTEX_EXIT(&ipf_nat);
1331 SPL_X(s);
1332 }
1333
1334
1335 #ifdef IPFILTER_LOG
1336 # ifdef __STDC__
1337 void nat_log(struct nat *nat, u_short type)
1338 # else
1339 void nat_log(nat, type)
1340 struct nat *nat;
1341 u_short type;
1342 # endif
1343 {
1344 struct ipnat *np;
1345 struct natlog natl;
1346 void *items[1];
1347 size_t sizes[1];
1348 int rulen, types[1];
1349
1350 natl.nl_inip = nat->nat_inip;
1351 natl.nl_outip = nat->nat_outip;
1352 natl.nl_origip = nat->nat_oip;
1353 natl.nl_bytes = nat->nat_bytes;
1354 natl.nl_pkts = nat->nat_pkts;
1355 natl.nl_origport = nat->nat_oport;
1356 natl.nl_inport = nat->nat_inport;
1357 natl.nl_outport = nat->nat_outport;
1358 natl.nl_type = type;
1359 natl.nl_rule = -1;
1360 if (nat->nat_ptr) {
1361 for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++)
1362 if (np == nat->nat_ptr) {
1363 natl.nl_rule = rulen;
1364 break;
1365 }
1366 }
1367 items[0] = &natl;
1368 sizes[0] = sizeof(natl);
1369 types[0] = 0;
1370
1371 (void) ipllog(IPL_LOGNAT, 0, items, sizes, types, 1);
1372 }
1373 #endif
Cache object: d70d74180043f884d18e414d240d92ea
|