]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/ip_nat.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (C) 1995-1997 by Darren Reed.
25 * Redistribution and use in source and binary forms are permitted
26 * provided that this notice is preserved and due credit is given
27 * to the original author and the contributors.
29 * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
32 /* static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; */
35 #include "opt_ipfilter.h"
36 #define __FreeBSD_version 300000 /* it's a hack, but close enough */
38 #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
42 #if !defined(_KERNEL) && !defined(KERNEL)
47 #include <sys/errno.h>
48 #include <sys/types.h>
49 #include <sys/param.h>
52 #if defined(KERNEL) && (__FreeBSD_version >= 220000)
53 # include <sys/filio.h>
54 # include <sys/fcntl.h>
56 # include <sys/ioctl.h>
58 #include <sys/fcntl.h>
61 # include <sys/protosw.h>
63 #include <sys/socket.h>
64 #if defined(_KERNEL) && !defined(linux)
65 # include <sys/systm.h>
67 #if !defined(__SVR4) && !defined(__svr4__)
69 # include <sys/mbuf.h>
72 # include <sys/filio.h>
73 # include <sys/byteorder.h>
74 # include <sys/dditypes.h>
75 # include <sys/stream.h>
76 # include <sys/kmem.h>
78 #if __FreeBSD_version >= 300000
79 # include <sys/queue.h>
80 # include <sys/malloc.h>
83 #if __FreeBSD_version >= 300000
84 # include <net/if_var.h>
89 #include <net/route.h>
90 #include <netinet/in.h>
91 #include <netinet/in_systm.h>
92 #include <netinet/ip.h>
95 # ifdef IFF_DRVRLOCK /* IRIX6 */
96 #include <sys/hashing.h>
97 #include <netinet/in_var.h>
103 #include <vpn/ipsec.h>
104 extern struct ifnet vpnif
;
108 # include <netinet/ip_var.h>
110 #include <netinet/tcp.h>
111 #include <netinet/udp.h>
112 #include <netinet/ip_icmp.h>
113 #include "netinet/ip_compat.h"
114 #include <netinet/tcpip.h>
115 #include "netinet/ip_fil.h"
116 #include "netinet/ip_proxy.h"
117 #include "netinet/ip_nat.h"
118 #include "netinet/ip_frag.h"
119 #include "netinet/ip_state.h"
121 #define MIN(a,b) (((a)<(b))?(a):(b))
124 #define SOCKADDR_IN struct sockaddr_in
126 nat_t
*nat_table
[2][NAT_SIZE
], *nat_instances
= NULL
;
127 static ipnat_t
*nat_list
= NULL
;
128 u_long fr_defnatage
= 1200, /* 10 minutes (600 seconds) */
129 fr_defnaticmpage
= 6; /* 3 seconds */
130 static natstat_t nat_stats
;
131 #if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
132 extern kmutex_t ipf_nat
;
135 static int nat_flushtable
__P((void));
136 static int nat_clearlist
__P((void));
137 static void nat_delete
__P((struct nat
*));
138 static int nat_ifpaddr
__P((nat_t
*, void *, struct in_addr
*));
141 #define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16))
143 #define CALC_SUMD(s1, s2, sd) { \
145 (s1) = ((s1) & 0xffff) + ((s1) >> 16); \
146 (s1) = ((s1) & 0xffff) + ((s1) >> 16); \
148 (s2) = ((s2) & 0xffff) + ((s2) >> 16); \
149 (s2) = ((s2) & 0xffff) + ((s2) >> 16); \
150 /* Because ~1 == -2, We really need ~1 == -1 */ \
151 if ((s1) > (s2)) (s2)--; \
152 (sd) = (s2) - (s1); \
153 (sd) = ((sd) & 0xffff) + ((sd) >> 16); }
155 void fix_outcksum(sp
, n
)
159 register u_short sumshort
;
160 register u_32_t sum1
;
164 sum1
= (~ntohs(*sp
)) & 0xffff;
166 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
168 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
169 sumshort
= ~(u_short
)sum1
;
170 *(sp
) = htons(sumshort
);
174 void fix_incksum(sp
, n
)
178 register u_short sumshort
;
179 register u_32_t sum1
;
184 sum1
= (~(*sp
)) & 0xffff;
186 sum1
= (~ntohs(*sp
)) & 0xffff;
188 sum1
+= ~(n
) & 0xffff;
189 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
191 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
192 sumshort
= ~(u_short
)sum1
;
193 *(sp
) = htons(sumshort
);
198 * How the NAT is organised and works.
200 * Inside (interface y) NAT Outside (interface x)
201 * -------------------- -+- -------------------------------------
202 * Packet going | out, processsed by ip_natout() for x
203 * ------------> | ------------>
204 * src=10.1.1.1 | src=192.1.1.1
206 * | in, processed by ip_natin() for x
207 * <------------ | <------------
208 * dst=10.1.1.1 | dst=192.1.1.1
209 * -------------------- -+- -------------------------------------
210 * ip_natout() - changes ip_src and if required, sport
211 * - creates a new mapping, if required.
212 * ip_natin() - changes ip_dst and if required, dport
214 * In the NAT table, internal source is recorded as "in" and externally
219 * Handle ioctls which manipulate the NAT.
221 int nat_ioctl(data
, cmd
, mode
)
222 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
230 register ipnat_t
*nat
, *n
= NULL
, **np
= NULL
;
233 #if defined(_KERNEL) && !SOLARIS
237 nat
= NULL
; /* XXX gcc -Wuninitialized */
240 * For add/delete, look to see if the NAT entry is already present
243 MUTEX_ENTER(&ipf_nat
);
244 if ((cmd
== SIOCADNAT
) || (cmd
== SIOCRMNAT
)) {
245 IRCOPY(data
, (char *)&natd
, sizeof(natd
));
247 nat
->in_inip
&= nat
->in_inmsk
;
248 nat
->in_outip
&= nat
->in_outmsk
;
249 for (np
= &nat_list
; (n
= *np
); np
= &n
->in_next
)
250 if (!bcmp((char *)&nat
->in_flags
, (char *)&n
->in_flags
,
258 if (!(mode
& FWRITE
)) {
266 KMALLOC(n
, ipnat_t
*, sizeof(*n
));
271 bcopy((char *)nat
, (char *)n
, sizeof(*n
));
272 n
->in_ifp
= (void *)GETUNIT(n
->in_ifname
);
274 n
->in_ifp
= (void *)-1;
275 n
->in_apr
= ap_match(n
->in_p
, n
->in_plabel
);
278 n
->in_space
= ~(0xffffffff & ntohl(n
->in_outmsk
));
279 if (n
->in_space
) /* lose 2: broadcast + network address */
282 n
->in_space
= 1; /* single IP# mapping */
283 if ((n
->in_outmsk
!= 0xffffffff) && n
->in_outmsk
)
284 n
->in_nip
= ntohl(n
->in_outip
) + 1;
286 n
->in_nip
= ntohl(n
->in_outip
);
287 if (n
->in_redir
& NAT_MAP
) {
288 n
->in_pnext
= ntohs(n
->in_pmin
);
290 * Multiply by the number of ports made available.
292 if (ntohs(n
->in_pmax
) > ntohs(n
->in_pmin
))
293 n
->in_space
*= (ntohs(n
->in_pmax
) -
296 /* Otherwise, these fields are preset */
298 nat_stats
.ns_rules
++;
301 if (!(mode
& FWRITE
)) {
314 nat_stats
.ns_rules
--;
316 n
->in_flags
|= IPN_DELETE
;
321 nat_stats
.ns_table
[0] = nat_table
[0];
322 nat_stats
.ns_table
[1] = nat_table
[1];
323 nat_stats
.ns_list
= nat_list
;
324 IWCOPY((char *)&nat_stats
, (char *)data
, sizeof(nat_stats
));
330 IRCOPY((char *)data
, (char *)&nl
, sizeof(nl
));
332 if (nat_lookupredir(&nl
)) {
333 IWCOPY((char *)&nl
, (char *)data
, sizeof(nl
));
339 if (!(mode
& FWRITE
)) {
343 ret
= nat_flushtable();
345 IWCOPY((caddr_t
)&ret
, data
, sizeof(ret
));
348 if (!(mode
& FWRITE
)) {
352 ret
= nat_clearlist();
353 IWCOPY((caddr_t
)&ret
, data
, sizeof(ret
));
357 IWCOPY((caddr_t
)&iplused
[IPL_LOGNAT
], (caddr_t
)data
,
358 sizeof(iplused
[IPL_LOGNAT
]));
362 MUTEX_EXIT(&ipf_nat
);
369 * Delete a nat entry from the various lists and table.
371 static void nat_delete(natd
)
374 register struct nat
**natp
, *nat
;
377 for (natp
= natd
->nat_hstart
[0]; (nat
= *natp
);
378 natp
= &nat
->nat_hnext
[0])
380 *natp
= nat
->nat_hnext
[0];
384 for (natp
= natd
->nat_hstart
[1]; (nat
= *natp
);
385 natp
= &nat
->nat_hnext
[1])
387 *natp
= nat
->nat_hnext
[1];
392 * If there is an active reference from the nat entry to its parent
393 * rule, decrement the rule's reference count and free it too if no
396 if ((ipn
= natd
->nat_ptr
)) {
399 if (!ipn
->in_use
&& (ipn
->in_flags
& IPN_DELETE
)) {
401 ap_free(ipn
->in_apr
);
403 nat_stats
.ns_rules
--;
408 * If there's a fragment table entry too for this nat entry, then
409 * dereference that as well.
411 ipfr_forget((void *)natd
);
417 * nat_flushtable - clear the NAT table of all mapping entries.
419 static int nat_flushtable()
421 register nat_t
*nat
, **natp
;
425 * Everything will be deleted, so lets just make it the deletions
428 bzero((char *)nat_table
[0], sizeof(nat_table
[0]));
429 bzero((char *)nat_table
[1], sizeof(nat_table
[1]));
431 for (natp
= &nat_instances
; (nat
= *natp
); ) {
432 *natp
= nat
->nat_next
;
442 * nat_clearlist - delete all entries in the active NAT mapping list.
444 static int nat_clearlist()
446 register ipnat_t
*n
, **np
= &nat_list
;
455 nat_stats
.ns_rules
--;
458 n
->in_flags
|= IPN_DELETE
;
462 nat_stats
.ns_inuse
= 0;
468 * return the first IP Address associated with an interface
470 static int nat_ifpaddr(nat
, ifptr
, inp
)
478 struct ifnet
*ifp
= ifptr
;
483 in
.s_addr
= ntohl(ill
->ill_ipif
->ipif_local_addr
);
489 struct sockaddr_in
*sin
;
491 # if (__FreeBSD_version >= 300000)
492 ifa
= TAILQ_FIRST(&ifp
->if_addrhead
);
494 # if defined(__NetBSD__) || defined(__OpenBSD__)
495 ifa
= ifp
->if_addrlist
.tqh_first
;
497 # if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
498 ifa
= &((struct in_ifaddr
*)ifp
->in_ifaddr
)->ia_ifa
;
500 ifa
= ifp
->if_addrlist
;
502 # endif /* __NetBSD__ || __OpenBSD__ */
503 # endif /* __FreeBSD_version >= 300000 */
504 # if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK))
505 sin
= (SOCKADDR_IN
*)&ifa
->ifa_addr
;
507 sin
= (SOCKADDR_IN
*)ifa
->ifa_addr
;
509 sin
->sin_family
!= AF_INET
) {
510 # if (__FreeBSD_version >= 300000)
511 ifa
= TAILQ_NEXT(ifa
, ifa_link
);
513 # if defined(__NetBSD__) || defined(__OpenBSD__)
514 ifa
= ifa
->ifa_list
.tqe_next
;
518 # endif /* __FreeBSD_version >= 300000 */
520 sin
= (SOCKADDR_IN
*)ifa
->ifa_addr
;
528 # endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */
530 in
.s_addr
= ntohl(in
.s_addr
);
539 * Create a new NAT table entry.
541 nat_t
*nat_new(np
, ip
, fin
, flags
, direction
)
548 register u_32_t sum1
, sum2
, sumd
, l
;
549 u_short port
= 0, sport
= 0, dport
= 0, nport
= 0;
551 tcphdr_t
*tcp
= NULL
;
555 nflags
= flags
& np
->in_flags
;
556 if (flags
& IPN_TCPUDP
) {
557 tcp
= (tcphdr_t
*)fin
->fin_dp
;
558 sport
= tcp
->th_sport
;
559 dport
= tcp
->th_dport
;
562 /* Give me a new nat */
563 KMALLOC(nat
, nat_t
*, sizeof(*nat
));
567 bzero((char *)nat
, sizeof(*nat
));
568 nat
->nat_flags
= flags
;
571 * Search the current table for a match.
573 if (direction
== NAT_OUTBOUND
) {
575 * If it's an outbound packet which doesn't match any existing
576 * record, then create a new port
582 in
.s_addr
= np
->in_nip
;
583 if (!in
.s_addr
&& (np
->in_outmsk
== 0xffffffff)) {
585 nat_ifpaddr(nat
, fin
->fin_ifp
, &in
) == -1) {
589 } else if (!in
.s_addr
&& !np
->in_outmsk
) {
594 in
.s_addr
= ntohl(ip
->ip_src
.s_addr
);
595 if (nflags
& IPN_TCPUDP
)
597 } else if (nflags
& IPN_TCPUDP
) {
598 port
= htons(np
->in_pnext
++);
599 if (np
->in_pnext
>= ntohs(np
->in_pmax
)) {
600 np
->in_pnext
= ntohs(np
->in_pmin
);
602 if (np
->in_outmsk
!= 0xffffffff)
605 } else if (np
->in_outmsk
!= 0xffffffff) {
610 if (!port
&& (flags
& IPN_TCPUDP
))
612 if ((np
->in_nip
& ntohl(np
->in_outmsk
)) >
614 np
->in_nip
= ntohl(np
->in_outip
) + 1;
615 } while (nat_inlookup(fin
->fin_ifp
, flags
, ip
->ip_dst
,
618 /* Setup the NAT table */
619 nat
->nat_inip
= ip
->ip_src
;
620 nat
->nat_outip
.s_addr
= htonl(in
.s_addr
);
621 nat
->nat_oip
= ip
->ip_dst
;
623 sum1
= (ntohl(ip
->ip_src
.s_addr
) & 0xffff) +
624 (ntohl(ip
->ip_src
.s_addr
) >> 16) + ntohs(sport
);
626 sum2
= (in
.s_addr
& 0xffff) + (in
.s_addr
>> 16) + ntohs(port
);
628 if (flags
& IPN_TCPUDP
) {
629 nat
->nat_inport
= sport
;
630 nat
->nat_outport
= port
;
631 nat
->nat_oport
= dport
;
636 * Otherwise, it's an inbound packet. Most likely, we don't
637 * want to rewrite source ports and source addresses. Instead,
638 * we want to rewrite to a fixed internal address and fixed
641 in
.s_addr
= ntohl(np
->in_inip
);
642 if (!(nport
= np
->in_pnext
))
645 nat
->nat_inip
.s_addr
= htonl(in
.s_addr
);
646 nat
->nat_outip
= ip
->ip_dst
;
647 nat
->nat_oip
= ip
->ip_src
;
649 sum1
= (ntohl(ip
->ip_dst
.s_addr
) & 0xffff) +
650 (ntohl(ip
->ip_dst
.s_addr
) >> 16) + ntohs(dport
);
652 sum2
= (in
.s_addr
& 0xffff) + (in
.s_addr
>> 16) + ntohs(nport
);
654 if (flags
& IPN_TCPUDP
) {
655 nat
->nat_inport
= nport
;
656 nat
->nat_outport
= dport
;
657 nat
->nat_oport
= sport
;
662 sum1
= (sum1
& 0xffff) + (sum1
>> 16);
663 sum1
= (sum1
& 0xffff) + (sum1
>> 16);
666 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
667 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
670 sum2
--; /* Because ~1 == -2, We really need ~1 == -1 */
672 sumd
= (sumd
& 0xffff) + (sumd
>> 16);
673 nat
->nat_sumd
= (sumd
& 0xffff) + (sumd
>> 16);
675 if ((flags
& IPN_TCPUDP
) && ((sport
!= port
) || (dport
!= nport
))) {
676 if (direction
== NAT_OUTBOUND
)
677 sum1
= (ntohl(ip
->ip_src
.s_addr
) & 0xffff) +
678 (ntohl(ip
->ip_src
.s_addr
) >> 16);
680 sum1
= (ntohl(ip
->ip_dst
.s_addr
) & 0xffff) +
681 (ntohl(ip
->ip_dst
.s_addr
) >> 16);
683 sum2
= (in
.s_addr
& 0xffff) + (in
.s_addr
>> 16);
686 sum1
= (sum1
& 0xffff) + (sum1
>> 16);
687 sum1
= (sum1
& 0xffff) + (sum1
>> 16);
690 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
691 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
694 sum2
--; /* Because ~1 == -2, We really need ~1 == -1 */
696 sumd
= (sumd
& 0xffff) + (sumd
>> 16);
697 nat
->nat_ipsumd
= (sumd
& 0xffff) + (sumd
>> 16);
699 nat
->nat_ipsumd
= nat
->nat_sumd
;
701 in
.s_addr
= htonl(in
.s_addr
);
702 nat
->nat_next
= nat_instances
;
704 natp
= &nat_table
[0][nat
->nat_inip
.s_addr
% NAT_SIZE
];
705 nat
->nat_hstart
[0] = natp
;
706 nat
->nat_hnext
[0] = *natp
;
708 natp
= &nat_table
[1][nat
->nat_outip
.s_addr
% NAT_SIZE
];
709 nat
->nat_hstart
[1] = natp
;
710 nat
->nat_hnext
[1] = *natp
;
715 nat
->nat_ifp
= fin
->fin_ifp
;
716 nat
->nat_dir
= direction
;
717 if (direction
== NAT_OUTBOUND
) {
718 if (flags
& IPN_TCPUDP
)
719 tcp
->th_sport
= port
;
721 if (flags
& IPN_TCPUDP
)
722 tcp
->th_dport
= nport
;
724 nat_stats
.ns_added
++;
725 nat_stats
.ns_inuse
++;
731 nat_t
*nat_icmpinlookup(ip
, fin
)
736 tcphdr_t
*tcp
= NULL
;
740 icmp
= (icmphdr_t
*)fin
->fin_dp
;
742 * Does it at least have the return (basic) IP header ?
743 * Only a basic IP header (no options) should be with an ICMP error
746 if ((ip
->ip_hl
!= 5) || (ip
->ip_len
< sizeof(*icmp
) + sizeof(ip_t
)))
748 type
= icmp
->icmp_type
;
750 * If it's not an error type, then return.
752 if ((type
!= ICMP_UNREACH
) && (type
!= ICMP_SOURCEQUENCH
) &&
753 (type
!= ICMP_REDIRECT
) && (type
!= ICMP_TIMXCEED
) &&
754 (type
!= ICMP_PARAMPROB
))
757 oip
= (ip_t
*)((char *)fin
->fin_dp
+ 8);
758 if (oip
->ip_p
== IPPROTO_TCP
)
760 else if (oip
->ip_p
== IPPROTO_UDP
)
762 if (flags
& IPN_TCPUDP
) {
763 tcp
= (tcphdr_t
*)((char *)oip
+ (oip
->ip_hl
<< 2));
764 return nat_inlookup(fin
->fin_ifp
, flags
, oip
->ip_dst
,
765 tcp
->th_dport
, oip
->ip_src
, tcp
->th_sport
);
767 return nat_inlookup(fin
->fin_ifp
, 0, oip
->ip_src
, 0, oip
->ip_dst
, 0);
772 * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP
773 * packet gets correctly recognised.
775 nat_t
*nat_icmpin(ip
, fin
, nflags
)
785 if (!(nat
= nat_icmpinlookup(ip
, fin
)))
788 *nflags
= IPN_ICMPERR
;
789 icmp
= (icmphdr_t
*)fin
->fin_dp
;
790 oip
= (ip_t
*)((char *)icmp
+ 8);
791 if (oip
->ip_p
== IPPROTO_TCP
)
793 else if (oip
->ip_p
== IPPROTO_UDP
)
796 * Need to adjust ICMP header to include the real IP#'s and
797 * port #'s. Only apply a checksum change relative to the
798 * IP address change is it will be modified again in ip_natout
799 * for both address and port. Two checksum changes are
800 * necessary for the two header address changes. Be careful
801 * to only modify the checksum once for the port # and twice
804 if (flags
& IPN_TCPUDP
) {
805 tcphdr_t
*tcp
= (tcphdr_t
*)(oip
+ 1);
806 u_32_t sum1
, sum2
, sumd
;
809 if (nat
->nat_dir
== NAT_OUTBOUND
) {
810 sum1
= LONG_SUM(ntohl(oip
->ip_src
.s_addr
));
813 tcp
->th_sport
= nat
->nat_outport
;
815 sum1
= LONG_SUM(ntohl(oip
->ip_dst
.s_addr
));
818 tcp
->th_dport
= nat
->nat_inport
;
821 sum2
= LONG_SUM(in
.s_addr
);
823 CALC_SUMD(sum1
, sum2
, sumd
);
824 sumd
= (sumd
& 0xffff) + (sumd
>> 16);
826 if (nat
->nat_dir
== NAT_OUTBOUND
) {
827 fix_incksum(&oip
->ip_sum
, sumd
);
828 fix_incksum(&icmp
->icmp_cksum
, sumd
);
830 fix_outcksum(&oip
->ip_sum
, sumd
);
831 fix_outcksum(&icmp
->icmp_cksum
, sumd
);
835 * TCP checksum doesn't make it into the 1st eight
836 * bytes but UDP does.
838 if (ip
->ip_p
== IPPROTO_UDP
) {
839 udphdr_t
*udp
= (udphdr_t
*)tcp
;
842 if (nat
->nat_dir
== NAT_OUTBOUND
)
843 fix_incksum(&udp
->uh_sum
,
846 fix_outcksum(&udp
->uh_sum
,
851 ip
->ip_dst
= nat
->nat_outip
;
852 nat
->nat_age
= fr_defnaticmpage
;
858 * NB: these lookups don't lock access to the list, it assume it has already
862 * Lookup a nat entry based on the mapped destination ip address/port and
863 * real source address/port. We use this lookup when receiving a packet,
864 * we're looking for a table entry, based on the destination address.
865 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
868 nat_t
*nat_inlookup(void *ifp
, int flags
, struct in_addr src
, u_short sport
, struct in_addr mapdst
, u_short mapdport
)
870 nat_t
*nat_inlookup(ifp
, flags
, src
, sport
, mapdst
, mapdport
)
873 struct in_addr src
, mapdst
;
874 u_short sport
, mapdport
;
881 nat
= nat_table
[1][mapdst
.s_addr
% NAT_SIZE
];
882 for (; nat
; nat
= nat
->nat_hnext
[1])
883 if ((!ifp
|| ifp
== nat
->nat_ifp
) &&
884 nat
->nat_oip
.s_addr
== src
.s_addr
&&
885 nat
->nat_outip
.s_addr
== mapdst
.s_addr
&&
886 flags
== nat
->nat_flags
&& (!flags
||
887 (nat
->nat_oport
== sport
&&
888 nat
->nat_outport
== mapdport
)))
895 * Lookup a nat entry based on the source 'real' ip address/port and
896 * destination address/port. We use this lookup when sending a packet out,
897 * we're looking for a table entry, based on the source address.
898 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
901 nat_t
*nat_outlookup(void *ifp
, int flags
, struct in_addr src
, u_short sport
, struct in_addr dst
, u_short dport
)
903 nat_t
*nat_outlookup(ifp
, flags
, src
, sport
, dst
, dport
)
906 struct in_addr src
, dst
;
907 u_short sport
, dport
;
914 nat
= nat_table
[0][src
.s_addr
% NAT_SIZE
];
915 for (; nat
; nat
= nat
->nat_hnext
[0]) {
916 if ((!ifp
|| ifp
== nat
->nat_ifp
) &&
917 nat
->nat_inip
.s_addr
== src
.s_addr
&&
918 nat
->nat_oip
.s_addr
== dst
.s_addr
&&
919 flags
== nat
->nat_flags
&& (!flags
||
920 (nat
->nat_inport
== sport
&& nat
->nat_oport
== dport
)))
928 * Lookup a nat entry based on the mapped source ip address/port and
929 * real destination address/port. We use this lookup when sending a packet
930 * out, we're looking for a table entry, based on the source address.
933 nat_t
*nat_lookupmapip(void *ifp
, int flags
, struct in_addr mapsrc
, u_short mapsport
, struct in_addr dst
, u_short dport
)
935 nat_t
*nat_lookupmapip(ifp
, flags
, mapsrc
, mapsport
, dst
, dport
)
938 struct in_addr mapsrc
, dst
;
939 u_short mapsport
, dport
;
946 nat
= nat_table
[1][mapsrc
.s_addr
% NAT_SIZE
];
947 for (; nat
; nat
= nat
->nat_hnext
[0])
948 if ((!ifp
|| ifp
== nat
->nat_ifp
) &&
949 nat
->nat_oip
.s_addr
== dst
.s_addr
&&
950 nat
->nat_outip
.s_addr
== mapsrc
.s_addr
&&
951 flags
== nat
->nat_flags
&& (!flags
||
952 (nat
->nat_outport
== mapsport
&&
953 nat
->nat_oport
== dport
)))
960 * Lookup the NAT tables to search for a matching redirect
962 nat_t
*nat_lookupredir(np
)
963 register natlookup_t
*np
;
968 * If nl_inip is non null, this is a lookup based on the real
969 * ip address. Else, we use the fake.
971 if ((nat
= nat_outlookup(NULL
, np
->nl_flags
, np
->nl_inip
,
972 np
->nl_inport
, np
->nl_outip
,
974 np
->nl_realip
= nat
->nat_outip
;
975 np
->nl_realport
= nat
->nat_outport
;
982 * Packets going out on the external interface go through this.
983 * Here, the source address requires alteration, if anything.
985 int ip_natout(ip
, hlen
, fin
)
990 register ipnat_t
*np
;
992 tcphdr_t
*tcp
= NULL
;
993 u_short nflags
= 0, sport
= 0, dport
= 0, *csump
= NULL
;
999 if ((fr
= fin
->fin_fr
) && !(fr
->fr_flags
& FR_DUP
) &&
1000 fr
->fr_tif
.fd_ifp
&& fr
->fr_tif
.fd_ifp
!= (void *)-1)
1001 ifp
= fr
->fr_tif
.fd_ifp
;
1005 if (!(ip
->ip_off
& 0x1fff) && !(fin
->fin_fi
.fi_fl
& FI_SHORT
)) {
1006 if (ip
->ip_p
== IPPROTO_TCP
)
1008 else if (ip
->ip_p
== IPPROTO_UDP
)
1011 tcp
= (tcphdr_t
*)fin
->fin_dp
;
1012 sport
= tcp
->th_sport
;
1013 dport
= tcp
->th_dport
;
1017 ipa
= ip
->ip_src
.s_addr
;
1019 MUTEX_ENTER(&ipf_nat
);
1020 if ((ip
->ip_off
& (IP_OFFMASK
|IP_MF
)) &&
1021 (nat
= ipfr_nat_knownfrag(ip
, fin
)))
1023 else if ((nat
= nat_outlookup(ifp
, nflags
, ip
->ip_src
, sport
,
1024 ip
->ip_dst
, dport
)))
1028 * If there is no current entry in the nat table for this IP#,
1029 * create one for it (if there is a matching rule).
1031 for (np
= nat_list
; np
; np
= np
->in_next
)
1032 if ((np
->in_ifp
== ifp
) && np
->in_space
&&
1033 (!np
->in_flags
|| (np
->in_flags
& nflags
)) &&
1034 ((ipa
& np
->in_inmsk
) == np
->in_inip
) &&
1035 ((np
->in_redir
& NAT_MAP
) ||
1036 (np
->in_pnext
== sport
))) {
1037 if (*np
->in_plabel
&& !ap_ok(ip
, tcp
, np
))
1040 * If it's a redirection, then we don't want to
1041 * create new outgoing port stuff.
1042 * Redirections are only for incoming
1045 if (!(np
->in_redir
& NAT_MAP
))
1047 if ((nat
= nat_new(np
, ip
, fin
, nflags
,
1050 nat_log(nat
, (u_short
)np
->in_redir
);
1058 if (natadd
&& fin
->fin_fi
.fi_fl
& FI_FRAG
)
1059 ipfr_nat_newfrag(ip
, fin
, 0, nat
);
1060 nat
->nat_age
= fr_defnatage
;
1061 ip
->ip_src
= nat
->nat_outip
;
1062 nat
->nat_bytes
+= ip
->ip_len
;
1066 * Fix up checksums, not by recalculating them, but
1067 * simply computing adjustments.
1069 #if SOLARIS || defined(__sgi)
1070 if (nat
->nat_dir
== NAT_OUTBOUND
)
1071 fix_outcksum(&ip
->ip_sum
, nat
->nat_ipsumd
);
1073 fix_incksum(&ip
->ip_sum
, nat
->nat_ipsumd
);
1076 if (nflags
&& !(ip
->ip_off
& 0x1fff) &&
1077 !(fin
->fin_fi
.fi_fl
& FI_SHORT
)) {
1079 if (nat
->nat_outport
)
1080 tcp
->th_sport
= nat
->nat_outport
;
1082 if (ip
->ip_p
== IPPROTO_TCP
) {
1083 csump
= &tcp
->th_sum
;
1084 fr_tcp_age(&nat
->nat_age
,
1085 nat
->nat_state
, ip
, fin
,1);
1087 * Increase this because we may have
1088 * "keep state" following this too and
1089 * packet storms can occur if this is
1090 * removed too quickly.
1092 if (nat
->nat_age
== fr_tcpclosed
)
1093 nat
->nat_age
= fr_tcplastack
;
1094 } else if (ip
->ip_p
== IPPROTO_UDP
) {
1095 udphdr_t
*udp
= (udphdr_t
*)tcp
;
1098 csump
= &udp
->uh_sum
;
1099 } else if (ip
->ip_p
== IPPROTO_ICMP
) {
1100 icmphdr_t
*ic
= (icmphdr_t
*)tcp
;
1102 csump
= &ic
->icmp_cksum
;
1105 if (nat
->nat_dir
== NAT_OUTBOUND
)
1113 (void) ap_check(ip
, tcp
, fin
, nat
);
1114 nat_stats
.ns_mapped
[1]++;
1115 MUTEX_EXIT(&ipf_nat
);
1118 MUTEX_EXIT(&ipf_nat
);
1124 * Packets coming in from the external interface go through this.
1125 * Here, the destination address requires alteration, if anything.
1127 int ip_natin(ip
, hlen
, fin
)
1132 register ipnat_t
*np
;
1133 register struct in_addr in
;
1134 struct ifnet
*ifp
= fin
->fin_ifp
;
1135 tcphdr_t
*tcp
= NULL
;
1136 u_short sport
= 0, dport
= 0, *csump
= NULL
;
1138 int nflags
= 0, natadd
= 1;
1140 if (!(ip
->ip_off
& 0x1fff) && !(fin
->fin_fi
.fi_fl
& FI_SHORT
)) {
1141 if (ip
->ip_p
== IPPROTO_TCP
)
1143 else if (ip
->ip_p
== IPPROTO_UDP
)
1146 tcp
= (tcphdr_t
*)((char *)ip
+ hlen
);
1147 dport
= tcp
->th_dport
;
1148 sport
= tcp
->th_sport
;
1154 MUTEX_ENTER(&ipf_nat
);
1156 if ((ip
->ip_p
== IPPROTO_ICMP
) && (nat
= nat_icmpin(ip
, fin
, &nflags
)))
1158 else if ((ip
->ip_off
& IP_OFFMASK
) &&
1159 (nat
= ipfr_nat_knownfrag(ip
, fin
)))
1161 else if ((nat
= nat_inlookup(fin
->fin_ifp
, nflags
, ip
->ip_src
, sport
,
1162 ip
->ip_dst
, dport
)))
1166 * If there is no current entry in the nat table for this IP#,
1167 * create one for it (if there is a matching rule).
1169 for (np
= nat_list
; np
; np
= np
->in_next
)
1170 if ((np
->in_ifp
== ifp
) &&
1171 (!np
->in_flags
|| (nflags
& np
->in_flags
)) &&
1172 ((in
.s_addr
& np
->in_outmsk
) == np
->in_outip
) &&
1173 (np
->in_redir
& NAT_REDIRECT
) &&
1174 (!np
->in_pmin
|| np
->in_pmin
== dport
)) {
1175 if ((nat
= nat_new(np
, ip
, fin
, nflags
,
1178 nat_log(nat
, (u_short
)np
->in_redir
);
1185 if (natadd
&& fin
->fin_fi
.fi_fl
& FI_FRAG
)
1186 ipfr_nat_newfrag(ip
, fin
, 0, nat
);
1187 (void) ap_check(ip
, tcp
, fin
, nat
);
1189 if (nflags
!= IPN_ICMPERR
)
1190 nat
->nat_age
= fr_defnatage
;
1192 ip
->ip_dst
= nat
->nat_inip
;
1193 nat
->nat_bytes
+= ip
->ip_len
;
1197 * Fix up checksums, not by recalculating them, but
1198 * simply computing adjustments.
1200 #if SOLARIS || defined(__sgi)
1201 if (nat
->nat_dir
== NAT_OUTBOUND
)
1202 fix_incksum(&ip
->ip_sum
, nat
->nat_ipsumd
);
1204 fix_outcksum(&ip
->ip_sum
, nat
->nat_ipsumd
);
1206 if ((nflags
& IPN_TCPUDP
) && !(ip
->ip_off
& 0x1fff) &&
1207 !(fin
->fin_fi
.fi_fl
& FI_SHORT
)) {
1209 if (nat
->nat_inport
)
1210 tcp
->th_dport
= nat
->nat_inport
;
1212 if (ip
->ip_p
== IPPROTO_TCP
) {
1213 csump
= &tcp
->th_sum
;
1214 fr_tcp_age(&nat
->nat_age
,
1215 nat
->nat_state
, ip
, fin
,0);
1217 * Increase this because we may have
1218 * "keep state" following this too and
1219 * packet storms can occur if this is
1220 * removed too quickly.
1222 if (nat
->nat_age
== fr_tcpclosed
)
1223 nat
->nat_age
= fr_tcplastack
;
1224 } else if (ip
->ip_p
== IPPROTO_UDP
) {
1225 udphdr_t
*udp
= (udphdr_t
*)tcp
;
1228 csump
= &udp
->uh_sum
;
1229 } else if (ip
->ip_p
== IPPROTO_ICMP
) {
1230 icmphdr_t
*ic
= (icmphdr_t
*)tcp
;
1232 csump
= &ic
->icmp_cksum
;
1235 if (nat
->nat_dir
== NAT_OUTBOUND
)
1243 nat_stats
.ns_mapped
[0]++;
1244 MUTEX_EXIT(&ipf_nat
);
1247 MUTEX_EXIT(&ipf_nat
);
1253 * Free all memory used by NAT structures allocated at runtime.
1257 MUTEX_ENTER(&ipf_nat
);
1258 (void) nat_clearlist();
1259 (void) nat_flushtable();
1261 MUTEX_EXIT(&ipf_nat
);
1266 * Slowly expire held state for NAT entries. Timeouts are set in
1267 * expectation of this being called twice per second.
1271 register struct nat
*nat
, **natp
;
1272 #if defined(_KERNEL) && !SOLARIS
1277 MUTEX_ENTER(&ipf_nat
);
1278 for (natp
= &nat_instances
; (nat
= *natp
); ) {
1279 if (--nat
->nat_age
) {
1280 natp
= &nat
->nat_next
;
1283 *natp
= nat
->nat_next
;
1285 nat_log(nat
, NL_EXPIRE
);
1288 nat_stats
.ns_expire
++;
1293 MUTEX_EXIT(&ipf_nat
);
1301 void ip_natsync(void *ifp
)
1303 void ip_natsync(ifp
)
1307 register nat_t
*nat
;
1308 register u_32_t sum1
, sum2
, sumd
;
1311 #if defined(_KERNEL) && !SOLARIS
1316 MUTEX_ENTER(&ipf_nat
);
1317 for (nat
= nat_instances
; nat
; nat
= nat
->nat_next
)
1318 if ((ifp
== nat
->nat_ifp
) && (np
= nat
->nat_ptr
))
1319 if ((np
->in_outmsk
== 0xffffffff) && !np
->in_nip
) {
1321 * Change the map-to address to be the same
1324 sum1
= nat
->nat_outip
.s_addr
;
1325 if (nat_ifpaddr(nat
, ifp
, &in
) == -1)
1326 nat
->nat_outip
.s_addr
= htonl(in
.s_addr
);
1327 sum2
= nat
->nat_outip
.s_addr
;
1330 * Readjust the checksum adjustment to take
1331 * into account the new IP#.
1335 sum1
= (sum1
& 0xffff) + (sum1
>> 16);
1336 sum1
= (sum1
& 0xffff) + (sum1
>> 16);
1339 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
1340 sum2
= (sum2
& 0xffff) + (sum2
>> 16);
1342 /* Because ~1 == -2, We really need ~1 == -1 */
1346 sumd
= (sumd
& 0xffff) + (sumd
>> 16);
1347 sumd
+= nat
->nat_sumd
;
1348 nat
->nat_sumd
= (sumd
& 0xffff) + (sumd
>> 16);
1350 MUTEX_EXIT(&ipf_nat
);
1357 void nat_log(struct nat
*nat
, u_short type
)
1359 void nat_log(nat
, type
)
1368 int rulen
, types
[1];
1370 natl
.nl_inip
= nat
->nat_inip
;
1371 natl
.nl_outip
= nat
->nat_outip
;
1372 natl
.nl_origip
= nat
->nat_oip
;
1373 natl
.nl_bytes
= nat
->nat_bytes
;
1374 natl
.nl_pkts
= nat
->nat_pkts
;
1375 natl
.nl_origport
= nat
->nat_oport
;
1376 natl
.nl_inport
= nat
->nat_inport
;
1377 natl
.nl_outport
= nat
->nat_outport
;
1378 natl
.nl_type
= type
;
1381 for (rulen
= 0, np
= nat_list
; np
; np
= np
->in_next
, rulen
++)
1382 if (np
== nat
->nat_ptr
) {
1383 natl
.nl_rule
= rulen
;
1388 sizes
[0] = sizeof(natl
);
1391 (void) ipllog(IPL_LOGNAT
, 0, items
, sizes
, types
, 1);