2 * Copyright (C) 1995-2004 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7 * Use is subject to license terms.
10 #if defined(KERNEL) || defined(_KERNEL)
16 #include <sys/errno.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
21 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
23 # include "opt_ipfilter_log.h"
36 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
37 # include <sys/filio.h>
38 # include <sys/fcntl.h>
40 # include <sys/ioctl.h>
43 # include <sys/fcntl.h>
46 # include <sys/protosw.h>
48 #include <sys/socket.h>
50 # include <sys/systm.h>
51 # if !defined(__SVR4) && !defined(__svr4__)
52 # include <sys/mbuf.h>
55 #if defined(__SVR4) || defined(__svr4__)
56 # include <sys/filio.h>
57 # include <sys/byteorder.h>
59 # include <sys/dditypes.h>
61 # include <sys/stream.h>
62 # include <sys/kmem.h>
64 #if __FreeBSD_version >= 300000
65 # include <sys/queue.h>
68 #if __FreeBSD_version >= 300000
69 # include <net/if_var.h>
70 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
71 # include "opt_ipfilter.h"
77 #include <net/route.h>
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/ip.h>
84 # include <vpn/ipsec.h>
85 extern struct ifnet vpnif
;
89 # include <netinet/ip_var.h>
91 #include <netinet/tcp.h>
92 #include <netinet/udp.h>
93 #include <netinet/ip_icmp.h>
94 #include "netinet/ip_compat.h"
95 #include <netinet/tcpip.h>
96 #include "netinet/ip_fil.h"
97 #include "netinet/ip_nat.h"
98 #include "netinet/ip_frag.h"
99 #include "netinet/ip_state.h"
100 #include "netinet/ip_proxy.h"
101 #include "netinet/ipf_stack.h"
103 #include "netinet/ip_sync.h"
105 #if (__FreeBSD_version >= 300000)
106 # include <sys/malloc.h>
108 /* END OF INCLUDES */
111 #define SOCKADDR_IN struct sockaddr_in
114 static const char sccsid
[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
115 static const char rcsid
[] = "@(#)$Id: ip_nat.c,v 2.195.2.42 2005/08/11 19:51:36 darrenr Exp $";
119 /* ======================================================================== */
120 /* How the NAT is organised and works. */
122 /* Inside (interface y) NAT Outside (interface x) */
123 /* -------------------- -+- ------------------------------------- */
124 /* Packet going | out, processsed by fr_checknatout() for x */
125 /* ------------> | ------------> */
126 /* src=10.1.1.1 | src=192.1.1.1 */
128 /* | in, processed by fr_checknatin() for x */
129 /* <------------ | <------------ */
130 /* dst=10.1.1.1 | dst=192.1.1.1 */
131 /* -------------------- -+- ------------------------------------- */
132 /* fr_checknatout() - changes ip_src and if required, sport */
133 /* - creates a new mapping, if required. */
134 /* fr_checknatin() - changes ip_dst and if required, dport */
136 /* In the NAT table, internal source is recorded as "in" and externally */
138 /* ======================================================================== */
141 static int nat_clearlist
__P((ipf_stack_t
*));
142 static void nat_addnat
__P((struct ipnat
*, ipf_stack_t
*));
143 static void nat_addrdr
__P((struct ipnat
*, ipf_stack_t
*));
144 static int fr_natgetent
__P((caddr_t
, ipf_stack_t
*));
145 static int fr_natgetsz
__P((caddr_t
, ipf_stack_t
*));
146 static int fr_natputent
__P((caddr_t
, int, ipf_stack_t
*));
147 static void nat_tabmove
__P((nat_t
*, ipf_stack_t
*));
148 static int nat_match
__P((fr_info_t
*, ipnat_t
*));
149 static INLINE
int nat_newmap
__P((fr_info_t
*, nat_t
*, natinfo_t
*));
150 static INLINE
int nat_newrdr
__P((fr_info_t
*, nat_t
*, natinfo_t
*));
151 static hostmap_t
*nat_hostmap
__P((ipnat_t
*, struct in_addr
,
152 struct in_addr
, struct in_addr
, u_32_t
,
154 static INLINE
int nat_icmpquerytype4
__P((int));
155 static int nat_ruleaddrinit
__P((ipnat_t
*));
156 static int nat_siocaddnat
__P((ipnat_t
*, ipnat_t
**, int, ipf_stack_t
*));
157 static void nat_siocdelnat
__P((ipnat_t
*, ipnat_t
**, int, ipf_stack_t
*));
158 static INLINE
int nat_icmperrortype4
__P((int));
159 static INLINE
int nat_finalise
__P((fr_info_t
*, nat_t
*, natinfo_t
*,
160 tcphdr_t
*, nat_t
**, int));
161 static INLINE
int nat_resolverule
__P((ipnat_t
*, ipf_stack_t
*));
162 static void nat_mssclamp
__P((tcphdr_t
*, u_32_t
, u_short
*));
163 static int nat_getnext
__P((ipftoken_t
*, ipfgeniter_t
*, ipf_stack_t
*));
164 static int nat_iterator
__P((ipftoken_t
*, ipfgeniter_t
*, ipf_stack_t
*));
165 static int nat_flushtable
__P((int, ipf_stack_t
*));
167 #define NAT_HAS_L4_CHANGED(n) \
168 (((n)->nat_flags & (IPN_TCPUDPICMP)) && \
169 (n)->nat_inport != (n)->nat_outport)
172 /* ------------------------------------------------------------------------ */
173 /* Function: fr_natinit */
174 /* Returns: int - 0 == success, -1 == failure */
175 /* Parameters: Nil */
177 /* Initialise all of the NAT locks, tables and other structures. */
178 /* ------------------------------------------------------------------------ */
184 KMALLOCS(ifs
->ifs_nat_table
[0], nat_t
**,
185 sizeof(nat_t
*) * ifs
->ifs_ipf_nattable_sz
);
186 if (ifs
->ifs_nat_table
[0] != NULL
)
187 bzero((char *)ifs
->ifs_nat_table
[0],
188 ifs
->ifs_ipf_nattable_sz
* sizeof(nat_t
*));
192 KMALLOCS(ifs
->ifs_nat_table
[1], nat_t
**,
193 sizeof(nat_t
*) * ifs
->ifs_ipf_nattable_sz
);
194 if (ifs
->ifs_nat_table
[1] != NULL
)
195 bzero((char *)ifs
->ifs_nat_table
[1],
196 ifs
->ifs_ipf_nattable_sz
* sizeof(nat_t
*));
200 KMALLOCS(ifs
->ifs_nat_rules
, ipnat_t
**,
201 sizeof(ipnat_t
*) * ifs
->ifs_ipf_natrules_sz
);
202 if (ifs
->ifs_nat_rules
!= NULL
)
203 bzero((char *)ifs
->ifs_nat_rules
,
204 ifs
->ifs_ipf_natrules_sz
* sizeof(ipnat_t
*));
208 KMALLOCS(ifs
->ifs_rdr_rules
, ipnat_t
**,
209 sizeof(ipnat_t
*) * ifs
->ifs_ipf_rdrrules_sz
);
210 if (ifs
->ifs_rdr_rules
!= NULL
)
211 bzero((char *)ifs
->ifs_rdr_rules
,
212 ifs
->ifs_ipf_rdrrules_sz
* sizeof(ipnat_t
*));
216 KMALLOCS(ifs
->ifs_maptable
, hostmap_t
**,
217 sizeof(hostmap_t
*) * ifs
->ifs_ipf_hostmap_sz
);
218 if (ifs
->ifs_maptable
!= NULL
)
219 bzero((char *)ifs
->ifs_maptable
,
220 sizeof(hostmap_t
*) * ifs
->ifs_ipf_hostmap_sz
);
224 ifs
->ifs_ipf_hm_maplist
= NULL
;
226 KMALLOCS(ifs
->ifs_nat_stats
.ns_bucketlen
[0], u_long
*,
227 ifs
->ifs_ipf_nattable_sz
* sizeof(u_long
));
228 if (ifs
->ifs_nat_stats
.ns_bucketlen
[0] == NULL
)
230 bzero((char *)ifs
->ifs_nat_stats
.ns_bucketlen
[0],
231 ifs
->ifs_ipf_nattable_sz
* sizeof(u_long
));
233 KMALLOCS(ifs
->ifs_nat_stats
.ns_bucketlen
[1], u_long
*,
234 ifs
->ifs_ipf_nattable_sz
* sizeof(u_long
));
235 if (ifs
->ifs_nat_stats
.ns_bucketlen
[1] == NULL
)
237 bzero((char *)ifs
->ifs_nat_stats
.ns_bucketlen
[1],
238 ifs
->ifs_ipf_nattable_sz
* sizeof(u_long
));
240 if (ifs
->ifs_fr_nat_maxbucket
== 0) {
241 for (i
= ifs
->ifs_ipf_nattable_sz
; i
> 0; i
>>= 1)
242 ifs
->ifs_fr_nat_maxbucket
++;
243 ifs
->ifs_fr_nat_maxbucket
*= 2;
246 fr_sttab_init(ifs
->ifs_nat_tqb
, ifs
);
248 * Increase this because we may have "keep state" following this too
249 * and packet storms can occur if this is removed too quickly.
251 ifs
->ifs_nat_tqb
[IPF_TCPS_CLOSED
].ifq_ttl
= ifs
->ifs_fr_tcplastack
;
252 ifs
->ifs_nat_tqb
[IPF_TCP_NSTATES
- 1].ifq_next
= &ifs
->ifs_nat_udptq
;
253 ifs
->ifs_nat_udptq
.ifq_ttl
= ifs
->ifs_fr_defnatage
;
254 ifs
->ifs_nat_udptq
.ifq_ref
= 1;
255 ifs
->ifs_nat_udptq
.ifq_head
= NULL
;
256 ifs
->ifs_nat_udptq
.ifq_tail
= &ifs
->ifs_nat_udptq
.ifq_head
;
257 MUTEX_INIT(&ifs
->ifs_nat_udptq
.ifq_lock
, "nat ipftq udp tab");
258 ifs
->ifs_nat_udptq
.ifq_next
= &ifs
->ifs_nat_icmptq
;
259 ifs
->ifs_nat_icmptq
.ifq_ttl
= ifs
->ifs_fr_defnaticmpage
;
260 ifs
->ifs_nat_icmptq
.ifq_ref
= 1;
261 ifs
->ifs_nat_icmptq
.ifq_head
= NULL
;
262 ifs
->ifs_nat_icmptq
.ifq_tail
= &ifs
->ifs_nat_icmptq
.ifq_head
;
263 MUTEX_INIT(&ifs
->ifs_nat_icmptq
.ifq_lock
, "nat icmp ipftq tab");
264 ifs
->ifs_nat_icmptq
.ifq_next
= &ifs
->ifs_nat_iptq
;
265 ifs
->ifs_nat_iptq
.ifq_ttl
= ifs
->ifs_fr_defnatipage
;
266 ifs
->ifs_nat_iptq
.ifq_ref
= 1;
267 ifs
->ifs_nat_iptq
.ifq_head
= NULL
;
268 ifs
->ifs_nat_iptq
.ifq_tail
= &ifs
->ifs_nat_iptq
.ifq_head
;
269 MUTEX_INIT(&ifs
->ifs_nat_iptq
.ifq_lock
, "nat ip ipftq tab");
270 ifs
->ifs_nat_iptq
.ifq_next
= NULL
;
272 for (i
= 0; i
< IPF_TCP_NSTATES
; i
++) {
273 if (ifs
->ifs_nat_tqb
[i
].ifq_ttl
< ifs
->ifs_fr_defnaticmpage
)
274 ifs
->ifs_nat_tqb
[i
].ifq_ttl
= ifs
->ifs_fr_defnaticmpage
;
276 else if (ifs
->ifs_nat_tqb
[i
].ifq_ttl
> ifs
->ifs_fr_defnatage
)
277 ifs
->ifs_nat_tqb
[i
].ifq_ttl
= ifs
->ifs_fr_defnatage
;
282 * Increase this because we may have "keep state" following
283 * this too and packet storms can occur if this is removed
286 ifs
->ifs_nat_tqb
[IPF_TCPS_CLOSED
].ifq_ttl
=
287 ifs
->ifs_nat_tqb
[IPF_TCPS_LAST_ACK
].ifq_ttl
;
289 RWLOCK_INIT(&ifs
->ifs_ipf_nat
, "ipf IP NAT rwlock");
290 RWLOCK_INIT(&ifs
->ifs_ipf_natfrag
, "ipf IP NAT-Frag rwlock");
291 MUTEX_INIT(&ifs
->ifs_ipf_nat_new
, "ipf nat new mutex");
292 MUTEX_INIT(&ifs
->ifs_ipf_natio
, "ipf nat io mutex");
294 ifs
->ifs_fr_nat_init
= 1;
295 ifs
->ifs_nat_last_force_flush
= ifs
->ifs_fr_ticks
;
300 /* ------------------------------------------------------------------------ */
301 /* Function: nat_addrdr */
303 /* Parameters: n(I) - pointer to NAT rule to add */
305 /* Adds a redirect rule to the hash table of redirect rules and the list of */
306 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */
307 /* use by redirect rules. */
308 /* ------------------------------------------------------------------------ */
309 static void nat_addrdr(n
, ifs
)
318 k
= count4bits(n
->in_outmsk
);
319 if ((k
>= 0) && (k
!= 32))
320 ifs
->ifs_rdr_masks
|= 1 << k
;
321 j
= (n
->in_outip
& n
->in_outmsk
);
322 hv
= NAT_HASH_FN(j
, 0, ifs
->ifs_ipf_rdrrules_sz
);
323 np
= ifs
->ifs_rdr_rules
+ hv
;
325 np
= &(*np
)->in_rnext
;
333 /* ------------------------------------------------------------------------ */
334 /* Function: nat_addnat */
336 /* Parameters: n(I) - pointer to NAT rule to add */
338 /* Adds a NAT map rule to the hash table of rules and the list of loaded */
339 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */
340 /* redirect rules. */
341 /* ------------------------------------------------------------------------ */
342 static void nat_addnat(n
, ifs
)
351 k
= count4bits(n
->in_inmsk
);
352 if ((k
>= 0) && (k
!= 32))
353 ifs
->ifs_nat_masks
|= 1 << k
;
354 j
= (n
->in_inip
& n
->in_inmsk
);
355 hv
= NAT_HASH_FN(j
, 0, ifs
->ifs_ipf_natrules_sz
);
356 np
= ifs
->ifs_nat_rules
+ hv
;
358 np
= &(*np
)->in_mnext
;
366 /* ------------------------------------------------------------------------ */
367 /* Function: nat_delrdr */
369 /* Parameters: n(I) - pointer to NAT rule to delete */
371 /* Removes a redirect rule from the hash table of redirect rules. */
372 /* ------------------------------------------------------------------------ */
377 n
->in_rnext
->in_prnext
= n
->in_prnext
;
378 *n
->in_prnext
= n
->in_rnext
;
382 /* ------------------------------------------------------------------------ */
383 /* Function: nat_delnat */
385 /* Parameters: n(I) - pointer to NAT rule to delete */
387 /* Removes a NAT map rule from the hash table of NAT map rules. */
388 /* ------------------------------------------------------------------------ */
392 if (n
->in_mnext
!= NULL
)
393 n
->in_mnext
->in_pmnext
= n
->in_pmnext
;
394 *n
->in_pmnext
= n
->in_mnext
;
398 /* ------------------------------------------------------------------------ */
399 /* Function: nat_hostmap */
400 /* Returns: struct hostmap* - NULL if no hostmap could be created, */
401 /* else a pointer to the hostmapping to use */
402 /* Parameters: np(I) - pointer to NAT rule */
403 /* real(I) - real IP address */
404 /* map(I) - mapped IP address */
405 /* port(I) - destination port number */
406 /* Write Locks: ipf_nat */
408 /* Check if an ip address has already been allocated for a given mapping */
409 /* that is not doing port based translation. If is not yet allocated, then */
410 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */
411 /* ------------------------------------------------------------------------ */
412 static struct hostmap
*nat_hostmap(np
, src
, dst
, map
, port
, ifs
)
423 hv
= (src
.s_addr
^ dst
.s_addr
);
427 for (hm
= ifs
->ifs_maptable
[hv
]; hm
; hm
= hm
->hm_next
)
428 if ((hm
->hm_srcip
.s_addr
== src
.s_addr
) &&
429 (hm
->hm_dstip
.s_addr
== dst
.s_addr
) &&
430 ((np
== NULL
) || (np
== hm
->hm_ipnat
)) &&
431 ((port
== 0) || (port
== hm
->hm_port
))) {
439 KMALLOC(hm
, hostmap_t
*);
441 hm
->hm_hnext
= ifs
->ifs_ipf_hm_maplist
;
442 hm
->hm_phnext
= &ifs
->ifs_ipf_hm_maplist
;
443 if (ifs
->ifs_ipf_hm_maplist
!= NULL
)
444 ifs
->ifs_ipf_hm_maplist
->hm_phnext
= &hm
->hm_hnext
;
445 ifs
->ifs_ipf_hm_maplist
= hm
;
447 hm
->hm_next
= ifs
->ifs_maptable
[hv
];
448 hm
->hm_pnext
= ifs
->ifs_maptable
+ hv
;
449 if (ifs
->ifs_maptable
[hv
] != NULL
)
450 ifs
->ifs_maptable
[hv
]->hm_pnext
= &hm
->hm_next
;
451 ifs
->ifs_maptable
[hv
] = hm
;
464 /* ------------------------------------------------------------------------ */
465 /* Function: fr_hostmapdel */
467 /* Parameters: hmp(I) - pointer to pointer to hostmap structure */
468 /* Write Locks: ipf_nat */
470 /* Decrement the references to this hostmap structure by one. If this */
471 /* reaches zero then remove it and free it. */
472 /* ------------------------------------------------------------------------ */
473 void fr_hostmapdel(hmp
)
474 struct hostmap
**hmp
;
482 if (hm
->hm_ref
== 0) {
484 hm
->hm_next
->hm_pnext
= hm
->hm_pnext
;
485 *hm
->hm_pnext
= hm
->hm_next
;
487 hm
->hm_hnext
->hm_phnext
= hm
->hm_phnext
;
488 *hm
->hm_phnext
= hm
->hm_hnext
;
494 /* ------------------------------------------------------------------------ */
495 /* Function: fix_outcksum */
497 /* Parameters: sp(I) - location of 16bit checksum to update */
498 /* n((I) - amount to adjust checksum by */
500 /* Adjusts the 16bit checksum by "n" for packets going out. */
501 /* ------------------------------------------------------------------------ */
502 void fix_outcksum(sp
, n
)
512 sum1
= (~ntohs(*sp
)) & 0xffff;
514 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
516 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
517 sumshort
= ~(u_short
)sum1
;
518 *(sp
) = htons(sumshort
);
522 /* ------------------------------------------------------------------------ */
523 /* Function: fix_incksum */
525 /* Parameters: sp(I) - location of 16bit checksum to update */
526 /* n((I) - amount to adjust checksum by */
528 /* Adjusts the 16bit checksum by "n" for packets going in. */
529 /* ------------------------------------------------------------------------ */
530 void fix_incksum(sp
, n
)
540 sum1
= (~ntohs(*sp
)) & 0xffff;
541 sum1
+= ~(n
) & 0xffff;
542 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
544 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
545 sumshort
= ~(u_short
)sum1
;
546 *(sp
) = htons(sumshort
);
550 /* ------------------------------------------------------------------------ */
551 /* Function: fix_datacksum */
553 /* Parameters: sp(I) - location of 16bit checksum to update */
554 /* n((I) - amount to adjust checksum by */
556 /* Fix_datacksum is used *only* for the adjustments of checksums in the */
557 /* data section of an IP packet. */
559 /* The only situation in which you need to do this is when NAT'ing an */
560 /* ICMP error message. Such a message, contains in its body the IP header */
561 /* of the original IP packet, that causes the error. */
563 /* You can't use fix_incksum or fix_outcksum in that case, because for the */
564 /* kernel the data section of the ICMP error is just data, and no special */
565 /* processing like hardware cksum or ntohs processing have been done by the */
566 /* kernel on the data section. */
567 /* ------------------------------------------------------------------------ */
568 void fix_datacksum(sp
, n
)
578 sum1
= (~ntohs(*sp
)) & 0xffff;
580 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
582 sum1
= (sum1
>> 16) + (sum1
& 0xffff);
583 sumshort
= ~(u_short
)sum1
;
584 *(sp
) = htons(sumshort
);
588 /* ------------------------------------------------------------------------ */
589 /* Function: fr_nat_ioctl */
590 /* Returns: int - 0 == success, != 0 == failure */
591 /* Parameters: data(I) - pointer to ioctl data */
592 /* cmd(I) - ioctl command integer */
593 /* mode(I) - file mode bits used with open */
594 /* uid(I) - uid of caller */
595 /* ctx(I) - pointer to give the uid context */
596 /* ifs - ipf stack instance */
598 /* Processes an ioctl call made to operate on the IP Filter NAT device. */
599 /* ------------------------------------------------------------------------ */
600 int fr_nat_ioctl(data
, cmd
, mode
, uid
, ctx
, ifs
)
607 ipnat_t
*nat
, *nt
, *n
= NULL
, **np
= NULL
;
608 int error
= 0, ret
, arg
, getlock
;
611 #if (BSD >= 199306) && defined(_KERNEL)
612 if ((securelevel
>= 2) && (mode
& FWRITE
))
616 #if defined(__osf__) && defined(_KERNEL)
619 getlock
= (mode
& NAT_LOCKHELD
) ? 0 : 1;
622 nat
= NULL
; /* XXX gcc -Wuninitialized */
623 if (cmd
== (ioctlcmd_t
)SIOCADNAT
) {
624 KMALLOC(nt
, ipnat_t
*);
629 if ((cmd
== (ioctlcmd_t
)SIOCADNAT
) || (cmd
== (ioctlcmd_t
)SIOCRMNAT
)) {
630 if (mode
& NAT_SYSSPACE
) {
631 bcopy(data
, (char *)&natd
, sizeof(natd
));
634 error
= fr_inobj(data
, &natd
, IPFOBJ_IPNAT
);
643 * For add/delete, look to see if the NAT entry is already present
645 if ((cmd
== (ioctlcmd_t
)SIOCADNAT
) || (cmd
== (ioctlcmd_t
)SIOCRMNAT
)) {
647 if (nat
->in_v
== 0) /* For backward compat. */
649 nat
->in_flags
&= IPN_USERFLAGS
;
650 if ((nat
->in_redir
& NAT_MAPBLK
) == 0) {
651 if ((nat
->in_flags
& IPN_SPLIT
) == 0)
652 nat
->in_inip
&= nat
->in_inmsk
;
653 if ((nat
->in_flags
& IPN_IPRANGE
) == 0)
654 nat
->in_outip
&= nat
->in_outmsk
;
656 MUTEX_ENTER(&ifs
->ifs_ipf_natio
);
657 for (np
= &ifs
->ifs_nat_list
; ((n
= *np
) != NULL
);
659 if (bcmp((char *)&nat
->in_flags
, (char *)&n
->in_flags
,
661 if (nat
->in_redir
== NAT_REDIRECT
&&
662 nat
->in_pnext
!= n
->in_pnext
)
675 error
= fr_inobj(data
, &iter
, IPFOBJ_GENITER
);
679 token
= ipf_findtoken(iter
.igi_type
, uid
, ctx
, ifs
);
681 error
= nat_iterator(token
, &iter
, ifs
);
684 RWLOCK_EXIT(&ifs
->ifs_ipf_tokens
);
692 if (!(mode
& FWRITE
))
695 tmp
= ipflog_clear(IPL_LOGNAT
, ifs
);
696 error
= BCOPYOUT((char *)&tmp
, (char *)data
,
704 if (!(mode
& FWRITE
)) {
707 error
= BCOPYIN((char *)data
,
708 (char *)&ifs
->ifs_nat_logging
,
709 sizeof(ifs
->ifs_nat_logging
));
715 error
= BCOPYOUT((char *)&ifs
->ifs_nat_logging
, (char *)data
,
716 sizeof(ifs
->ifs_nat_logging
));
721 arg
= ifs
->ifs_iplused
[IPL_LOGNAT
];
722 error
= BCOPYOUT(&arg
, data
, sizeof(arg
));
728 if (!(mode
& FWRITE
)) {
730 } else if (n
!= NULL
) {
732 } else if (nt
== NULL
) {
736 MUTEX_EXIT(&ifs
->ifs_ipf_natio
);
739 bcopy((char *)nat
, (char *)nt
, sizeof(*n
));
740 error
= nat_siocaddnat(nt
, np
, getlock
, ifs
);
741 MUTEX_EXIT(&ifs
->ifs_ipf_natio
);
746 if (!(mode
& FWRITE
)) {
749 } else if (n
== NULL
) {
754 MUTEX_EXIT(&ifs
->ifs_ipf_natio
);
757 nat_siocdelnat(n
, np
, getlock
, ifs
);
759 MUTEX_EXIT(&ifs
->ifs_ipf_natio
);
763 ifs
->ifs_nat_stats
.ns_table
[0] = ifs
->ifs_nat_table
[0];
764 ifs
->ifs_nat_stats
.ns_table
[1] = ifs
->ifs_nat_table
[1];
765 ifs
->ifs_nat_stats
.ns_list
= ifs
->ifs_nat_list
;
766 ifs
->ifs_nat_stats
.ns_maptable
= ifs
->ifs_maptable
;
767 ifs
->ifs_nat_stats
.ns_maplist
= ifs
->ifs_ipf_hm_maplist
;
768 ifs
->ifs_nat_stats
.ns_nattab_max
= ifs
->ifs_ipf_nattable_max
;
769 ifs
->ifs_nat_stats
.ns_nattab_sz
= ifs
->ifs_ipf_nattable_sz
;
770 ifs
->ifs_nat_stats
.ns_rultab_sz
= ifs
->ifs_ipf_natrules_sz
;
771 ifs
->ifs_nat_stats
.ns_rdrtab_sz
= ifs
->ifs_ipf_rdrrules_sz
;
772 ifs
->ifs_nat_stats
.ns_hostmap_sz
= ifs
->ifs_ipf_hostmap_sz
;
773 ifs
->ifs_nat_stats
.ns_instances
= ifs
->ifs_nat_instances
;
774 ifs
->ifs_nat_stats
.ns_apslist
= ifs
->ifs_ap_sess_list
;
775 error
= fr_outobj(data
, &ifs
->ifs_nat_stats
, IPFOBJ_NATSTAT
);
782 READ_ENTER(&ifs
->ifs_ipf_nat
);
784 error
= fr_inobj(data
, &nl
, IPFOBJ_NATLOOKUP
);
793 ptr
= nat_lookupredir(&nl
, ifs
);
797 ptr
= nat6_lookupredir(&nl
, ifs
);
806 error
= fr_outobj(data
, &nl
, IPFOBJ_NATLOOKUP
);
812 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
816 case SIOCIPFFL
: /* old SIOCFLNAT & SIOCCNATL */
817 if (!(mode
& FWRITE
)) {
822 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
824 error
= BCOPYIN(data
, &arg
, sizeof(arg
));
828 if (arg
== FLUSH_LIST
)
829 ret
= nat_clearlist(ifs
);
830 else if (VALID_TABLE_FLUSH_OPT(arg
))
831 ret
= nat_flushtable(arg
, ifs
);
836 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
839 error
= BCOPYOUT(&ret
, data
, sizeof(ret
));
845 error
= appr_ioctl(data
, cmd
, mode
, ifs
);
848 if (!(mode
& FWRITE
)) {
851 error
= fr_lock(data
, &ifs
->ifs_fr_nat_lock
);
855 if ((mode
& FWRITE
) != 0) {
856 error
= fr_natputent(data
, getlock
, ifs
);
862 if (ifs
->ifs_fr_nat_lock
) {
864 READ_ENTER(&ifs
->ifs_ipf_nat
);
866 error
= fr_natgetsz(data
, ifs
);
868 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
874 if (ifs
->ifs_fr_nat_lock
) {
876 READ_ENTER(&ifs
->ifs_ipf_nat
);
878 error
= fr_natgetent(data
, ifs
);
880 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
886 error
= BCOPYIN((caddr_t
)data
, (caddr_t
)&arg
, sizeof(arg
));
890 error
= ipf_deltoken(arg
, uid
, ctx
, ifs
);
904 /* ------------------------------------------------------------------------ */
905 /* Function: nat_siocaddnat */
906 /* Returns: int - 0 == success, != 0 == failure */
907 /* Parameters: n(I) - pointer to new NAT rule */
908 /* np(I) - pointer to where to insert new NAT rule */
909 /* getlock(I) - flag indicating if lock on ipf_nat is held */
910 /* Mutex Locks: ipf_natio */
912 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */
913 /* from information passed to the kernel, then add it to the appropriate */
914 /* NAT rule table(s). */
915 /* ------------------------------------------------------------------------ */
916 static int nat_siocaddnat(n
, np
, getlock
, ifs
)
923 if (nat_resolverule(n
, ifs
) != 0)
926 if ((n
->in_age
[0] == 0) && (n
->in_age
[1] != 0))
930 if (n
->in_redir
& NAT_MAPBLK
)
931 n
->in_space
= USABLE_PORTS
* ~ntohl(n
->in_outmsk
);
932 else if (n
->in_flags
& IPN_AUTOPORTMAP
)
933 n
->in_space
= USABLE_PORTS
* ~ntohl(n
->in_inmsk
);
934 else if (n
->in_flags
& IPN_IPRANGE
)
935 n
->in_space
= ntohl(n
->in_outmsk
) - ntohl(n
->in_outip
);
936 else if (n
->in_flags
& IPN_SPLIT
)
938 else if (n
->in_outmsk
!= 0)
939 n
->in_space
= ~ntohl(n
->in_outmsk
);
942 if ((n
->in_flags
& NAT_TCPUDPICMPQ
) && (n
->in_redir
!= NAT_REDIRECT
)) {
943 if (ntohs(n
->in_pmax
) < ntohs(n
->in_pmin
))
948 * Calculate the number of valid IP addresses in the output
949 * mapping range. In all cases, the range is inclusive of
950 * the start and ending IP addresses.
951 * If to a CIDR address, lose 2: broadcast + network address
953 * If to a range, add one.
954 * If to a single IP address, set to 1.
957 if ((n
->in_flags
& IPN_IPRANGE
) != 0)
965 if (n
->in_v
== 6 && (n
->in_flags
& (IPN_IPRANGE
|IPN_SPLIT
)) == 0 &&
966 !IP6_ISONES(&n
->in_out
[1]) && !IP6_ISZERO(&n
->in_out
[1]))
967 IP6_ADD(&n
->in_out
[0], 1, &n
->in_next6
)
968 else if (n
->in_v
== 6 &&
969 (n
->in_flags
& IPN_SPLIT
) && (n
->in_redir
& NAT_REDIRECT
))
970 n
->in_next6
= n
->in_in
[0];
971 else if (n
->in_v
== 6)
972 n
->in_next6
= n
->in_out
[0];
975 if ((n
->in_outmsk
!= 0xffffffff) && (n
->in_outmsk
!= 0) &&
976 ((n
->in_flags
& (IPN_IPRANGE
|IPN_SPLIT
)) == 0))
977 n
->in_nip
= ntohl(n
->in_outip
) + 1;
978 else if ((n
->in_flags
& IPN_SPLIT
) &&
979 (n
->in_redir
& NAT_REDIRECT
))
980 n
->in_nip
= ntohl(n
->in_inip
);
982 n
->in_nip
= ntohl(n
->in_outip
);
984 if (n
->in_redir
& NAT_MAP
) {
985 n
->in_pnext
= ntohs(n
->in_pmin
);
987 * Multiply by the number of ports made available.
989 if (ntohs(n
->in_pmax
) >= ntohs(n
->in_pmin
)) {
990 n
->in_space
*= (ntohs(n
->in_pmax
) -
991 ntohs(n
->in_pmin
) + 1);
993 * Because two different sources can map to
994 * different destinations but use the same
996 * If the result is smaller than in_space, then
997 * we may have wrapped around 32bits.
1000 if ((i
!= 0) && (i
!= 0xffffffff)) {
1001 j
= n
->in_space
* (~ntohl(i
) + 1);
1002 if (j
>= n
->in_space
)
1005 n
->in_space
= 0xffffffff;
1009 * If no protocol is specified, multiple by 256 to allow for
1010 * at least one IP:IP mapping per protocol.
1012 if ((n
->in_flags
& IPN_TCPUDPICMP
) == 0) {
1013 j
= n
->in_space
* 256;
1014 if (j
>= n
->in_space
)
1017 n
->in_space
= 0xffffffff;
1021 /* Otherwise, these fields are preset */
1024 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
1029 if (n
->in_age
[0] != 0)
1030 n
->in_tqehead
[0] = fr_addtimeoutqueue(&ifs
->ifs_nat_utqe
,
1033 if (n
->in_age
[1] != 0)
1034 n
->in_tqehead
[1] = fr_addtimeoutqueue(&ifs
->ifs_nat_utqe
,
1037 if (n
->in_redir
& NAT_REDIRECT
) {
1038 n
->in_flags
&= ~IPN_NOTDST
;
1046 nat6_addrdr(n
, ifs
);
1053 if (n
->in_redir
& (NAT_MAP
|NAT_MAPBLK
)) {
1054 n
->in_flags
&= ~IPN_NOTSRC
;
1062 nat6_addnat(n
, ifs
);
1070 ifs
->ifs_nat_stats
.ns_rules
++;
1072 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
); /* WRITE */
1079 /* ------------------------------------------------------------------------ */
1080 /* Function: nat_resolvrule */
1081 /* Returns: int - 0 == success, -1 == failure */
1082 /* Parameters: n(I) - pointer to NAT rule */
1084 /* Resolve some of the details inside the NAT rule. Includes resolving */
1085 /* any specified interfaces and proxy labels, and determines whether or not */
1086 /* all proxy labels are correctly specified. */
1088 /* Called by nat_siocaddnat() (SIOCADNAT) and fr_natputent (SIOCSTPUT). */
1089 /* ------------------------------------------------------------------------ */
1090 static int nat_resolverule(n
, ifs
)
1094 n
->in_ifnames
[0][LIFNAMSIZ
- 1] = '\0';
1095 n
->in_ifps
[0] = fr_resolvenic(n
->in_ifnames
[0], n
->in_v
, ifs
);
1097 n
->in_ifnames
[1][LIFNAMSIZ
- 1] = '\0';
1098 if (n
->in_ifnames
[1][0] == '\0') {
1099 (void) strncpy(n
->in_ifnames
[1], n
->in_ifnames
[0], LIFNAMSIZ
);
1100 n
->in_ifps
[1] = n
->in_ifps
[0];
1102 n
->in_ifps
[1] = fr_resolvenic(n
->in_ifnames
[1], n
->in_v
, ifs
);
1105 if (n
->in_plabel
[0] != '\0') {
1106 n
->in_apr
= appr_lookup(n
->in_p
, n
->in_plabel
, ifs
);
1107 if (n
->in_apr
== NULL
)
1114 /* ------------------------------------------------------------------------ */
1115 /* Function: nat_siocdelnat */
1116 /* Returns: int - 0 == success, != 0 == failure */
1117 /* Parameters: n(I) - pointer to new NAT rule */
1118 /* np(I) - pointer to where to insert new NAT rule */
1119 /* getlock(I) - flag indicating if lock on ipf_nat is held */
1120 /* Mutex Locks: ipf_natio */
1122 /* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */
1123 /* from information passed to the kernel, then add it to the appropriate */
1124 /* NAT rule table(s). */
1125 /* ------------------------------------------------------------------------ */
1126 static void nat_siocdelnat(n
, np
, getlock
, ifs
)
1134 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
1136 if (n
->in_redir
& NAT_REDIRECT
)
1138 if (n
->in_redir
& (NAT_MAPBLK
|NAT_MAP
))
1140 if (ifs
->ifs_nat_list
== NULL
) {
1141 ifs
->ifs_nat_masks
= 0;
1142 ifs
->ifs_rdr_masks
= 0;
1143 for (i
= 0; i
< 4; i
++) {
1144 ifs
->ifs_nat6_masks
[i
] = 0;
1145 ifs
->ifs_rdr6_masks
[i
] = 0;
1149 if (n
->in_tqehead
[0] != NULL
) {
1150 if (fr_deletetimeoutqueue(n
->in_tqehead
[0]) == 0) {
1151 fr_freetimeoutqueue(n
->in_tqehead
[0], ifs
);
1155 if (n
->in_tqehead
[1] != NULL
) {
1156 if (fr_deletetimeoutqueue(n
->in_tqehead
[1]) == 0) {
1157 fr_freetimeoutqueue(n
->in_tqehead
[1], ifs
);
1163 if (n
->in_use
== 0) {
1165 appr_free(n
->in_apr
);
1167 ifs
->ifs_nat_stats
.ns_rules
--;
1169 n
->in_flags
|= IPN_DELETE
;
1173 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
); /* READ/WRITE */
1178 /* ------------------------------------------------------------------------ */
1179 /* Function: fr_natgetsz */
1180 /* Returns: int - 0 == success, != 0 is the error value. */
1181 /* Parameters: data(I) - pointer to natget structure with kernel pointer */
1182 /* get the size of. */
1184 /* Handle SIOCSTGSZ. */
1185 /* Return the size of the nat list entry to be copied back to user space. */
1186 /* The size of the entry is stored in the ng_sz field and the enture natget */
1187 /* structure is copied back to the user. */
1188 /* ------------------------------------------------------------------------ */
1189 static int fr_natgetsz(data
, ifs
)
1198 err
= BCOPYIN(data
, &ng
, sizeof(ng
));
1204 nat
= ifs
->ifs_nat_instances
;
1207 * Empty list so the size returned is 0. Simple.
1210 err
= BCOPYOUT(&ng
, data
, sizeof(ng
));
1219 * Make sure the pointer we're copying from exists in the
1220 * current list of entries. Security precaution to prevent
1221 * copying of random kernel data.
1223 for (n
= ifs
->ifs_nat_instances
; n
; n
= n
->nat_next
)
1231 * Incluse any space required for proxy data structures.
1233 ng
.ng_sz
= sizeof(nat_save_t
);
1236 ng
.ng_sz
+= sizeof(ap_session_t
) - 4;
1237 if (aps
->aps_data
!= 0)
1238 ng
.ng_sz
+= aps
->aps_psiz
;
1241 err
= BCOPYOUT(&ng
, data
, sizeof(ng
));
1248 /* ------------------------------------------------------------------------ */
1249 /* Function: fr_natgetent */
1250 /* Returns: int - 0 == success, != 0 is the error value. */
1251 /* Parameters: data(I) - pointer to natget structure with kernel pointer */
1252 /* to NAT structure to copy out. */
1254 /* Handle SIOCSTGET. */
1255 /* Copies out NAT entry to user space. Any additional data held for a */
1256 /* proxy is also copied, as to is the NAT rule which was responsible for it */
1257 /* ------------------------------------------------------------------------ */
1258 static int fr_natgetent(data
, ifs
)
1264 nat_save_t
*ipn
, ipns
;
1267 error
= fr_inobj(data
, &ipns
, IPFOBJ_NATSAVE
);
1271 if ((ipns
.ipn_dsize
< sizeof(ipns
)) || (ipns
.ipn_dsize
> 81920))
1274 KMALLOCS(ipn
, nat_save_t
*, ipns
.ipn_dsize
);
1278 ipn
->ipn_dsize
= ipns
.ipn_dsize
;
1279 nat
= ipns
.ipn_next
;
1281 nat
= ifs
->ifs_nat_instances
;
1283 if (ifs
->ifs_nat_instances
== NULL
)
1289 * Make sure the pointer we're copying from exists in the
1290 * current list of entries. Security precaution to prevent
1291 * copying of random kernel data.
1293 for (n
= ifs
->ifs_nat_instances
; n
; n
= n
->nat_next
)
1301 ipn
->ipn_next
= nat
->nat_next
;
1304 * Copy the NAT structure.
1306 bcopy((char *)nat
, &ipn
->ipn_nat
, sizeof(*nat
));
1309 * If we have a pointer to the NAT rule it belongs to, save that too.
1311 if (nat
->nat_ptr
!= NULL
)
1312 bcopy((char *)nat
->nat_ptr
, (char *)&ipn
->ipn_ipnat
,
1313 sizeof(ipn
->ipn_ipnat
));
1316 * If we also know the NAT entry has an associated filter rule,
1319 if (nat
->nat_fr
!= NULL
)
1320 bcopy((char *)nat
->nat_fr
, (char *)&ipn
->ipn_fr
,
1321 sizeof(ipn
->ipn_fr
));
1324 * Last but not least, if there is an application proxy session set
1325 * up for this NAT entry, then copy that out too, including any
1326 * private data saved along side it by the proxy.
1329 outsize
= ipn
->ipn_dsize
- sizeof(*ipn
) + sizeof(ipn
->ipn_data
);
1333 if (outsize
< sizeof(*aps
)) {
1339 bcopy((char *)aps
, s
, sizeof(*aps
));
1341 outsize
-= sizeof(*aps
);
1342 if ((aps
->aps_data
!= NULL
) && (outsize
>= aps
->aps_psiz
))
1343 bcopy(aps
->aps_data
, s
, aps
->aps_psiz
);
1348 error
= fr_outobjsz(data
, ipn
, IPFOBJ_NATSAVE
, ipns
.ipn_dsize
);
1353 KFREES(ipn
, ipns
.ipn_dsize
);
1358 /* ------------------------------------------------------------------------ */
1359 /* Function: nat_calc_chksum_diffs */
1361 /* Parameters: nat - pointer to NAT table entry */
1363 /* Function calculates chksum deltas for IP header (nat_ipsumd) and TCP/UDP */
1364 /* headers (nat_sumd). The things for L4 (UDP/TCP) get complicated when */
1365 /* we are dealing with partial chksum offload. For these cases we need to */
1366 /* compute a 'partial chksum delta'. The 'partial chksum delta'is stored */
1367 /* into nat_sumd[1], while ordinary chksum delta for TCP/UDP is in */
1370 /* The function accepts initialized NAT table entry and computes the deltas */
1371 /* from nat_inip/nat_outip members. The function is called right before */
1372 /* the new entry is inserted into the table. */
1374 /* The ipsumd (IP hedaer chksum delta adjustment) is computed as a chksum */
1375 /* of delta between original and new IP addresses. */
1377 /* the nat_sumd[0] (TCP/UDP header chksum delta adjustment) is computed as */
1378 /* a chkusm of delta between original an new IP addrress:port tupples. */
1380 /* Some facts about chksum, we should remember: */
1381 /* IP header chksum covers IP header only */
1383 /* TCP/UDP chksum covers data payload and so called pseudo header */
1384 /* SRC, DST IP address */
1386 /* length of payload */
1388 /* The partial chksum delta (nat_sumd[1] is used to adjust db_ckusm16 */
1389 /* member of dblk_t structure. The db_ckusm16 member is not part of */
1390 /* IP/UDP/TCP header it is 16 bit value computed by NIC driver with partial */
1391 /* chksum offload capacbility for every inbound packet. The db_cksum16 is */
1392 /* stored along with other IP packet data in dblk_t structure and used in */
1393 /* for IP/UDP/TCP chksum validation later in ip.c. */
1395 /* The partial chksum delta (adjustment, nat_sumd[1]) is computed as chksum */
1396 /* of delta between new and orig address. NOTE: the order of operands for */
1397 /* partial delta operation is swapped compared to computing the IP/TCP/UDP */
1398 /* header adjustment. It is by design see (IP_CKSUM_RECV() macro in ip.c). */
1400 /* ------------------------------------------------------------------------ */
1401 void nat_calc_chksum_diffs(nat
)
1404 u_32_t sum_orig
= 0;
1405 u_32_t sum_changed
= 0;
1407 u_32_t ipsum_orig
= 0;
1408 u_32_t ipsum_changed
= 0;
1410 if (nat
->nat_v
!= 4 && nat
->nat_v
!= 6)
1414 * the switch calculates operands for CALC_SUMD(),
1415 * which will compute the partial chksum delta.
1417 switch (nat
->nat_dir
)
1421 * we are dealing with RDR rule (DST address gets
1422 * modified on packet from client)
1424 if (nat
->nat_v
== 4) {
1425 sum_changed
= LONG_SUM(ntohl(nat
->nat_inip
.s_addr
));
1426 sum_orig
= LONG_SUM(ntohl(nat
->nat_outip
.s_addr
));
1428 sum_changed
= LONG_SUM6(&nat
->nat_inip6
);
1429 sum_orig
= LONG_SUM6(&nat
->nat_outip6
);
1434 * we are dealing with MAP rule (SRC address gets
1435 * modified on packet from client)
1437 if (nat
->nat_v
== 4) {
1438 sum_changed
= LONG_SUM(ntohl(nat
->nat_outip
.s_addr
));
1439 sum_orig
= LONG_SUM(ntohl(nat
->nat_inip
.s_addr
));
1441 sum_changed
= LONG_SUM6(&nat
->nat_outip6
);
1442 sum_orig
= LONG_SUM6(&nat
->nat_inip6
);
1450 * we also preserve CALC_SUMD() operands here, for IP chksum delta
1451 * calculation, which happens at the end of function.
1453 ipsum_changed
= sum_changed
;
1454 ipsum_orig
= sum_orig
;
1456 * NOTE: the order of operands for partial chksum adjustment
1457 * computation has to be swapped!
1459 CALC_SUMD(sum_changed
, sum_orig
, sumd
);
1460 nat
->nat_sumd
[1] = (sumd
& 0xffff) + (sumd
>> 16);
1462 if (nat
->nat_flags
& (IPN_TCPUDP
| IPN_ICMPQUERY
)) {
1465 * switch calculates operands for CALC_SUMD(), which will
1466 * compute the full chksum delta.
1468 switch (nat
->nat_dir
)
1471 if (nat
->nat_v
== 4) {
1472 sum_changed
= LONG_SUM(
1473 ntohl(nat
->nat_inip
.s_addr
) +
1474 ntohs(nat
->nat_inport
));
1475 sum_orig
= LONG_SUM(
1476 ntohl(nat
->nat_outip
.s_addr
) +
1477 ntohs(nat
->nat_outport
));
1479 sum_changed
= LONG_SUM6(&nat
->nat_inip6
) +
1480 ntohs(nat
->nat_inport
);
1481 sum_orig
= LONG_SUM6(&nat
->nat_outip6
) +
1482 ntohs(nat
->nat_outport
);
1486 if (nat
->nat_v
== 4) {
1487 sum_changed
= LONG_SUM(
1488 ntohl(nat
->nat_outip
.s_addr
) +
1489 ntohs(nat
->nat_outport
));
1490 sum_orig
= LONG_SUM(
1491 ntohl(nat
->nat_inip
.s_addr
) +
1492 ntohs(nat
->nat_inport
));
1494 sum_changed
= LONG_SUM6(&nat
->nat_outip6
) +
1495 ntohs(nat
->nat_outport
);
1496 sum_orig
= LONG_SUM6(&nat
->nat_inip6
) +
1497 ntohs(nat
->nat_inport
);
1504 CALC_SUMD(sum_orig
, sum_changed
, sumd
);
1505 nat
->nat_sumd
[0] = (sumd
& 0xffff) + (sumd
>> 16);
1507 if (!(nat
->nat_flags
& IPN_TCPUDP
)) {
1509 * partial HW chksum offload works for TCP/UDP headers only,
1510 * so we need to enforce full chksum adjustment for ICMP
1512 nat
->nat_sumd
[1] = nat
->nat_sumd
[0];
1516 nat
->nat_sumd
[0] = nat
->nat_sumd
[1];
1519 * we may reuse the already computed nat_sumd[0] for IP header chksum
1520 * adjustment in case the L4 (TCP/UDP header) is not changed by NAT.
1522 if (nat
->nat_v
== 4) {
1523 if (NAT_HAS_L4_CHANGED(nat
)) {
1525 * bad luck, NAT changes also the L4 header, use IP
1526 * addresses to compute chksum adjustment for IP header.
1528 CALC_SUMD(ipsum_orig
, ipsum_changed
, sumd
);
1529 nat
->nat_ipsumd
= (sumd
& 0xffff) + (sumd
>> 16);
1532 * the NAT does not change L4 hdr -> reuse chksum
1533 * adjustment for IP hdr.
1535 nat
->nat_ipsumd
= nat
->nat_sumd
[0];
1538 * if L4 header does not use chksum - zero out deltas
1540 if (!(nat
->nat_flags
& IPN_TCPUDP
)) {
1541 nat
->nat_sumd
[0] = 0;
1542 nat
->nat_sumd
[1] = 0;
1550 /* ------------------------------------------------------------------------ */
1551 /* Function: fr_natputent */
1552 /* Returns: int - 0 == success, != 0 is the error value. */
1553 /* Parameters: data(I) - pointer to natget structure with NAT */
1554 /* structure information to load into the kernel */
1555 /* getlock(I) - flag indicating whether or not a write lock */
1556 /* on ipf_nat is already held. */
1557 /* ifs - ipf stack instance */
1559 /* Handle SIOCSTPUT. */
1560 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */
1561 /* firewall rule data structures, if pointers to them indicate so. */
1562 /* ------------------------------------------------------------------------ */
1563 static int fr_natputent(data
, getlock
, ifs
)
1568 nat_save_t ipn
, *ipnn
;
1576 error
= fr_inobj(data
, &ipn
, IPFOBJ_NATSAVE
);
1581 * Trigger automatic call to nat_flushtable() if the
1582 * table has reached capcity specified by hi watermark.
1584 if (NAT_TAB_WATER_LEVEL(ifs
) > ifs
->ifs_nat_flush_level_hi
)
1585 ifs
->ifs_nat_doflush
= 1;
1588 * If automatic flushing did not do its job, and the table
1589 * has filled up, don't try to create a new entry.
1591 if (ifs
->ifs_nat_stats
.ns_inuse
>= ifs
->ifs_ipf_nattable_max
) {
1592 ifs
->ifs_nat_stats
.ns_memfail
++;
1597 * Initialise early because of code at junkput label.
1605 * New entry, copy in the rest of the NAT entry if it's size is more
1606 * than just the nat_t structure.
1609 if (ipn
.ipn_dsize
> sizeof(ipn
)) {
1610 if (ipn
.ipn_dsize
> 81920) {
1615 KMALLOCS(ipnn
, nat_save_t
*, ipn
.ipn_dsize
);
1619 error
= fr_inobjsz(data
, ipnn
, IPFOBJ_NATSAVE
, ipn
.ipn_dsize
);
1627 KMALLOC(nat
, nat_t
*);
1633 bcopy((char *)&ipnn
->ipn_nat
, (char *)nat
, sizeof(*nat
));
1635 * Initialize all these so that nat_delete() doesn't cause a crash.
1637 bzero((char *)nat
, offsetof(struct nat
, nat_tqe
));
1638 nat
->nat_tqe
.tqe_pnext
= NULL
;
1639 nat
->nat_tqe
.tqe_next
= NULL
;
1640 nat
->nat_tqe
.tqe_ifq
= NULL
;
1641 nat
->nat_tqe
.tqe_parent
= nat
;
1644 * Restore the rule associated with this nat session
1646 in
= ipnn
->ipn_nat
.nat_ptr
;
1648 KMALLOC(in
, ipnat_t
*);
1654 bzero((char *)in
, offsetof(struct ipnat
, in_next6
));
1655 bcopy((char *)&ipnn
->ipn_ipnat
, (char *)in
, sizeof(*in
));
1657 in
->in_flags
|= IPN_DELETE
;
1659 ATOMIC_INC(ifs
->ifs_nat_stats
.ns_rules
);
1661 if (nat_resolverule(in
, ifs
) != 0) {
1668 * Check that the NAT entry doesn't already exist in the kernel.
1670 if (nat
->nat_v
!= 6)
1672 bzero((char *)&fin
, sizeof(fin
));
1673 fin
.fin_p
= nat
->nat_p
;
1675 if (nat
->nat_dir
== NAT_OUTBOUND
) {
1676 fin
.fin_data
[0] = ntohs(nat
->nat_oport
);
1677 fin
.fin_data
[1] = ntohs(nat
->nat_outport
);
1678 fin
.fin_ifp
= nat
->nat_ifps
[0];
1680 READ_ENTER(&ifs
->ifs_ipf_nat
);
1686 fin
.fin_v
= nat
->nat_v
;
1687 n
= nat_inlookup(&fin
, nat
->nat_flags
, fin
.fin_p
,
1688 nat
->nat_oip
, nat
->nat_outip
);
1692 n
= nat6_inlookup(&fin
, nat
->nat_flags
, fin
.fin_p
,
1693 &nat
->nat_oip6
.in6
, &nat
->nat_outip6
.in6
);
1702 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
1708 } else if (nat
->nat_dir
== NAT_INBOUND
) {
1709 fin
.fin_data
[0] = ntohs(nat
->nat_inport
);
1710 fin
.fin_data
[1] = ntohs(nat
->nat_oport
);
1711 fin
.fin_ifp
= nat
->nat_ifps
[1];
1713 READ_ENTER(&ifs
->ifs_ipf_nat
);
1719 n
= nat_outlookup(&fin
, nat
->nat_flags
, fin
.fin_p
,
1720 nat
->nat_inip
, nat
->nat_oip
);
1724 n
= nat6_outlookup(&fin
, nat
->nat_flags
, fin
.fin_p
,
1725 &nat
->nat_inip6
.in6
, &nat
->nat_oip6
.in6
);
1734 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
1746 * Restore ap_session_t structure. Include the private data allocated
1751 KMALLOC(aps
, ap_session_t
*);
1757 bcopy(ipnn
->ipn_data
, (char *)aps
, sizeof(*aps
));
1759 aps
->aps_apr
= in
->in_apr
;
1761 aps
->aps_apr
= NULL
;
1762 if (aps
->aps_psiz
!= 0) {
1763 if (aps
->aps_psiz
> 81920) {
1767 KMALLOCS(aps
->aps_data
, void *, aps
->aps_psiz
);
1768 if (aps
->aps_data
== NULL
) {
1772 bcopy(ipnn
->ipn_data
+ sizeof(*aps
), aps
->aps_data
,
1776 aps
->aps_data
= NULL
;
1781 * If there was a filtering rule associated with this entry then
1782 * build up a new one.
1786 if ((nat
->nat_flags
& SI_NEWFR
) != 0) {
1787 KMALLOC(fr
, frentry_t
*);
1793 ipnn
->ipn_nat
.nat_fr
= fr
;
1794 (void) fr_outobj(data
, ipnn
, IPFOBJ_NATSAVE
);
1795 bcopy((char *)&ipnn
->ipn_fr
, (char *)fr
, sizeof(*fr
));
1800 fr
->fr_type
= FR_T_NONE
;
1802 MUTEX_NUKE(&fr
->fr_lock
);
1803 MUTEX_INIT(&fr
->fr_lock
, "nat-filter rule lock");
1806 READ_ENTER(&ifs
->ifs_ipf_nat
);
1808 for (n
= ifs
->ifs_nat_instances
; n
; n
= n
->nat_next
)
1809 if (n
->nat_fr
== fr
)
1813 MUTEX_ENTER(&fr
->fr_lock
);
1815 MUTEX_EXIT(&fr
->fr_lock
);
1818 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
1828 KFREES(ipnn
, ipn
.ipn_dsize
);
1832 nat_calc_chksum_diffs(nat
);
1835 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
1838 nat_calc_chksum_diffs(nat
);
1843 error
= nat_insert(nat
, nat
->nat_rev
, ifs
);
1847 error
= nat6_insert(nat
, nat
->nat_rev
, ifs
);
1854 if ((error
== 0) && (aps
!= NULL
)) {
1855 aps
->aps_next
= ifs
->ifs_ap_sess_list
;
1856 ifs
->ifs_ap_sess_list
= aps
;
1859 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
1869 (void) fr_derefrule(&fr
, ifs
);
1871 if ((ipnn
!= NULL
) && (ipnn
!= &ipn
)) {
1872 KFREES(ipnn
, ipn
.ipn_dsize
);
1876 if (aps
->aps_data
!= NULL
) {
1877 KFREES(aps
->aps_data
, aps
->aps_psiz
);
1883 appr_free(in
->in_apr
);
1892 /* ------------------------------------------------------------------------ */
1893 /* Function: nat_delete */
1894 /* Returns: int - 0 if entry deleted. Otherwise, ref count on entry */
1895 /* Parameters: nat - pointer to the NAT entry to delete */
1896 /* logtype - type of LOG record to create before deleting */
1897 /* ifs - ipf stack instance */
1898 /* Write Lock: ipf_nat */
1900 /* Delete a nat entry from the various lists and table. If NAT logging is */
1901 /* enabled then generate a NAT log record for this event. */
1902 /* ------------------------------------------------------------------------ */
1903 int nat_delete(nat
, logtype
, ifs
)
1911 if (logtype
!= 0 && ifs
->ifs_nat_logging
!= 0)
1912 nat_log(nat
, logtype
, ifs
);
1915 * Start by removing the entry from the hash table of nat entries
1916 * so it will not be "used" again.
1918 * It will remain in the "list" of nat entries until all references
1919 * have been accounted for.
1921 if ((nat
->nat_phnext
[0] != NULL
) && (nat
->nat_phnext
[1] != NULL
)) {
1924 ifs
->ifs_nat_stats
.ns_bucketlen
[0][nat
->nat_hv
[0]]--;
1925 ifs
->ifs_nat_stats
.ns_bucketlen
[1][nat
->nat_hv
[1]]--;
1927 *nat
->nat_phnext
[0] = nat
->nat_hnext
[0];
1928 if (nat
->nat_hnext
[0] != NULL
) {
1929 nat
->nat_hnext
[0]->nat_phnext
[0] = nat
->nat_phnext
[0];
1930 nat
->nat_hnext
[0] = NULL
;
1932 nat
->nat_phnext
[0] = NULL
;
1934 *nat
->nat_phnext
[1] = nat
->nat_hnext
[1];
1935 if (nat
->nat_hnext
[1] != NULL
) {
1936 nat
->nat_hnext
[1]->nat_phnext
[1] = nat
->nat_phnext
[1];
1937 nat
->nat_hnext
[1] = NULL
;
1939 nat
->nat_phnext
[1] = NULL
;
1941 if ((nat
->nat_flags
& SI_WILDP
) != 0)
1942 ifs
->ifs_nat_stats
.ns_wilds
--;
1946 * Next, remove it from the timeout queue it is in.
1948 fr_deletequeueentry(&nat
->nat_tqe
);
1950 if (nat
->nat_me
!= NULL
) {
1951 *nat
->nat_me
= NULL
;
1955 MUTEX_ENTER(&nat
->nat_lock
);
1956 if (nat
->nat_ref
> 1) {
1958 MUTEX_EXIT(&nat
->nat_lock
);
1960 ifs
->ifs_nat_stats
.ns_orphans
++;
1961 return (nat
->nat_ref
);
1963 MUTEX_EXIT(&nat
->nat_lock
);
1968 * If entry had already been removed,
1969 * it means we're cleaning up an orphan.
1972 ifs
->ifs_nat_stats
.ns_orphans
--;
1974 #ifdef IPFILTER_SYNC
1976 ipfsync_del(nat
->nat_sync
);
1980 * Now remove it from master list of nat table entries
1982 if (nat
->nat_pnext
!= NULL
) {
1983 *nat
->nat_pnext
= nat
->nat_next
;
1984 if (nat
->nat_next
!= NULL
) {
1985 nat
->nat_next
->nat_pnext
= nat
->nat_pnext
;
1986 nat
->nat_next
= NULL
;
1988 nat
->nat_pnext
= NULL
;
1991 if (nat
->nat_fr
!= NULL
)
1992 (void)fr_derefrule(&nat
->nat_fr
, ifs
);
1994 if (nat
->nat_hm
!= NULL
)
1995 fr_hostmapdel(&nat
->nat_hm
);
1998 * If there is an active reference from the nat entry to its parent
1999 * rule, decrement the rule's reference count and free it too if no
2000 * longer being used.
2006 if (ipn
->in_use
== 0 && (ipn
->in_flags
& IPN_DELETE
)) {
2008 appr_free(ipn
->in_apr
);
2010 ifs
->ifs_nat_stats
.ns_rules
--;
2014 MUTEX_DESTROY(&nat
->nat_lock
);
2016 aps_free(nat
->nat_aps
, ifs
);
2017 ifs
->ifs_nat_stats
.ns_inuse
--;
2020 * If there's a fragment table entry too for this nat entry, then
2021 * dereference that as well. This is after nat_lock is released
2024 fr_forgetnat((void *)nat
, ifs
);
2032 /* ------------------------------------------------------------------------ */
2033 /* Function: nat_clearlist */
2034 /* Returns: int - number of NAT/RDR rules deleted */
2035 /* Parameters: Nil */
2037 /* Delete all rules in the current list of rules. There is nothing elegant */
2038 /* about this cleanup: simply free all entries on the list of rules and */
2039 /* clear out the tables used for hashed NAT rule lookups. */
2040 /* ------------------------------------------------------------------------ */
2041 static int nat_clearlist(ifs
)
2044 ipnat_t
*n
, **np
= &ifs
->ifs_nat_list
;
2047 if (ifs
->ifs_nat_rules
!= NULL
)
2048 bzero((char *)ifs
->ifs_nat_rules
,
2049 sizeof(*ifs
->ifs_nat_rules
) * ifs
->ifs_ipf_natrules_sz
);
2050 if (ifs
->ifs_rdr_rules
!= NULL
)
2051 bzero((char *)ifs
->ifs_rdr_rules
,
2052 sizeof(*ifs
->ifs_rdr_rules
) * ifs
->ifs_ipf_rdrrules_sz
);
2054 while ((n
= *np
) != NULL
) {
2056 if (n
->in_use
== 0) {
2057 if (n
->in_apr
!= NULL
)
2058 appr_free(n
->in_apr
);
2060 ifs
->ifs_nat_stats
.ns_rules
--;
2062 n
->in_flags
|= IPN_DELETE
;
2067 ifs
->ifs_nat_masks
= 0;
2068 ifs
->ifs_rdr_masks
= 0;
2069 for (i
= 0; i
< 4; i
++) {
2070 ifs
->ifs_nat6_masks
[i
] = 0;
2071 ifs
->ifs_rdr6_masks
[i
] = 0;
2077 /* ------------------------------------------------------------------------ */
2078 /* Function: nat_newmap */
2079 /* Returns: int - -1 == error, 0 == success */
2080 /* Parameters: fin(I) - pointer to packet information */
2081 /* nat(I) - pointer to NAT entry */
2082 /* ni(I) - pointer to structure with misc. information needed */
2083 /* to create new NAT entry. */
2085 /* Given an empty NAT structure, populate it with new information about a */
2086 /* new NAT session, as defined by the matching NAT rule. */
2087 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2088 /* to the new IP address for the translation. */
2089 /* ------------------------------------------------------------------------ */
2090 static INLINE
int nat_newmap(fin
, nat
, ni
)
2095 u_short st_port
, dport
, sport
, port
, sp
, dp
;
2096 struct in_addr in
, inb
;
2103 ipf_stack_t
*ifs
= fin
->fin_ifs
;
2106 * If it's an outbound packet which doesn't match any existing
2107 * record, then create a new port
2113 st_port
= np
->in_pnext
;
2114 flags
= ni
->nai_flags
;
2115 sport
= ni
->nai_sport
;
2116 dport
= ni
->nai_dport
;
2119 * Do a loop until we either run out of entries to try or we find
2120 * a NAT mapping that isn't currently being used. This is done
2121 * because the change to the source is not (usually) being fixed.
2125 in
.s_addr
= htonl(np
->in_nip
);
2128 * Check to see if there is an existing NAT
2129 * setup for this IP address pair.
2131 hm
= nat_hostmap(np
, fin
->fin_src
, fin
->fin_dst
,
2134 in
.s_addr
= hm
->hm_mapip
.s_addr
;
2135 } else if ((l
== 1) && (hm
!= NULL
)) {
2138 in
.s_addr
= ntohl(in
.s_addr
);
2142 if ((np
->in_outmsk
== 0xffffffff) && (np
->in_pnext
== 0)) {
2147 if (np
->in_redir
== NAT_BIMAP
&&
2148 np
->in_inmsk
== np
->in_outmsk
) {
2150 * map the address block in a 1:1 fashion
2152 in
.s_addr
= np
->in_outip
;
2153 in
.s_addr
|= fin
->fin_saddr
& ~np
->in_inmsk
;
2154 in
.s_addr
= ntohl(in
.s_addr
);
2156 } else if (np
->in_redir
& NAT_MAPBLK
) {
2157 if ((l
>= np
->in_ppip
) || ((l
> 0) &&
2158 !(flags
& IPN_TCPUDP
)))
2161 * map-block - Calculate destination address.
2163 in
.s_addr
= ntohl(fin
->fin_saddr
);
2164 in
.s_addr
&= ntohl(~np
->in_inmsk
);
2165 inb
.s_addr
= in
.s_addr
;
2166 in
.s_addr
/= np
->in_ippip
;
2167 in
.s_addr
&= ntohl(~np
->in_outmsk
);
2168 in
.s_addr
+= ntohl(np
->in_outip
);
2170 * Calculate destination port.
2172 if ((flags
& IPN_TCPUDP
) &&
2173 (np
->in_ppip
!= 0)) {
2174 port
= ntohs(sport
) + l
;
2175 port
%= np
->in_ppip
;
2176 port
+= np
->in_ppip
*
2177 (inb
.s_addr
% np
->in_ippip
);
2178 port
+= MAPBLK_MINPORT
;
2182 } else if ((np
->in_outip
== 0) &&
2183 (np
->in_outmsk
== 0xffffffff)) {
2185 * 0/32 - use the interface's IP address.
2188 fr_ifpaddr(4, FRI_NORMAL
, fin
->fin_ifp
,
2189 &in
, NULL
, fin
->fin_ifs
) == -1)
2191 in
.s_addr
= ntohl(in
.s_addr
);
2193 } else if ((np
->in_outip
== 0) && (np
->in_outmsk
== 0)) {
2195 * 0/0 - use the original source address/port.
2199 in
.s_addr
= ntohl(fin
->fin_saddr
);
2201 } else if ((np
->in_outmsk
!= 0xffffffff) &&
2202 (np
->in_pnext
== 0) && ((l
> 0) || (hm
== NULL
)))
2207 if ((flags
& IPN_TCPUDP
) &&
2208 ((np
->in_redir
& NAT_MAPBLK
) == 0) &&
2209 (np
->in_flags
& IPN_AUTOPORTMAP
)) {
2211 * "ports auto" (without map-block)
2213 if ((l
> 0) && (l
% np
->in_ppip
== 0)) {
2214 if (l
> np
->in_space
) {
2216 } else if ((l
> np
->in_ppip
) &&
2217 np
->in_outmsk
!= 0xffffffff)
2220 if (np
->in_ppip
!= 0) {
2221 port
= ntohs(sport
);
2222 port
+= (l
% np
->in_ppip
);
2223 port
%= np
->in_ppip
;
2224 port
+= np
->in_ppip
*
2225 (ntohl(fin
->fin_saddr
) %
2227 port
+= MAPBLK_MINPORT
;
2231 } else if (((np
->in_redir
& NAT_MAPBLK
) == 0) &&
2232 (flags
& IPN_TCPUDPICMP
) && (np
->in_pnext
!= 0)) {
2234 * Standard port translation. Select next port.
2236 if (np
->in_flags
& IPN_SEQUENTIAL
) {
2237 port
= np
->in_pnext
;
2239 port
= ipf_random() % (ntohs(np
->in_pmax
) -
2240 ntohs(np
->in_pmin
) + 1);
2241 port
+= ntohs(np
->in_pmin
);
2246 if (np
->in_pnext
> ntohs(np
->in_pmax
)) {
2247 np
->in_pnext
= ntohs(np
->in_pmin
);
2248 if (np
->in_outmsk
!= 0xffffffff)
2253 if (np
->in_flags
& IPN_IPRANGE
) {
2254 if (np
->in_nip
> ntohl(np
->in_outmsk
))
2255 np
->in_nip
= ntohl(np
->in_outip
);
2257 if ((np
->in_outmsk
!= 0xffffffff) &&
2258 ((np
->in_nip
+ 1) & ntohl(np
->in_outmsk
)) >
2259 ntohl(np
->in_outip
))
2260 np
->in_nip
= ntohl(np
->in_outip
) + 1;
2263 if ((port
== 0) && (flags
& (IPN_TCPUDPICMP
|IPN_ICMPQUERY
)))
2267 * Here we do a lookup of the connection as seen from
2268 * the outside. If an IP# pair already exists, try
2269 * again. So if you have A->B becomes C->B, you can
2270 * also have D->E become C->E but not D->B causing
2271 * another C->B. Also take protocol and ports into
2272 * account when determining whether a pre-existing
2273 * NAT setup will cause an external conflict where
2274 * this is appropriate.
2276 inb
.s_addr
= htonl(in
.s_addr
);
2277 sp
= fin
->fin_data
[0];
2278 dp
= fin
->fin_data
[1];
2279 fin
->fin_data
[0] = fin
->fin_data
[1];
2280 fin
->fin_data
[1] = htons(port
);
2281 natl
= nat_inlookup(fin
, flags
& ~(SI_WILDP
|NAT_SEARCH
),
2282 (u_int
)fin
->fin_p
, fin
->fin_dst
, inb
);
2283 fin
->fin_data
[0] = sp
;
2284 fin
->fin_data
[1] = dp
;
2287 * Has the search wrapped around and come back to the
2290 if ((natl
!= NULL
) &&
2291 (np
->in_pnext
!= 0) && (st_port
== np
->in_pnext
) &&
2292 (np
->in_nip
!= 0) && (st_ip
== np
->in_nip
))
2295 } while (natl
!= NULL
);
2297 if (np
->in_space
> 0)
2300 /* Setup the NAT table */
2301 nat
->nat_inip
= fin
->fin_src
;
2302 nat
->nat_outip
.s_addr
= htonl(in
.s_addr
);
2303 nat
->nat_oip
= fin
->fin_dst
;
2304 if (nat
->nat_hm
== NULL
)
2305 nat
->nat_hm
= nat_hostmap(np
, fin
->fin_src
, fin
->fin_dst
,
2306 nat
->nat_outip
, 0, ifs
);
2308 if (flags
& IPN_TCPUDP
) {
2309 nat
->nat_inport
= sport
;
2310 nat
->nat_outport
= port
; /* sport */
2311 nat
->nat_oport
= dport
;
2312 ((tcphdr_t
*)fin
->fin_dp
)->th_sport
= port
;
2313 } else if (flags
& IPN_ICMPQUERY
) {
2314 ((icmphdr_t
*)fin
->fin_dp
)->icmp_id
= port
;
2315 nat
->nat_inport
= port
;
2316 nat
->nat_outport
= port
;
2319 ni
->nai_ip
.s_addr
= in
.s_addr
;
2320 ni
->nai_port
= port
;
2321 ni
->nai_nport
= dport
;
2326 /* ------------------------------------------------------------------------ */
2327 /* Function: nat_newrdr */
2328 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
2329 /* allow rule to be moved if IPN_ROUNDR is set. */
2330 /* Parameters: fin(I) - pointer to packet information */
2331 /* nat(I) - pointer to NAT entry */
2332 /* ni(I) - pointer to structure with misc. information needed */
2333 /* to create new NAT entry. */
2335 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2336 /* to the new IP address for the translation. */
2337 /* ------------------------------------------------------------------------ */
2338 static INLINE
int nat_newrdr(fin
, nat
, ni
)
2343 u_short nport
, dport
, sport
;
2344 struct in_addr in
, inb
;
2351 ipf_stack_t
*ifs
= fin
->fin_ifs
;
2357 flags
= ni
->nai_flags
;
2358 sport
= ni
->nai_sport
;
2359 dport
= ni
->nai_dport
;
2362 * If the matching rule has IPN_STICKY set, then we want to have the
2363 * same rule kick in as before. Why would this happen? If you have
2364 * a collection of rdr rules with "round-robin sticky", the current
2365 * packet might match a different one to the previous connection but
2366 * we want the same destination to be used.
2368 if ((np
->in_flags
& (IPN_ROUNDR
|IPN_STICKY
)) ==
2369 (IPN_ROUNDR
|IPN_STICKY
)) {
2370 hm
= nat_hostmap(NULL
, fin
->fin_src
, fin
->fin_dst
, in
,
2371 (u_32_t
)dport
, ifs
);
2373 in
.s_addr
= ntohl(hm
->hm_mapip
.s_addr
);
2381 * Otherwise, it's an inbound packet. Most likely, we don't
2382 * want to rewrite source ports and source addresses. Instead,
2383 * we want to rewrite to a fixed internal address and fixed
2386 if (np
->in_flags
& IPN_SPLIT
) {
2387 in
.s_addr
= np
->in_nip
;
2389 if ((np
->in_flags
& (IPN_ROUNDR
|IPN_STICKY
)) == IPN_STICKY
) {
2390 hm
= nat_hostmap(np
, fin
->fin_src
, fin
->fin_dst
,
2391 in
, (u_32_t
)dport
, ifs
);
2393 in
.s_addr
= hm
->hm_mapip
.s_addr
;
2398 if (hm
== NULL
|| hm
->hm_ref
== 1) {
2399 if (np
->in_inip
== htonl(in
.s_addr
)) {
2400 np
->in_nip
= ntohl(np
->in_inmsk
);
2403 np
->in_nip
= ntohl(np
->in_inip
);
2407 } else if ((np
->in_inip
== 0) && (np
->in_inmsk
== 0xffffffff)) {
2409 * 0/32 - use the interface's IP address.
2411 if (fr_ifpaddr(4, FRI_NORMAL
, fin
->fin_ifp
, &in
, NULL
,
2412 fin
->fin_ifs
) == -1)
2414 in
.s_addr
= ntohl(in
.s_addr
);
2416 } else if ((np
->in_inip
== 0) && (np
->in_inmsk
== 0)) {
2418 * 0/0 - use the original destination address/port.
2420 in
.s_addr
= ntohl(fin
->fin_daddr
);
2422 } else if (np
->in_redir
== NAT_BIMAP
&&
2423 np
->in_inmsk
== np
->in_outmsk
) {
2425 * map the address block in a 1:1 fashion
2427 in
.s_addr
= np
->in_inip
;
2428 in
.s_addr
|= fin
->fin_daddr
& ~np
->in_inmsk
;
2429 in
.s_addr
= ntohl(in
.s_addr
);
2431 in
.s_addr
= ntohl(np
->in_inip
);
2434 if ((np
->in_pnext
== 0) || ((flags
& NAT_NOTRULEPORT
) != 0))
2438 * Whilst not optimized for the case where
2439 * pmin == pmax, the gain is not significant.
2441 if (((np
->in_flags
& IPN_FIXEDDPORT
) == 0) &&
2442 (np
->in_pmin
!= np
->in_pmax
)) {
2443 nport
= ntohs(dport
) - ntohs(np
->in_pmin
) +
2444 ntohs(np
->in_pnext
);
2445 nport
= htons(nport
);
2447 nport
= np
->in_pnext
;
2451 * When the redirect-to address is set to 0.0.0.0, just
2452 * assume a blank `forwarding' of the packet. We don't
2453 * setup any translation for this either.
2455 if (in
.s_addr
== 0) {
2458 in
.s_addr
= ntohl(fin
->fin_daddr
);
2462 * Check to see if this redirect mapping already exists and if
2463 * it does, return "failure" (allowing it to be created will just
2464 * cause one or both of these "connections" to stop working.)
2466 inb
.s_addr
= htonl(in
.s_addr
);
2467 sp
= fin
->fin_data
[0];
2468 dp
= fin
->fin_data
[1];
2469 fin
->fin_data
[1] = fin
->fin_data
[0];
2470 fin
->fin_data
[0] = ntohs(nport
);
2471 natl
= nat_outlookup(fin
, flags
& ~(SI_WILDP
|NAT_SEARCH
),
2472 (u_int
)fin
->fin_p
, inb
, fin
->fin_src
);
2473 fin
->fin_data
[0] = sp
;
2474 fin
->fin_data
[1] = dp
;
2478 nat
->nat_inip
.s_addr
= htonl(in
.s_addr
);
2479 nat
->nat_outip
= fin
->fin_dst
;
2480 nat
->nat_oip
= fin
->fin_src
;
2482 ni
->nai_ip
.s_addr
= in
.s_addr
;
2483 ni
->nai_nport
= nport
;
2484 ni
->nai_port
= sport
;
2486 if (flags
& IPN_TCPUDP
) {
2487 nat
->nat_inport
= nport
;
2488 nat
->nat_outport
= dport
;
2489 nat
->nat_oport
= sport
;
2490 ((tcphdr_t
*)fin
->fin_dp
)->th_dport
= nport
;
2491 } else if (flags
& IPN_ICMPQUERY
) {
2492 ((icmphdr_t
*)fin
->fin_dp
)->icmp_id
= nport
;
2493 nat
->nat_inport
= nport
;
2494 nat
->nat_outport
= nport
;
2500 /* ------------------------------------------------------------------------ */
2501 /* Function: nat_new */
2502 /* Returns: nat_t* - NULL == failure to create new NAT structure, */
2503 /* else pointer to new NAT structure */
2504 /* Parameters: fin(I) - pointer to packet information */
2505 /* np(I) - pointer to NAT rule */
2506 /* natsave(I) - pointer to where to store NAT struct pointer */
2507 /* flags(I) - flags describing the current packet */
2508 /* direction(I) - direction of packet (in/out) */
2509 /* Write Lock: ipf_nat */
2511 /* Attempts to create a new NAT entry. Does not actually change the packet */
2514 /* This fucntion is in three main parts: (1) deal with creating a new NAT */
2515 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */
2516 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
2517 /* and (3) building that structure and putting it into the NAT table(s). */
2518 /* ------------------------------------------------------------------------ */
2519 nat_t
*nat_new(fin
, np
, natsave
, flags
, direction
)
2526 tcphdr_t
*tcp
= NULL
;
2527 hostmap_t
*hm
= NULL
;
2532 ipf_stack_t
*ifs
= fin
->fin_ifs
;
2535 * Trigger automatic call to nat_flushtable() if the
2536 * table has reached capcity specified by hi watermark.
2538 if (NAT_TAB_WATER_LEVEL(ifs
) > ifs
->ifs_nat_flush_level_hi
)
2539 ifs
->ifs_nat_doflush
= 1;
2542 * If automatic flushing did not do its job, and the table
2543 * has filled up, don't try to create a new entry.
2545 if (ifs
->ifs_nat_stats
.ns_inuse
>= ifs
->ifs_ipf_nattable_max
) {
2546 ifs
->ifs_nat_stats
.ns_memfail
++;
2551 nflags
= np
->in_flags
& flags
;
2552 nflags
&= NAT_FROMRULE
;
2555 ni
.nai_nflags
= nflags
;
2556 ni
.nai_flags
= flags
;
2558 /* Give me a new nat */
2559 KMALLOC(nat
, nat_t
*);
2561 ifs
->ifs_nat_stats
.ns_memfail
++;
2563 * Try to automatically tune the max # of entries in the
2564 * table allowed to be less than what will cause kmem_alloc()
2565 * to fail and try to eliminate panics due to out of memory
2566 * conditions arising.
2568 if (ifs
->ifs_ipf_nattable_max
> ifs
->ifs_ipf_nattable_sz
) {
2569 ifs
->ifs_ipf_nattable_max
= ifs
->ifs_nat_stats
.ns_inuse
- 100;
2570 printf("ipf_nattable_max reduced to %d\n",
2571 ifs
->ifs_ipf_nattable_max
);
2576 if (flags
& IPN_TCPUDP
) {
2578 ni
.nai_sport
= htons(fin
->fin_sport
);
2579 ni
.nai_dport
= htons(fin
->fin_dport
);
2580 } else if (flags
& IPN_ICMPQUERY
) {
2582 * In the ICMP query NAT code, we translate the ICMP id fields
2583 * to make them unique. This is indepedent of the ICMP type
2584 * (e.g. in the unlikely event that a host sends an echo and
2585 * an tstamp request with the same id, both packets will have
2586 * their ip address/id field changed in the same way).
2588 /* The icmp_id field is used by the sender to identify the
2589 * process making the icmp request. (the receiver justs
2590 * copies it back in its response). So, it closely matches
2591 * the concept of source port. We overlay sport, so we can
2592 * maximally reuse the existing code.
2594 ni
.nai_sport
= ((icmphdr_t
*)fin
->fin_dp
)->icmp_id
;
2595 ni
.nai_dport
= ni
.nai_sport
;
2598 bzero((char *)nat
, sizeof(*nat
));
2599 nat
->nat_flags
= flags
;
2600 nat
->nat_redir
= np
->in_redir
;
2602 if ((flags
& NAT_SLAVE
) == 0) {
2603 MUTEX_ENTER(&ifs
->ifs_ipf_nat_new
);
2607 * Search the current table for a match.
2609 if (direction
== NAT_OUTBOUND
) {
2611 * We can now arrange to call this for the same connection
2612 * because ipf_nat_new doesn't protect the code path into
2615 natl
= nat_outlookup(fin
, nflags
, (u_int
)fin
->fin_p
,
2616 fin
->fin_src
, fin
->fin_dst
);
2623 move
= nat_newmap(fin
, nat
, &ni
);
2630 * NAT_INBOUND is used only for redirects rules
2632 natl
= nat_inlookup(fin
, nflags
, (u_int
)fin
->fin_p
,
2633 fin
->fin_src
, fin
->fin_dst
);
2640 move
= nat_newrdr(fin
, nat
, &ni
);
2647 if ((move
== 1) && (np
->in_flags
& IPN_ROUNDR
)) {
2648 if (np
->in_redir
== NAT_REDIRECT
) {
2650 nat_addrdr(np
, ifs
);
2651 } else if (np
->in_redir
== NAT_MAP
) {
2653 nat_addnat(np
, ifs
);
2657 if (nat_finalise(fin
, nat
, &ni
, tcp
, natsave
, direction
) == -1) {
2661 nat_calc_chksum_diffs(nat
);
2663 if (flags
& SI_WILDP
)
2664 ifs
->ifs_nat_stats
.ns_wilds
++;
2665 fin
->fin_flx
|= FI_NEWNAT
;
2668 ifs
->ifs_nat_stats
.ns_badnat
++;
2669 if ((hm
= nat
->nat_hm
) != NULL
)
2674 if ((flags
& NAT_SLAVE
) == 0) {
2675 MUTEX_EXIT(&ifs
->ifs_ipf_nat_new
);
2681 /* ------------------------------------------------------------------------ */
2682 /* Function: nat_finalise */
2683 /* Returns: int - 0 == sucess, -1 == failure */
2684 /* Parameters: fin(I) - pointer to packet information */
2685 /* nat(I) - pointer to NAT entry */
2686 /* ni(I) - pointer to structure with misc. information needed */
2687 /* to create new NAT entry. */
2688 /* Write Lock: ipf_nat */
2690 /* This is the tail end of constructing a new NAT entry and is the same */
2691 /* for both IPv4 and IPv6. */
2692 /* ------------------------------------------------------------------------ */
2694 static INLINE
int nat_finalise(fin
, nat
, ni
, tcp
, natsave
, direction
)
2704 ipf_stack_t
*ifs
= fin
->fin_ifs
;
2708 COPYIFNAME(fin
->fin_ifp
, nat
->nat_ifnames
[0], fin
->fin_v
);
2710 #ifdef IPFILTER_SYNC
2711 if ((nat
->nat_flags
& SI_CLONE
) == 0)
2712 nat
->nat_sync
= ipfsync_new(SMC_NAT
, fin
, nat
);
2715 nat
->nat_me
= natsave
;
2716 nat
->nat_dir
= direction
;
2717 nat
->nat_ifps
[0] = np
->in_ifps
[0];
2718 nat
->nat_ifps
[1] = np
->in_ifps
[1];
2720 nat
->nat_p
= fin
->fin_p
;
2721 nat
->nat_v
= fin
->fin_v
;
2722 nat
->nat_mssclamp
= np
->in_mssclamp
;
2726 if ((np
->in_apr
!= NULL
) && ((ni
->nai_flags
& NAT_SLAVE
) == 0))
2727 if (appr_new(fin
, nat
) == -1)
2730 if (nat_insert(nat
, fin
->fin_rev
, ifs
) == 0) {
2731 if (ifs
->ifs_nat_logging
)
2732 nat_log(nat
, (u_int
)np
->in_redir
, ifs
);
2735 MUTEX_ENTER(&fr
->fr_lock
);
2737 MUTEX_EXIT(&fr
->fr_lock
);
2743 * nat_insert failed, so cleanup time...
2749 /* ------------------------------------------------------------------------ */
2750 /* Function: nat_insert */
2751 /* Returns: int - 0 == sucess, -1 == failure */
2752 /* Parameters: nat(I) - pointer to NAT structure */
2753 /* rev(I) - flag indicating forward/reverse direction of packet */
2754 /* Write Lock: ipf_nat */
2756 /* Insert a NAT entry into the hash tables for searching and add it to the */
2757 /* list of active NAT entries. Adjust global counters when complete. */
2758 /* ------------------------------------------------------------------------ */
2759 int nat_insert(nat
, rev
, ifs
)
2768 * Try and return an error as early as possible, so calculate the hash
2769 * entry numbers first and then proceed.
2771 if ((nat
->nat_flags
& (SI_W_SPORT
|SI_W_DPORT
)) == 0) {
2772 hv1
= NAT_HASH_FN(nat
->nat_inip
.s_addr
, nat
->nat_inport
,
2774 hv1
= NAT_HASH_FN(nat
->nat_oip
.s_addr
, hv1
+ nat
->nat_oport
,
2775 ifs
->ifs_ipf_nattable_sz
);
2776 hv2
= NAT_HASH_FN(nat
->nat_outip
.s_addr
, nat
->nat_outport
,
2778 hv2
= NAT_HASH_FN(nat
->nat_oip
.s_addr
, hv2
+ nat
->nat_oport
,
2779 ifs
->ifs_ipf_nattable_sz
);
2781 hv1
= NAT_HASH_FN(nat
->nat_inip
.s_addr
, 0, 0xffffffff);
2782 hv1
= NAT_HASH_FN(nat
->nat_oip
.s_addr
, hv1
,
2783 ifs
->ifs_ipf_nattable_sz
);
2784 hv2
= NAT_HASH_FN(nat
->nat_outip
.s_addr
, 0, 0xffffffff);
2785 hv2
= NAT_HASH_FN(nat
->nat_oip
.s_addr
, hv2
,
2786 ifs
->ifs_ipf_nattable_sz
);
2789 if (ifs
->ifs_nat_stats
.ns_bucketlen
[0][hv1
] >= ifs
->ifs_fr_nat_maxbucket
||
2790 ifs
->ifs_nat_stats
.ns_bucketlen
[1][hv2
] >= ifs
->ifs_fr_nat_maxbucket
) {
2794 nat
->nat_hv
[0] = hv1
;
2795 nat
->nat_hv
[1] = hv2
;
2797 MUTEX_INIT(&nat
->nat_lock
, "nat entry lock");
2801 nat
->nat_bytes
[0] = 0;
2802 nat
->nat_pkts
[0] = 0;
2803 nat
->nat_bytes
[1] = 0;
2804 nat
->nat_pkts
[1] = 0;
2806 nat
->nat_ifnames
[0][LIFNAMSIZ
- 1] = '\0';
2807 nat
->nat_ifps
[0] = fr_resolvenic(nat
->nat_ifnames
[0], 4, ifs
);
2809 if (nat
->nat_ifnames
[1][0] !='\0') {
2810 nat
->nat_ifnames
[1][LIFNAMSIZ
- 1] = '\0';
2811 nat
->nat_ifps
[1] = fr_resolvenic(nat
->nat_ifnames
[1], 4, ifs
);
2813 (void) strncpy(nat
->nat_ifnames
[1], nat
->nat_ifnames
[0],
2815 nat
->nat_ifnames
[1][LIFNAMSIZ
- 1] = '\0';
2816 nat
->nat_ifps
[1] = nat
->nat_ifps
[0];
2819 nat
->nat_next
= ifs
->ifs_nat_instances
;
2820 nat
->nat_pnext
= &ifs
->ifs_nat_instances
;
2821 if (ifs
->ifs_nat_instances
)
2822 ifs
->ifs_nat_instances
->nat_pnext
= &nat
->nat_next
;
2823 ifs
->ifs_nat_instances
= nat
;
2825 natp
= &ifs
->ifs_nat_table
[0][hv1
];
2827 (*natp
)->nat_phnext
[0] = &nat
->nat_hnext
[0];
2828 nat
->nat_phnext
[0] = natp
;
2829 nat
->nat_hnext
[0] = *natp
;
2831 ifs
->ifs_nat_stats
.ns_bucketlen
[0][hv1
]++;
2833 natp
= &ifs
->ifs_nat_table
[1][hv2
];
2835 (*natp
)->nat_phnext
[1] = &nat
->nat_hnext
[1];
2836 nat
->nat_phnext
[1] = natp
;
2837 nat
->nat_hnext
[1] = *natp
;
2839 ifs
->ifs_nat_stats
.ns_bucketlen
[1][hv2
]++;
2841 fr_setnatqueue(nat
, rev
, ifs
);
2843 ifs
->ifs_nat_stats
.ns_added
++;
2844 ifs
->ifs_nat_stats
.ns_inuse
++;
2849 /* ------------------------------------------------------------------------ */
2850 /* Function: nat_icmperrorlookup */
2851 /* Returns: nat_t* - point to matching NAT structure */
2852 /* Parameters: fin(I) - pointer to packet information */
2853 /* dir(I) - direction of packet (in/out) */
2855 /* Check if the ICMP error message is related to an existing TCP, UDP or */
2856 /* ICMP query nat entry. It is assumed that the packet is already of the */
2857 /* the required length. */
2858 /* ------------------------------------------------------------------------ */
2859 nat_t
*nat_icmperrorlookup(fin
, dir
)
2863 int flags
= 0, minlen
;
2865 tcphdr_t
*tcp
= NULL
;
2872 * Does it at least have the return (basic) IP header ?
2873 * Only a basic IP header (no options) should be with an ICMP error
2874 * header. Also, if it's not an error type, then return.
2876 if ((fin
->fin_hlen
!= sizeof(ip_t
)) || !(fin
->fin_flx
& FI_ICMPERR
))
2882 oip
= (ip_t
*)((char *)fin
->fin_dp
+ 8);
2883 minlen
= IP_HL(oip
) << 2;
2884 if ((minlen
< sizeof(ip_t
)) ||
2885 (fin
->fin_plen
< ICMPERR_IPICMPHLEN
+ minlen
))
2888 * Is the buffer big enough for all of it ? It's the size of the IP
2889 * header claimed in the encapsulated part which is of concern. It
2890 * may be too big to be in this buffer but not so big that it's
2891 * outside the ICMP packet, leading to TCP deref's causing problems.
2892 * This is possible because we don't know how big oip_hl is when we
2893 * do the pullup early in fr_check() and thus can't gaurantee it is
2901 # if defined(MENTAT)
2902 if ((char *)oip
+ fin
->fin_dlen
- ICMPERR_ICMPHLEN
> (char *)m
->b_wptr
)
2905 if ((char *)oip
+ fin
->fin_dlen
- ICMPERR_ICMPHLEN
>
2906 (char *)fin
->fin_ip
+ M_LEN(m
))
2912 if (fin
->fin_daddr
!= oip
->ip_src
.s_addr
)
2916 if (p
== IPPROTO_TCP
)
2918 else if (p
== IPPROTO_UDP
)
2920 else if (p
== IPPROTO_ICMP
) {
2921 orgicmp
= (icmphdr_t
*)((char *)oip
+ (IP_HL(oip
) << 2));
2923 /* see if this is related to an ICMP query */
2924 if (nat_icmpquerytype4(orgicmp
->icmp_type
)) {
2925 data
[0] = fin
->fin_data
[0];
2926 data
[1] = fin
->fin_data
[1];
2927 fin
->fin_data
[0] = 0;
2928 fin
->fin_data
[1] = orgicmp
->icmp_id
;
2930 flags
= IPN_ICMPERR
|IPN_ICMPQUERY
;
2932 * NOTE : dir refers to the direction of the original
2933 * ip packet. By definition the icmp error
2934 * message flows in the opposite direction.
2936 if (dir
== NAT_INBOUND
)
2937 nat
= nat_inlookup(fin
, flags
, p
, oip
->ip_dst
,
2940 nat
= nat_outlookup(fin
, flags
, p
, oip
->ip_dst
,
2942 fin
->fin_data
[0] = data
[0];
2943 fin
->fin_data
[1] = data
[1];
2948 if (flags
& IPN_TCPUDP
) {
2949 minlen
+= 8; /* + 64bits of data to get ports */
2950 if (fin
->fin_plen
< ICMPERR_IPICMPHLEN
+ minlen
)
2953 data
[0] = fin
->fin_data
[0];
2954 data
[1] = fin
->fin_data
[1];
2955 tcp
= (tcphdr_t
*)((char *)oip
+ (IP_HL(oip
) << 2));
2956 fin
->fin_data
[0] = ntohs(tcp
->th_dport
);
2957 fin
->fin_data
[1] = ntohs(tcp
->th_sport
);
2959 if (dir
== NAT_INBOUND
) {
2960 nat
= nat_inlookup(fin
, flags
, p
, oip
->ip_dst
,
2963 nat
= nat_outlookup(fin
, flags
, p
, oip
->ip_dst
,
2966 fin
->fin_data
[0] = data
[0];
2967 fin
->fin_data
[1] = data
[1];
2970 if (dir
== NAT_INBOUND
)
2971 return nat_inlookup(fin
, 0, p
, oip
->ip_dst
, oip
->ip_src
);
2973 return nat_outlookup(fin
, 0, p
, oip
->ip_dst
, oip
->ip_src
);
2977 /* ------------------------------------------------------------------------ */
2978 /* Function: nat_icmperror */
2979 /* Returns: nat_t* - point to matching NAT structure */
2980 /* Parameters: fin(I) - pointer to packet information */
2981 /* nflags(I) - NAT flags for this packet */
2982 /* dir(I) - direction of packet (in/out) */
2984 /* Fix up an ICMP packet which is an error message for an existing NAT */
2985 /* session. This will correct both packet header data and checksums. */
2987 /* This should *ONLY* be used for incoming ICMP error packets to make sure */
2988 /* a NAT'd ICMP packet gets correctly recognised. */
2989 /* ------------------------------------------------------------------------ */
2990 nat_t
*nat_icmperror(fin
, nflags
, dir
)
2995 u_32_t sum1
, sum2
, sumd
, psum1
, psum2
, psumd
, sumd2
;
2997 icmphdr_t
*icmp
, *orgicmp
;
3003 if ((fin
->fin_flx
& (FI_SHORT
|FI_FRAGBODY
)))
3007 * nat_icmperrorlookup() looks up nat entry associated with the
3008 * offending IP packet and returns pointer to the entry, or NULL
3009 * if packet wasn't natted or for `defective' packets.
3012 if ((fin
->fin_v
!= 4) || !(nat
= nat_icmperrorlookup(fin
, dir
)))
3016 *nflags
= IPN_ICMPERR
;
3018 oip
= (ip_t
*)&icmp
->icmp_ip
;
3019 udp
= (udphdr_t
*)((((char *)oip
) + (IP_HL(oip
) << 2)));
3020 tcp
= (tcphdr_t
*)udp
;
3021 dlen
= fin
->fin_plen
- ((char *)udp
- (char *)fin
->fin_ip
);
3024 * Need to adjust ICMP header to include the real IP#'s and
3025 * port #'s. There are three steps required.
3028 * Fix the IP addresses in the offending IP packet and update
3029 * ip header checksum to compensate for the change.
3031 * No update needed here for icmp_cksum because the ICMP checksum
3032 * is calculated over the complete ICMP packet, which includes the
3033 * changed oip IP addresses and oip->ip_sum. These two changes
3034 * cancel each other out (if the delta for the IP address is x,
3035 * then the delta for ip_sum is minus x).
3038 if (oip
->ip_dst
.s_addr
== nat
->nat_oip
.s_addr
) {
3039 sum1
= LONG_SUM(ntohl(oip
->ip_src
.s_addr
));
3043 sum1
= LONG_SUM(ntohl(oip
->ip_dst
.s_addr
));
3044 in
= nat
->nat_outip
;
3048 sum2
= LONG_SUM(ntohl(in
.s_addr
));
3049 CALC_SUMD(sum1
, sum2
, sumd
);
3050 fix_datacksum(&oip
->ip_sum
, sumd
);
3054 * Perform other adjustments based on protocol of offending packet.
3057 switch (oip
->ip_p
) {
3062 * For offending TCP/UDP IP packets, translate the ports
3063 * based on the NAT specification.
3065 * Advance notice : Now it becomes complicated :-)
3067 * Since the port and IP addresse fields are both part
3068 * of the TCP/UDP checksum of the offending IP packet,
3069 * we need to adjust that checksum as well.
3071 * To further complicate things, the TCP/UDP checksum
3072 * may not be present. We must check to see if the
3073 * length of the data portion is big enough to hold
3074 * the checksum. In the UDP case, a test to determine
3075 * if the checksum is even set is also required.
3077 * Any changes to an IP address, port or checksum within
3078 * the ICMP packet requires a change to icmp_cksum.
3080 * Be extremely careful here ... The change is dependent
3081 * upon whether or not the TCP/UPD checksum is present.
3083 * If TCP/UPD checksum is present, the icmp_cksum must
3084 * compensate for checksum modification resulting from
3085 * IP address change only. Port change and resulting
3086 * data checksum adjustments cancel each other out.
3088 * If TCP/UDP checksum is not present, icmp_cksum must
3089 * compensate for port change only. The IP address
3090 * change does not modify anything else in this case.
3097 if ((tcp
->th_dport
== nat
->nat_oport
) &&
3098 (tcp
->th_sport
!= nat
->nat_inport
)) {
3101 * Translate the source port.
3104 psum1
= ntohs(tcp
->th_sport
);
3105 psum2
= ntohs(nat
->nat_inport
);
3106 tcp
->th_sport
= nat
->nat_inport
;
3108 } else if ((tcp
->th_sport
== nat
->nat_oport
) &&
3109 (tcp
->th_dport
!= nat
->nat_outport
)) {
3112 * Translate the destination port.
3115 psum1
= ntohs(tcp
->th_dport
);
3116 psum2
= ntohs(nat
->nat_outport
);
3117 tcp
->th_dport
= nat
->nat_outport
;
3120 if ((oip
->ip_p
== IPPROTO_TCP
) && (dlen
>= 18)) {
3123 * TCP checksum present.
3125 * Adjust data checksum and icmp checksum to
3126 * compensate for any IP address change.
3129 sum1
= ntohs(tcp
->th_sum
);
3130 fix_datacksum(&tcp
->th_sum
, sumd
);
3131 sum2
= ntohs(tcp
->th_sum
);
3133 CALC_SUMD(sum1
, sum2
, sumd
);
3137 * Also make data checksum adjustment to
3138 * compensate for any port change.
3141 if (psum1
!= psum2
) {
3142 CALC_SUMD(psum1
, psum2
, psumd
);
3143 fix_datacksum(&tcp
->th_sum
, psumd
);
3146 } else if ((oip
->ip_p
== IPPROTO_UDP
) &&
3147 (dlen
>= 8) && (udp
->uh_sum
!= 0)) {
3150 * The UDP checksum is present and set.
3152 * Adjust data checksum and icmp checksum to
3153 * compensate for any IP address change.
3156 sum1
= ntohs(udp
->uh_sum
);
3157 fix_datacksum(&udp
->uh_sum
, sumd
);
3158 sum2
= ntohs(udp
->uh_sum
);
3160 CALC_SUMD(sum1
, sum2
, sumd
);
3164 * Also make data checksum adjustment to
3165 * compensate for any port change.
3168 if (psum1
!= psum2
) {
3169 CALC_SUMD(psum1
, psum2
, psumd
);
3170 fix_datacksum(&udp
->uh_sum
, psumd
);
3176 * Data checksum was not present.
3178 * Compensate for any port change.
3181 CALC_SUMD(psum2
, psum1
, psumd
);
3188 orgicmp
= (icmphdr_t
*)udp
;
3190 if ((nat
->nat_dir
== NAT_OUTBOUND
) &&
3191 (orgicmp
->icmp_id
!= nat
->nat_inport
) &&
3195 * Fix ICMP checksum (of the offening ICMP
3196 * query packet) to compensate the change
3197 * in the ICMP id of the offending ICMP
3200 * Since you modify orgicmp->icmp_id with
3201 * a delta (say x) and you compensate that
3202 * in origicmp->icmp_cksum with a delta
3203 * minus x, you don't have to adjust the
3204 * overall icmp->icmp_cksum
3207 sum1
= ntohs(orgicmp
->icmp_id
);
3208 sum2
= ntohs(nat
->nat_inport
);
3209 CALC_SUMD(sum1
, sum2
, sumd
);
3210 orgicmp
->icmp_id
= nat
->nat_inport
;
3211 fix_datacksum(&orgicmp
->icmp_cksum
, sumd
);
3213 } /* nat_dir can't be NAT_INBOUND for icmp queries */
3221 } /* switch (oip->ip_p) */
3225 * Make the adjustments to icmp checksum.
3229 sumd2
= (sumd2
& 0xffff) + (sumd2
>> 16);
3230 sumd2
= (sumd2
& 0xffff) + (sumd2
>> 16);
3231 fix_incksum(&icmp
->icmp_cksum
, sumd2
);
3238 * NB: these lookups don't lock access to the list, it assumed that it has
3239 * already been done!
3242 /* ------------------------------------------------------------------------ */
3243 /* Function: nat_inlookup */
3244 /* Returns: nat_t* - NULL == no match, */
3245 /* else pointer to matching NAT entry */
3246 /* Parameters: fin(I) - pointer to packet information */
3247 /* flags(I) - NAT flags for this packet */
3248 /* p(I) - protocol for this packet */
3249 /* src(I) - source IP address */
3250 /* mapdst(I) - destination IP address */
3252 /* Lookup a nat entry based on the mapped destination ip address/port and */
3253 /* real source address/port. We use this lookup when receiving a packet, */
3254 /* we're looking for a table entry, based on the destination address. */
3256 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
3258 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
3259 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
3261 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
3262 /* the packet is of said protocol */
3263 /* ------------------------------------------------------------------------ */
3264 nat_t
*nat_inlookup(fin
, flags
, p
, src
, mapdst
)
3267 struct in_addr src
, mapdst
;
3269 u_short sport
, dport
;
3277 ipf_stack_t
*ifs
= fin
->fin_ifs
;
3285 dst
= mapdst
.s_addr
;
3286 sflags
= flags
& NAT_TCPUDPICMP
;
3292 sport
= htons(fin
->fin_data
[0]);
3293 dport
= htons(fin
->fin_data
[1]);
3296 if (flags
& IPN_ICMPERR
)
3297 sport
= fin
->fin_data
[1];
3299 dport
= fin
->fin_data
[1];
3306 if ((flags
& SI_WILDP
) != 0)
3307 goto find_in_wild_ports
;
3309 hv
= NAT_HASH_FN(dst
, dport
, 0xffffffff);
3310 hv
= NAT_HASH_FN(src
.s_addr
, hv
+ sport
, ifs
->ifs_ipf_nattable_sz
);
3311 nat
= ifs
->ifs_nat_table
[1][hv
];
3312 for (; nat
; nat
= nat
->nat_hnext
[1]) {
3313 if (nat
->nat_v
!= 4)
3316 if (nat
->nat_ifps
[0] != NULL
) {
3317 if ((ifp
!= NULL
) && (ifp
!= nat
->nat_ifps
[0]))
3319 } else if (ifp
!= NULL
)
3320 nat
->nat_ifps
[0] = ifp
;
3322 nflags
= nat
->nat_flags
;
3324 if (nat
->nat_oip
.s_addr
== src
.s_addr
&&
3325 nat
->nat_outip
.s_addr
== dst
&&
3327 (sflags
== (nat
->nat_flags
& IPN_TCPUDPICMP
)))
3328 || (p
== nat
->nat_p
))) {
3333 if (nat
->nat_call
[1] != fin
->fin_data
[0])
3338 if ((flags
& IPN_ICMPERR
) != 0) {
3339 if (nat
->nat_outport
!= sport
)
3342 if (nat
->nat_outport
!= dport
)
3348 if (nat
->nat_oport
!= sport
)
3350 if (nat
->nat_outport
!= dport
)
3358 if ((ipn
!= NULL
) && (nat
->nat_aps
!= NULL
))
3359 if (appr_match(fin
, nat
) != 0)
3366 * So if we didn't find it but there are wildcard members in the hash
3367 * table, go back and look for them. We do this search and update here
3368 * because it is modifying the NAT table and we want to do this only
3369 * for the first packet that matches. The exception, of course, is
3370 * for "dummy" (FI_IGNORE) lookups.
3373 if (!(flags
& NAT_TCPUDP
) || !(flags
& NAT_SEARCH
))
3375 if (ifs
->ifs_nat_stats
.ns_wilds
== 0)
3378 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
3380 hv
= NAT_HASH_FN(dst
, 0, 0xffffffff);
3381 hv
= NAT_HASH_FN(src
.s_addr
, hv
, ifs
->ifs_ipf_nattable_sz
);
3383 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
3385 nat
= ifs
->ifs_nat_table
[1][hv
];
3386 for (; nat
; nat
= nat
->nat_hnext
[1]) {
3387 if (nat
->nat_v
!= 4)
3390 if (nat
->nat_ifps
[0] != NULL
) {
3391 if ((ifp
!= NULL
) && (ifp
!= nat
->nat_ifps
[0]))
3393 } else if (ifp
!= NULL
)
3394 nat
->nat_ifps
[0] = ifp
;
3396 if (nat
->nat_p
!= fin
->fin_p
)
3398 if (nat
->nat_oip
.s_addr
!= src
.s_addr
||
3399 nat
->nat_outip
.s_addr
!= dst
)
3402 nflags
= nat
->nat_flags
;
3403 if (!(nflags
& (NAT_TCPUDP
|SI_WILDP
)))
3406 if (nat_wildok(nat
, (int)sport
, (int)dport
, nflags
,
3407 NAT_INBOUND
) == 1) {
3408 if ((fin
->fin_flx
& FI_IGNORE
) != 0)
3410 if ((nflags
& SI_CLONE
) != 0) {
3411 nat
= fr_natclone(fin
, nat
);
3415 MUTEX_ENTER(&ifs
->ifs_ipf_nat_new
);
3416 ifs
->ifs_nat_stats
.ns_wilds
--;
3417 MUTEX_EXIT(&ifs
->ifs_ipf_nat_new
);
3419 nat
->nat_oport
= sport
;
3420 nat
->nat_outport
= dport
;
3421 nat
->nat_flags
&= ~(SI_W_DPORT
|SI_W_SPORT
);
3422 nat_tabmove(nat
, ifs
);
3427 MUTEX_DOWNGRADE(&ifs
->ifs_ipf_nat
);
3433 /* ------------------------------------------------------------------------ */
3434 /* Function: nat_tabmove */
3436 /* Parameters: nat(I) - pointer to NAT structure */
3437 /* Write Lock: ipf_nat */
3439 /* This function is only called for TCP/UDP NAT table entries where the */
3440 /* original was placed in the table without hashing on the ports and we now */
3441 /* want to include hashing on port numbers. */
3442 /* ------------------------------------------------------------------------ */
3443 static void nat_tabmove(nat
, ifs
)
3450 if (nat
->nat_flags
& SI_CLONE
)
3454 * Remove the NAT entry from the old location
3456 if (nat
->nat_hnext
[0])
3457 nat
->nat_hnext
[0]->nat_phnext
[0] = nat
->nat_phnext
[0];
3458 *nat
->nat_phnext
[0] = nat
->nat_hnext
[0];
3459 ifs
->ifs_nat_stats
.ns_bucketlen
[0][nat
->nat_hv
[0]]--;
3461 if (nat
->nat_hnext
[1])
3462 nat
->nat_hnext
[1]->nat_phnext
[1] = nat
->nat_phnext
[1];
3463 *nat
->nat_phnext
[1] = nat
->nat_hnext
[1];
3464 ifs
->ifs_nat_stats
.ns_bucketlen
[1][nat
->nat_hv
[1]]--;
3467 * Add into the NAT table in the new position
3469 hv
= NAT_HASH_FN(nat
->nat_inip
.s_addr
, nat
->nat_inport
, 0xffffffff);
3470 hv
= NAT_HASH_FN(nat
->nat_oip
.s_addr
, hv
+ nat
->nat_oport
,
3471 ifs
->ifs_ipf_nattable_sz
);
3472 nat
->nat_hv
[0] = hv
;
3473 natp
= &ifs
->ifs_nat_table
[0][hv
];
3475 (*natp
)->nat_phnext
[0] = &nat
->nat_hnext
[0];
3476 nat
->nat_phnext
[0] = natp
;
3477 nat
->nat_hnext
[0] = *natp
;
3479 ifs
->ifs_nat_stats
.ns_bucketlen
[0][hv
]++;
3481 hv
= NAT_HASH_FN(nat
->nat_outip
.s_addr
, nat
->nat_outport
, 0xffffffff);
3482 hv
= NAT_HASH_FN(nat
->nat_oip
.s_addr
, hv
+ nat
->nat_oport
,
3483 ifs
->ifs_ipf_nattable_sz
);
3484 nat
->nat_hv
[1] = hv
;
3485 natp
= &ifs
->ifs_nat_table
[1][hv
];
3487 (*natp
)->nat_phnext
[1] = &nat
->nat_hnext
[1];
3488 nat
->nat_phnext
[1] = natp
;
3489 nat
->nat_hnext
[1] = *natp
;
3491 ifs
->ifs_nat_stats
.ns_bucketlen
[1][hv
]++;
3495 /* ------------------------------------------------------------------------ */
3496 /* Function: nat_outlookup */
3497 /* Returns: nat_t* - NULL == no match, */
3498 /* else pointer to matching NAT entry */
3499 /* Parameters: fin(I) - pointer to packet information */
3500 /* flags(I) - NAT flags for this packet */
3501 /* p(I) - protocol for this packet */
3502 /* src(I) - source IP address */
3503 /* dst(I) - destination IP address */
3504 /* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */
3506 /* Lookup a nat entry based on the source 'real' ip address/port and */
3507 /* destination address/port. We use this lookup when sending a packet out, */
3508 /* we're looking for a table entry, based on the source address. */
3510 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
3512 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
3513 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
3515 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
3516 /* the packet is of said protocol */
3517 /* ------------------------------------------------------------------------ */
3518 nat_t
*nat_outlookup(fin
, flags
, p
, src
, dst
)
3521 struct in_addr src
, dst
;
3523 u_short sport
, dport
;
3531 ipf_stack_t
*ifs
= fin
->fin_ifs
;
3536 sflags
= flags
& IPN_TCPUDPICMP
;
3544 sport
= htons(fin
->fin_data
[0]);
3545 dport
= htons(fin
->fin_data
[1]);
3548 if (flags
& IPN_ICMPERR
)
3549 sport
= fin
->fin_data
[1];
3551 dport
= fin
->fin_data
[1];
3557 if ((flags
& SI_WILDP
) != 0)
3558 goto find_out_wild_ports
;
3560 hv
= NAT_HASH_FN(srcip
, sport
, 0xffffffff);
3561 hv
= NAT_HASH_FN(dst
.s_addr
, hv
+ dport
, ifs
->ifs_ipf_nattable_sz
);
3562 nat
= ifs
->ifs_nat_table
[0][hv
];
3563 for (; nat
; nat
= nat
->nat_hnext
[0]) {
3564 if (nat
->nat_v
!= 4)
3567 if (nat
->nat_ifps
[1] != NULL
) {
3568 if ((ifp
!= NULL
) && (ifp
!= nat
->nat_ifps
[1]))
3570 } else if (ifp
!= NULL
)
3571 nat
->nat_ifps
[1] = ifp
;
3573 nflags
= nat
->nat_flags
;
3575 if (nat
->nat_inip
.s_addr
== srcip
&&
3576 nat
->nat_oip
.s_addr
== dst
.s_addr
&&
3577 (((p
== 0) && (sflags
== (nflags
& NAT_TCPUDPICMP
)))
3578 || (p
== nat
->nat_p
))) {
3583 if (nat
->nat_call
[1] != fin
->fin_data
[0])
3589 if (nat
->nat_oport
!= dport
)
3591 if (nat
->nat_inport
!= sport
)
3599 if ((ipn
!= NULL
) && (nat
->nat_aps
!= NULL
))
3600 if (appr_match(fin
, nat
) != 0)
3607 * So if we didn't find it but there are wildcard members in the hash
3608 * table, go back and look for them. We do this search and update here
3609 * because it is modifying the NAT table and we want to do this only
3610 * for the first packet that matches. The exception, of course, is
3611 * for "dummy" (FI_IGNORE) lookups.
3613 find_out_wild_ports
:
3614 if (!(flags
& NAT_TCPUDP
) || !(flags
& NAT_SEARCH
))
3616 if (ifs
->ifs_nat_stats
.ns_wilds
== 0)
3619 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
3621 hv
= NAT_HASH_FN(srcip
, 0, 0xffffffff);
3622 hv
= NAT_HASH_FN(dst
.s_addr
, hv
, ifs
->ifs_ipf_nattable_sz
);
3624 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
3626 nat
= ifs
->ifs_nat_table
[0][hv
];
3627 for (; nat
; nat
= nat
->nat_hnext
[0]) {
3628 if (nat
->nat_v
!= 4)
3631 if (nat
->nat_ifps
[1] != NULL
) {
3632 if ((ifp
!= NULL
) && (ifp
!= nat
->nat_ifps
[1]))
3634 } else if (ifp
!= NULL
)
3635 nat
->nat_ifps
[1] = ifp
;
3637 if (nat
->nat_p
!= fin
->fin_p
)
3639 if ((nat
->nat_inip
.s_addr
!= srcip
) ||
3640 (nat
->nat_oip
.s_addr
!= dst
.s_addr
))
3643 nflags
= nat
->nat_flags
;
3644 if (!(nflags
& (NAT_TCPUDP
|SI_WILDP
)))
3647 if (nat_wildok(nat
, (int)sport
, (int)dport
, nflags
,
3648 NAT_OUTBOUND
) == 1) {
3649 if ((fin
->fin_flx
& FI_IGNORE
) != 0)
3651 if ((nflags
& SI_CLONE
) != 0) {
3652 nat
= fr_natclone(fin
, nat
);
3656 MUTEX_ENTER(&ifs
->ifs_ipf_nat_new
);
3657 ifs
->ifs_nat_stats
.ns_wilds
--;
3658 MUTEX_EXIT(&ifs
->ifs_ipf_nat_new
);
3660 nat
->nat_inport
= sport
;
3661 nat
->nat_oport
= dport
;
3662 if (nat
->nat_outport
== 0)
3663 nat
->nat_outport
= sport
;
3664 nat
->nat_flags
&= ~(SI_W_DPORT
|SI_W_SPORT
);
3665 nat_tabmove(nat
, ifs
);
3670 MUTEX_DOWNGRADE(&ifs
->ifs_ipf_nat
);
3676 /* ------------------------------------------------------------------------ */
3677 /* Function: nat_lookupredir */
3678 /* Returns: nat_t* - NULL == no match, */
3679 /* else pointer to matching NAT entry */
3680 /* Parameters: np(I) - pointer to description of packet to find NAT table */
3683 /* Lookup the NAT tables to search for a matching redirect */
3684 /* ------------------------------------------------------------------------ */
3685 nat_t
*nat_lookupredir(np
, ifs
)
3692 bzero((char *)&fi
, sizeof(fi
));
3693 if (np
->nl_flags
& IPN_IN
) {
3694 fi
.fin_data
[0] = ntohs(np
->nl_realport
);
3695 fi
.fin_data
[1] = ntohs(np
->nl_outport
);
3697 fi
.fin_data
[0] = ntohs(np
->nl_inport
);
3698 fi
.fin_data
[1] = ntohs(np
->nl_outport
);
3700 if (np
->nl_flags
& IPN_TCP
)
3701 fi
.fin_p
= IPPROTO_TCP
;
3702 else if (np
->nl_flags
& IPN_UDP
)
3703 fi
.fin_p
= IPPROTO_UDP
;
3704 else if (np
->nl_flags
& (IPN_ICMPERR
|IPN_ICMPQUERY
))
3705 fi
.fin_p
= IPPROTO_ICMP
;
3709 * We can do two sorts of lookups:
3710 * - IPN_IN: we have the `real' and `out' address, look for `in'.
3711 * - default: we have the `in' and `out' address, look for `real'.
3713 if (np
->nl_flags
& IPN_IN
) {
3714 if ((nat
= nat_inlookup(&fi
, np
->nl_flags
, fi
.fin_p
,
3715 np
->nl_realip
, np
->nl_outip
))) {
3716 np
->nl_inip
= nat
->nat_inip
;
3717 np
->nl_inport
= nat
->nat_inport
;
3721 * If nl_inip is non null, this is a lookup based on the real
3722 * ip address. Else, we use the fake.
3724 if ((nat
= nat_outlookup(&fi
, np
->nl_flags
, fi
.fin_p
,
3725 np
->nl_inip
, np
->nl_outip
))) {
3727 if ((np
->nl_flags
& IPN_FINDFORWARD
) != 0) {
3729 bzero((char *)&fin
, sizeof(fin
));
3730 fin
.fin_p
= nat
->nat_p
;
3731 fin
.fin_data
[0] = ntohs(nat
->nat_outport
);
3732 fin
.fin_data
[1] = ntohs(nat
->nat_oport
);
3734 if (nat_inlookup(&fin
, np
->nl_flags
, fin
.fin_p
,
3736 nat
->nat_oip
) != NULL
) {
3737 np
->nl_flags
&= ~IPN_FINDFORWARD
;
3741 np
->nl_realip
= nat
->nat_outip
;
3742 np
->nl_realport
= nat
->nat_outport
;
3750 /* ------------------------------------------------------------------------ */
3751 /* Function: nat_match */
3752 /* Returns: int - 0 == no match, 1 == match */
3753 /* Parameters: fin(I) - pointer to packet information */
3754 /* np(I) - pointer to NAT rule */
3756 /* Pull the matching of a packet against a NAT rule out of that complex */
3757 /* loop inside fr_checknatin() and lay it out properly in its own function. */
3758 /* ------------------------------------------------------------------------ */
3759 static int nat_match(fin
, np
)
3765 if (fin
->fin_v
!= 4)
3768 if (np
->in_p
&& fin
->fin_p
!= np
->in_p
)
3772 if (!(np
->in_redir
& (NAT_MAP
|NAT_MAPBLK
)))
3774 if (((fin
->fin_fi
.fi_saddr
& np
->in_inmsk
) != np
->in_inip
)
3775 ^ ((np
->in_flags
& IPN_NOTSRC
) != 0))
3777 if (((fin
->fin_fi
.fi_daddr
& np
->in_srcmsk
) != np
->in_srcip
)
3778 ^ ((np
->in_flags
& IPN_NOTDST
) != 0))
3781 if (!(np
->in_redir
& NAT_REDIRECT
))
3783 if (((fin
->fin_fi
.fi_saddr
& np
->in_srcmsk
) != np
->in_srcip
)
3784 ^ ((np
->in_flags
& IPN_NOTSRC
) != 0))
3786 if (((fin
->fin_fi
.fi_daddr
& np
->in_outmsk
) != np
->in_outip
)
3787 ^ ((np
->in_flags
& IPN_NOTDST
) != 0))
3792 if (!(fin
->fin_flx
& FI_TCPUDP
) ||
3793 (fin
->fin_flx
& (FI_SHORT
|FI_FRAGBODY
))) {
3794 if (ft
->ftu_scmp
|| ft
->ftu_dcmp
)
3799 return fr_tcpudpchk(fin
, ft
);
3803 /* ------------------------------------------------------------------------ */
3804 /* Function: nat_update */
3806 /* Parameters: fin(I) - pointer to packet information */
3807 /* nat(I) - pointer to NAT structure */
3808 /* np(I) - pointer to NAT rule */
3809 /* Locks: nat_lock */
3811 /* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */
3812 /* called with fin_rev updated - i.e. after calling nat_proto(). */
3813 /* ------------------------------------------------------------------------ */
3814 void nat_update(fin
, nat
, np
)
3819 ipftq_t
*ifq
, *ifq2
;
3821 ipf_stack_t
*ifs
= fin
->fin_ifs
;
3823 tqe
= &nat
->nat_tqe
;
3827 * We allow over-riding of NAT timeouts from NAT rules, even for
3828 * TCP, however, if it is TCP and there is no rule timeout set,
3829 * then do not update the timeout here.
3832 ifq2
= np
->in_tqehead
[fin
->fin_rev
];
3836 if (nat
->nat_p
== IPPROTO_TCP
&& ifq2
== NULL
) {
3837 (void) fr_tcp_age(&nat
->nat_tqe
, fin
, ifs
->ifs_nat_tqb
, 0);
3840 if (nat
->nat_p
== IPPROTO_UDP
)
3841 ifq2
= &ifs
->ifs_nat_udptq
;
3842 else if (nat
->nat_p
== IPPROTO_ICMP
)
3843 ifq2
= &ifs
->ifs_nat_icmptq
;
3845 ifq2
= &ifs
->ifs_nat_iptq
;
3848 fr_movequeue(tqe
, ifq
, ifq2
, ifs
);
3853 /* ------------------------------------------------------------------------ */
3854 /* Function: fr_checknatout */
3855 /* Returns: int - -1 == packet failed NAT checks so block it, */
3856 /* 0 == no packet translation occurred, */
3857 /* 1 == packet was successfully translated. */
3858 /* Parameters: fin(I) - pointer to packet information */
3859 /* passp(I) - pointer to filtering result flags */
3861 /* Check to see if an outcoming packet should be changed. ICMP packets are */
3862 /* first checked to see if they match an existing entry (if an error), */
3863 /* otherwise a search of the current NAT table is made. If neither results */
3864 /* in a match then a search for a matching NAT rule is made. Create a new */
3865 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */
3866 /* packet header(s) as required. */
3867 /* ------------------------------------------------------------------------ */
3868 int fr_checknatout(fin
, passp
)
3872 ipnat_t
*np
= NULL
, *npnext
;
3873 struct ifnet
*ifp
, *sifp
;
3874 icmphdr_t
*icmp
= NULL
;
3875 tcphdr_t
*tcp
= NULL
;
3876 int rval
, natfailed
;
3882 ipf_stack_t
*ifs
= fin
->fin_ifs
;
3884 if (ifs
->ifs_fr_nat_lock
!= 0)
3886 if (ifs
->ifs_nat_stats
.ns_rules
== 0 && ifs
->ifs_nat_instances
== NULL
)
3891 sifp
= fin
->fin_ifp
;
3892 if ((fr
!= NULL
) && !(fr
->fr_flags
& FR_DUP
) &&
3893 fr
->fr_tifs
[fin
->fin_rev
].fd_ifp
&&
3894 fr
->fr_tifs
[fin
->fin_rev
].fd_ifp
!= (void *)-1)
3895 fin
->fin_ifp
= fr
->fr_tifs
[fin
->fin_rev
].fd_ifp
;
3898 if (!(fin
->fin_flx
& FI_SHORT
) && (fin
->fin_off
== 0)) {
3911 * This is an incoming packet, so the destination is
3912 * the icmp_id and the source port equals 0
3914 if (nat_icmpquerytype4(icmp
->icmp_type
))
3915 nflags
= IPN_ICMPQUERY
;
3921 if ((nflags
& IPN_TCPUDP
))
3925 ipa
= fin
->fin_saddr
;
3927 READ_ENTER(&ifs
->ifs_ipf_nat
);
3929 if ((fin
->fin_p
== IPPROTO_ICMP
) && !(nflags
& IPN_ICMPQUERY
) &&
3930 (nat
= nat_icmperror(fin
, &nflags
, NAT_OUTBOUND
)))
3932 else if ((fin
->fin_flx
& FI_FRAG
) && (nat
= fr_nat_knownfrag(fin
)))
3934 else if ((nat
= nat_outlookup(fin
, nflags
|NAT_SEARCH
, (u_int
)fin
->fin_p
,
3935 fin
->fin_src
, fin
->fin_dst
))) {
3936 nflags
= nat
->nat_flags
;
3938 u_32_t hv
, msk
, nmsk
;
3941 * There is no current entry in the nat table for this packet.
3943 * If the packet is a fragment, but not the first fragment,
3944 * then don't do anything. Otherwise, if there is a matching
3945 * nat rule, try to create a new nat entry.
3947 if ((fin
->fin_off
!= 0) && (fin
->fin_flx
& FI_TCPUDP
))
3951 nmsk
= ifs
->ifs_nat_masks
;
3953 iph
= ipa
& htonl(msk
);
3954 hv
= NAT_HASH_FN(iph
, 0, ifs
->ifs_ipf_natrules_sz
);
3955 for (np
= ifs
->ifs_nat_rules
[hv
]; np
; np
= npnext
) {
3956 npnext
= np
->in_mnext
;
3957 if ((np
->in_ifps
[1] && (np
->in_ifps
[1] != ifp
)))
3959 if (np
->in_v
!= fin
->fin_v
)
3961 if (np
->in_p
&& (np
->in_p
!= fin
->fin_p
))
3963 if ((np
->in_flags
& IPN_RF
) && !(np
->in_flags
& nflags
))
3965 if (np
->in_flags
& IPN_FILTER
) {
3966 if (!nat_match(fin
, np
))
3968 } else if ((ipa
& np
->in_inmsk
) != np
->in_inip
)
3972 !fr_matchtag(&np
->in_tag
, &fr
->fr_nattag
))
3975 if (*np
->in_plabel
!= '\0') {
3976 if (((np
->in_flags
& IPN_FILTER
) == 0) &&
3977 (np
->in_dport
!= tcp
->th_dport
))
3979 if (appr_ok(fin
, tcp
, np
) == 0)
3983 ATOMIC_INC32(np
->in_use
);
3984 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
3985 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
3986 nat
= nat_new(fin
, np
, NULL
, nflags
, NAT_OUTBOUND
);
3990 MUTEX_DOWNGRADE(&ifs
->ifs_ipf_nat
);
3994 npnext
= np
->in_mnext
;
3995 fr_ipnatderef(&np
, ifs
);
3996 MUTEX_DOWNGRADE(&ifs
->ifs_ipf_nat
);
3998 if ((np
== NULL
) && (nmsk
!= 0)) {
4001 if (nmsk
& 0x80000000)
4014 rval
= fr_natout(fin
, nat
, natadd
, nflags
);
4016 MUTEX_ENTER(&nat
->nat_lock
);
4017 nat_update(fin
, nat
, nat
->nat_ptr
);
4018 nat
->nat_bytes
[1] += fin
->fin_plen
;
4020 fin
->fin_pktnum
= nat
->nat_pkts
[1];
4021 MUTEX_EXIT(&nat
->nat_lock
);
4025 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4030 fin
->fin_flx
|= FI_BADNAT
;
4032 fin
->fin_ifp
= sifp
;
4036 /* ------------------------------------------------------------------------ */
4037 /* Function: fr_natout */
4038 /* Returns: int - -1 == packet failed NAT checks so block it, */
4039 /* 1 == packet was successfully translated. */
4040 /* Parameters: fin(I) - pointer to packet information */
4041 /* nat(I) - pointer to NAT structure */
4042 /* natadd(I) - flag indicating if it is safe to add frag cache */
4043 /* nflags(I) - NAT flags set for this packet */
4045 /* Translate a packet coming "out" on an interface. */
4046 /* ------------------------------------------------------------------------ */
4047 int fr_natout(fin
, nat
, natadd
, nflags
)
4059 ipf_stack_t
*ifs
= fin
->fin_ifs
;
4061 if (fin
->fin_v
== 6) {
4063 return fr_nat6out(fin
, nat
, natadd
, nflags
);
4069 #if SOLARIS && defined(_KERNEL)
4070 net_handle_t net_data_p
= ifs
->ifs_ipf_ipv4
;
4078 if ((natadd
!= 0) && (fin
->fin_flx
& FI_FRAG
))
4079 (void) fr_nat_newfrag(fin
, 0, nat
);
4082 * Fix up checksums, not by recalculating them, but
4083 * simply computing adjustments.
4084 * This is only done for STREAMS based IP implementations where the
4085 * checksum has already been calculated by IP. In all other cases,
4086 * IPFilter is called before the checksum needs calculating so there
4087 * is no call to modify whatever is in the header now.
4089 ASSERT(fin
->fin_m
!= NULL
);
4090 if (fin
->fin_v
== 4 && !NET_IS_HCK_L3_FULL(net_data_p
, fin
->fin_m
)) {
4091 if (nflags
== IPN_ICMPERR
) {
4094 s1
= LONG_SUM(ntohl(fin
->fin_saddr
));
4095 s2
= LONG_SUM(ntohl(nat
->nat_outip
.s_addr
));
4096 CALC_SUMD(s1
, s2
, sumd
);
4098 fix_outcksum(&fin
->fin_ip
->ip_sum
, sumd
);
4100 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
4101 defined(linux) || defined(BRIDGE_IPF)
4104 * Strictly speaking, this isn't necessary on BSD
4105 * kernels because they do checksum calculation after
4106 * this code has run BUT if ipfilter is being used
4107 * to do NAT as a bridge, that code doesn't exist.
4109 if (nat
->nat_dir
== NAT_OUTBOUND
)
4110 fix_outcksum(&fin
->fin_ip
->ip_sum
,
4113 fix_incksum(&fin
->fin_ip
->ip_sum
,
4119 if (!(fin
->fin_flx
& FI_SHORT
) && (fin
->fin_off
== 0)) {
4120 if ((nat
->nat_outport
!= 0) && (nflags
& IPN_TCPUDP
)) {
4123 tcp
->th_sport
= nat
->nat_outport
;
4124 fin
->fin_data
[0] = ntohs(nat
->nat_outport
);
4127 if ((nat
->nat_outport
!= 0) && (nflags
& IPN_ICMPQUERY
)) {
4129 icmp
->icmp_id
= nat
->nat_outport
;
4132 csump
= nat_proto(fin
, nat
, nflags
);
4135 fin
->fin_ip
->ip_src
= nat
->nat_outip
;
4138 * The above comments do not hold for layer 4 (or higher) checksums...
4140 if (csump
!= NULL
&& !NET_IS_HCK_L4_FULL(net_data_p
, fin
->fin_m
)) {
4141 if (nflags
& IPN_TCPUDP
&&
4142 NET_IS_HCK_L4_PART(net_data_p
, fin
->fin_m
))
4143 sumd
= nat
->nat_sumd
[1];
4145 sumd
= nat
->nat_sumd
[0];
4147 if (nat
->nat_dir
== NAT_OUTBOUND
)
4148 fix_outcksum(csump
, sumd
);
4150 fix_incksum(csump
, sumd
);
4152 #ifdef IPFILTER_SYNC
4153 ipfsync_update(SMC_NAT
, fin
, nat
->nat_sync
);
4155 /* ------------------------------------------------------------- */
4156 /* A few quick notes: */
4157 /* Following are test conditions prior to calling the */
4158 /* appr_check routine. */
4160 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
4161 /* with a redirect rule, we attempt to match the packet's */
4162 /* source port against in_dport, otherwise we'd compare the */
4163 /* packet's destination. */
4164 /* ------------------------------------------------------------- */
4165 if ((np
!= NULL
) && (np
->in_apr
!= NULL
)) {
4166 i
= appr_check(fin
, nat
);
4171 ifs
->ifs_nat_stats
.ns_mapped
[1]++;
4172 fin
->fin_flx
|= FI_NATED
;
4177 /* ------------------------------------------------------------------------ */
4178 /* Function: fr_checknatin */
4179 /* Returns: int - -1 == packet failed NAT checks so block it, */
4180 /* 0 == no packet translation occurred, */
4181 /* 1 == packet was successfully translated. */
4182 /* Parameters: fin(I) - pointer to packet information */
4183 /* passp(I) - pointer to filtering result flags */
4185 /* Check to see if an incoming packet should be changed. ICMP packets are */
4186 /* first checked to see if they match an existing entry (if an error), */
4187 /* otherwise a search of the current NAT table is made. If neither results */
4188 /* in a match then a search for a matching NAT rule is made. Create a new */
4189 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */
4190 /* packet header(s) as required. */
4191 /* ------------------------------------------------------------------------ */
4192 int fr_checknatin(fin
, passp
)
4196 u_int nflags
, natadd
;
4197 ipnat_t
*np
, *npnext
;
4198 int rval
, natfailed
;
4206 ipf_stack_t
*ifs
= fin
->fin_ifs
;
4208 if (ifs
->ifs_fr_nat_lock
!= 0)
4210 if (ifs
->ifs_nat_stats
.ns_rules
== 0 && ifs
->ifs_nat_instances
== NULL
)
4221 if (!(fin
->fin_flx
& FI_SHORT
) && (fin
->fin_off
== 0)) {
4234 * This is an incoming packet, so the destination is
4235 * the icmp_id and the source port equals 0
4237 if (nat_icmpquerytype4(icmp
->icmp_type
)) {
4238 nflags
= IPN_ICMPQUERY
;
4239 dport
= icmp
->icmp_id
;
4245 if ((nflags
& IPN_TCPUDP
)) {
4247 dport
= tcp
->th_dport
;
4253 READ_ENTER(&ifs
->ifs_ipf_nat
);
4255 if ((fin
->fin_p
== IPPROTO_ICMP
) && !(nflags
& IPN_ICMPQUERY
) &&
4256 (nat
= nat_icmperror(fin
, &nflags
, NAT_INBOUND
)))
4258 else if ((fin
->fin_flx
& FI_FRAG
) && (nat
= fr_nat_knownfrag(fin
)))
4260 else if ((nat
= nat_inlookup(fin
, nflags
|NAT_SEARCH
, (u_int
)fin
->fin_p
,
4261 fin
->fin_src
, in
))) {
4262 nflags
= nat
->nat_flags
;
4264 u_32_t hv
, msk
, rmsk
;
4267 * There is no current entry in the nat table for this packet.
4269 * If the packet is a fragment, but not the first fragment,
4270 * then don't do anything. Otherwise, if there is a matching
4271 * nat rule, try to create a new nat entry.
4273 if ((fin
->fin_off
!= 0) && (fin
->fin_flx
& FI_TCPUDP
))
4276 rmsk
= ifs
->ifs_rdr_masks
;
4279 iph
= in
.s_addr
& htonl(msk
);
4280 hv
= NAT_HASH_FN(iph
, 0, ifs
->ifs_ipf_rdrrules_sz
);
4281 for (np
= ifs
->ifs_rdr_rules
[hv
]; np
; np
= npnext
) {
4282 npnext
= np
->in_rnext
;
4283 if (np
->in_ifps
[0] && (np
->in_ifps
[0] != ifp
))
4285 if (np
->in_v
!= fin
->fin_v
)
4287 if (np
->in_p
&& (np
->in_p
!= fin
->fin_p
))
4289 if ((np
->in_flags
& IPN_RF
) && !(np
->in_flags
& nflags
))
4291 if (np
->in_flags
& IPN_FILTER
) {
4292 if (!nat_match(fin
, np
))
4295 if ((in
.s_addr
& np
->in_outmsk
) != np
->in_outip
)
4298 ((ntohs(np
->in_pmax
) < ntohs(dport
)) ||
4299 (ntohs(dport
) < ntohs(np
->in_pmin
))))
4303 if (*np
->in_plabel
!= '\0') {
4304 if (!appr_ok(fin
, tcp
, np
)) {
4309 ATOMIC_INC32(np
->in_use
);
4310 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4311 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
4312 nat
= nat_new(fin
, np
, NULL
, nflags
, NAT_INBOUND
);
4316 MUTEX_DOWNGRADE(&ifs
->ifs_ipf_nat
);
4320 npnext
= np
->in_rnext
;
4321 fr_ipnatderef(&np
, ifs
);
4322 MUTEX_DOWNGRADE(&ifs
->ifs_ipf_nat
);
4325 if ((np
== NULL
) && (rmsk
!= 0)) {
4328 if (rmsk
& 0x80000000)
4341 rval
= fr_natin(fin
, nat
, natadd
, nflags
);
4343 MUTEX_ENTER(&nat
->nat_lock
);
4344 nat_update(fin
, nat
, nat
->nat_ptr
);
4345 nat
->nat_bytes
[0] += fin
->fin_plen
;
4347 fin
->fin_pktnum
= nat
->nat_pkts
[0];
4348 MUTEX_EXIT(&nat
->nat_lock
);
4352 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4357 fin
->fin_flx
|= FI_BADNAT
;
4363 /* ------------------------------------------------------------------------ */
4364 /* Function: fr_natin */
4365 /* Returns: int - -1 == packet failed NAT checks so block it, */
4366 /* 1 == packet was successfully translated. */
4367 /* Parameters: fin(I) - pointer to packet information */
4368 /* nat(I) - pointer to NAT structure */
4369 /* natadd(I) - flag indicating if it is safe to add frag cache */
4370 /* nflags(I) - NAT flags set for this packet */
4371 /* Locks Held: ipf_nat (READ) */
4373 /* Translate a packet coming "in" on an interface. */
4374 /* ------------------------------------------------------------------------ */
4375 int fr_natin(fin
, nat
, natadd
, nflags
)
4386 ipf_stack_t
*ifs
= fin
->fin_ifs
;
4388 if (fin
->fin_v
== 6) {
4390 return fr_nat6in(fin
, nat
, natadd
, nflags
);
4396 #if SOLARIS && defined(_KERNEL)
4397 net_handle_t net_data_p
= ifs
->ifs_ipf_ipv4
;
4403 fin
->fin_fr
= nat
->nat_fr
;
4405 if ((natadd
!= 0) && (fin
->fin_flx
& FI_FRAG
))
4406 (void) fr_nat_newfrag(fin
, 0, nat
);
4410 /* ------------------------------------------------------------- */
4411 /* A few quick notes: */
4412 /* Following are test conditions prior to calling the */
4413 /* appr_check routine. */
4415 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
4416 /* with a map rule, we attempt to match the packet's */
4417 /* source port against in_dport, otherwise we'd compare the */
4418 /* packet's destination. */
4419 /* ------------------------------------------------------------- */
4420 if (np
->in_apr
!= NULL
) {
4421 i
= appr_check(fin
, nat
);
4428 #ifdef IPFILTER_SYNC
4429 ipfsync_update(SMC_NAT
, fin
, nat
->nat_sync
);
4432 fin
->fin_ip
->ip_dst
= nat
->nat_inip
;
4433 fin
->fin_fi
.fi_daddr
= nat
->nat_inip
.s_addr
;
4434 if (nflags
& IPN_TCPUDP
)
4438 * Fix up checksums, not by recalculating them, but
4439 * simply computing adjustments.
4440 * Why only do this for some platforms on inbound packets ?
4441 * Because for those that it is done, IP processing is yet to happen
4442 * and so the IPv4 header checksum has not yet been evaluated.
4443 * Perhaps it should always be done for the benefit of things like
4444 * fast forwarding (so that it doesn't need to be recomputed) but with
4445 * header checksum offloading, perhaps it is a moot point.
4447 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
4448 defined(__osf__) || defined(linux)
4449 if (nat
->nat_dir
== NAT_OUTBOUND
)
4450 fix_incksum(&fin
->fin_ip
->ip_sum
, nat
->nat_ipsumd
);
4452 fix_outcksum(&fin
->fin_ip
->ip_sum
, nat
->nat_ipsumd
);
4455 if (!(fin
->fin_flx
& FI_SHORT
) && (fin
->fin_off
== 0)) {
4456 if ((nat
->nat_inport
!= 0) && (nflags
& IPN_TCPUDP
)) {
4457 tcp
->th_dport
= nat
->nat_inport
;
4458 fin
->fin_data
[1] = ntohs(nat
->nat_inport
);
4462 if ((nat
->nat_inport
!= 0) && (nflags
& IPN_ICMPQUERY
)) {
4465 icmp
->icmp_id
= nat
->nat_inport
;
4468 csump
= nat_proto(fin
, nat
, nflags
);
4472 * In case they are being forwarded, inbound packets always need to have
4473 * their checksum adjusted even if hardware checksum validation said OK.
4475 if (csump
!= NULL
) {
4476 if (nat
->nat_dir
== NAT_OUTBOUND
)
4477 fix_incksum(csump
, nat
->nat_sumd
[0]);
4479 fix_outcksum(csump
, nat
->nat_sumd
[0]);
4482 #if SOLARIS && defined(_KERNEL)
4483 if (nflags
& IPN_TCPUDP
&&
4484 NET_IS_HCK_L4_PART(net_data_p
, fin
->fin_m
)) {
4486 * Need to adjust the partial checksum result stored in
4487 * db_cksum16, which will be used for validation in IP.
4488 * See IP_CKSUM_RECV().
4489 * Adjustment data should be the inverse of the IP address
4490 * changes, because db_cksum16 is supposed to be the complement
4491 * of the pesudo header.
4493 csump
= &fin
->fin_m
->b_datap
->db_cksum16
;
4494 if (nat
->nat_dir
== NAT_OUTBOUND
)
4495 fix_outcksum(csump
, nat
->nat_sumd
[1]);
4497 fix_incksum(csump
, nat
->nat_sumd
[1]);
4501 ifs
->ifs_nat_stats
.ns_mapped
[0]++;
4502 fin
->fin_flx
|= FI_NATED
;
4503 if (np
!= NULL
&& np
->in_tag
.ipt_num
[0] != 0)
4504 fin
->fin_nattag
= &np
->in_tag
;
4509 /* ------------------------------------------------------------------------ */
4510 /* Function: nat_proto */
4511 /* Returns: u_short* - pointer to transport header checksum to update, */
4512 /* NULL if the transport protocol is not recognised */
4513 /* as needing a checksum update. */
4514 /* Parameters: fin(I) - pointer to packet information */
4515 /* nat(I) - pointer to NAT structure */
4516 /* nflags(I) - NAT flags set for this packet */
4518 /* Return the pointer to the checksum field for each protocol so understood.*/
4519 /* If support for making other changes to a protocol header is required, */
4520 /* that is not strictly 'address' translation, such as clamping the MSS in */
4521 /* TCP down to a specific value, then do it from here. */
4522 /* ------------------------------------------------------------------------ */
4523 u_short
*nat_proto(fin
, nat
, nflags
)
4529 struct icmp6_hdr
*icmp6
;
4535 if (fin
->fin_out
== 0) {
4536 fin
->fin_rev
= (nat
->nat_dir
== NAT_OUTBOUND
);
4538 fin
->fin_rev
= (nat
->nat_dir
== NAT_INBOUND
);
4546 csump
= &tcp
->th_sum
;
4549 * Do a MSS CLAMPING on a SYN packet,
4550 * only deal IPv4 for now.
4552 if ((nat
->nat_mssclamp
!= 0) && (tcp
->th_flags
& TH_SYN
) != 0)
4553 nat_mssclamp(tcp
, nat
->nat_mssclamp
, csump
);
4561 csump
= &udp
->uh_sum
;
4567 if ((nflags
& IPN_ICMPQUERY
) != 0) {
4568 if (icmp
->icmp_cksum
!= 0)
4569 csump
= &icmp
->icmp_cksum
;
4573 case IPPROTO_ICMPV6
:
4574 icmp6
= fin
->fin_dp
;
4576 if ((nflags
& IPN_ICMPQUERY
) != 0) {
4577 if (icmp6
->icmp6_cksum
!= 0)
4578 csump
= &icmp6
->icmp6_cksum
;
4586 /* ------------------------------------------------------------------------ */
4587 /* Function: fr_natunload */
4589 /* Parameters: ifs - ipf stack instance */
4591 /* Free all memory used by NAT structures allocated at runtime. */
4592 /* ------------------------------------------------------------------------ */
4593 void fr_natunload(ifs
)
4596 ipftq_t
*ifq
, *ifqnext
;
4598 (void) nat_clearlist(ifs
);
4599 (void) nat_flushtable(FLUSH_TABLE_ALL
, ifs
);
4602 * Proxy timeout queues are not cleaned here because although they
4603 * exist on the NAT list, appr_unload is called after fr_natunload
4604 * and the proxies actually are responsible for them being created.
4605 * Should the proxy timeouts have their own list? There's no real
4606 * justification as this is the only complication.
4608 for (ifq
= ifs
->ifs_nat_utqe
; ifq
!= NULL
; ifq
= ifqnext
) {
4609 ifqnext
= ifq
->ifq_next
;
4610 if (((ifq
->ifq_flags
& IFQF_PROXY
) == 0) &&
4611 (fr_deletetimeoutqueue(ifq
) == 0))
4612 fr_freetimeoutqueue(ifq
, ifs
);
4615 if (ifs
->ifs_nat_table
[0] != NULL
) {
4616 KFREES(ifs
->ifs_nat_table
[0],
4617 sizeof(nat_t
*) * ifs
->ifs_ipf_nattable_sz
);
4618 ifs
->ifs_nat_table
[0] = NULL
;
4620 if (ifs
->ifs_nat_table
[1] != NULL
) {
4621 KFREES(ifs
->ifs_nat_table
[1],
4622 sizeof(nat_t
*) * ifs
->ifs_ipf_nattable_sz
);
4623 ifs
->ifs_nat_table
[1] = NULL
;
4625 if (ifs
->ifs_nat_rules
!= NULL
) {
4626 KFREES(ifs
->ifs_nat_rules
,
4627 sizeof(ipnat_t
*) * ifs
->ifs_ipf_natrules_sz
);
4628 ifs
->ifs_nat_rules
= NULL
;
4630 if (ifs
->ifs_rdr_rules
!= NULL
) {
4631 KFREES(ifs
->ifs_rdr_rules
,
4632 sizeof(ipnat_t
*) * ifs
->ifs_ipf_rdrrules_sz
);
4633 ifs
->ifs_rdr_rules
= NULL
;
4635 if (ifs
->ifs_maptable
!= NULL
) {
4636 KFREES(ifs
->ifs_maptable
,
4637 sizeof(hostmap_t
*) * ifs
->ifs_ipf_hostmap_sz
);
4638 ifs
->ifs_maptable
= NULL
;
4640 if (ifs
->ifs_nat_stats
.ns_bucketlen
[0] != NULL
) {
4641 KFREES(ifs
->ifs_nat_stats
.ns_bucketlen
[0],
4642 sizeof(u_long
*) * ifs
->ifs_ipf_nattable_sz
);
4643 ifs
->ifs_nat_stats
.ns_bucketlen
[0] = NULL
;
4645 if (ifs
->ifs_nat_stats
.ns_bucketlen
[1] != NULL
) {
4646 KFREES(ifs
->ifs_nat_stats
.ns_bucketlen
[1],
4647 sizeof(u_long
*) * ifs
->ifs_ipf_nattable_sz
);
4648 ifs
->ifs_nat_stats
.ns_bucketlen
[1] = NULL
;
4651 if (ifs
->ifs_fr_nat_maxbucket_reset
== 1)
4652 ifs
->ifs_fr_nat_maxbucket
= 0;
4654 if (ifs
->ifs_fr_nat_init
== 1) {
4655 ifs
->ifs_fr_nat_init
= 0;
4656 fr_sttab_destroy(ifs
->ifs_nat_tqb
);
4658 RW_DESTROY(&ifs
->ifs_ipf_natfrag
);
4659 RW_DESTROY(&ifs
->ifs_ipf_nat
);
4661 MUTEX_DESTROY(&ifs
->ifs_ipf_nat_new
);
4662 MUTEX_DESTROY(&ifs
->ifs_ipf_natio
);
4664 MUTEX_DESTROY(&ifs
->ifs_nat_udptq
.ifq_lock
);
4665 MUTEX_DESTROY(&ifs
->ifs_nat_icmptq
.ifq_lock
);
4666 MUTEX_DESTROY(&ifs
->ifs_nat_iptq
.ifq_lock
);
4671 /* ------------------------------------------------------------------------ */
4672 /* Function: fr_natexpire */
4674 /* Parameters: ifs - ipf stack instance */
4676 /* Check all of the timeout queues for entries at the top which need to be */
4678 /* ------------------------------------------------------------------------ */
4679 void fr_natexpire(ifs
)
4682 ipftq_t
*ifq
, *ifqnext
;
4683 ipftqent_t
*tqe
, *tqn
;
4688 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
4689 for (ifq
= ifs
->ifs_nat_tqb
, i
= 0; ifq
!= NULL
; ifq
= ifq
->ifq_next
) {
4690 for (tqn
= ifq
->ifq_head
; ((tqe
= tqn
) != NULL
); i
++) {
4691 if (tqe
->tqe_die
> ifs
->ifs_fr_ticks
)
4693 tqn
= tqe
->tqe_next
;
4694 (void) nat_delete(tqe
->tqe_parent
, NL_EXPIRE
, ifs
);
4698 for (ifq
= ifs
->ifs_nat_utqe
; ifq
!= NULL
; ifq
= ifqnext
) {
4699 ifqnext
= ifq
->ifq_next
;
4701 for (tqn
= ifq
->ifq_head
; ((tqe
= tqn
) != NULL
); i
++) {
4702 if (tqe
->tqe_die
> ifs
->ifs_fr_ticks
)
4704 tqn
= tqe
->tqe_next
;
4705 (void) nat_delete(tqe
->tqe_parent
, NL_EXPIRE
, ifs
);
4709 for (ifq
= ifs
->ifs_nat_utqe
; ifq
!= NULL
; ifq
= ifqnext
) {
4710 ifqnext
= ifq
->ifq_next
;
4712 if (((ifq
->ifq_flags
& IFQF_DELETE
) != 0) &&
4713 (ifq
->ifq_ref
== 0)) {
4714 fr_freetimeoutqueue(ifq
, ifs
);
4718 if (ifs
->ifs_nat_doflush
!= 0) {
4719 (void) nat_flushtable(FLUSH_TABLE_EXTRA
, ifs
);
4720 ifs
->ifs_nat_doflush
= 0;
4723 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4728 /* ------------------------------------------------------------------------ */
4729 /* Function: fr_nataddrsync */
4731 /* Parameters: ifp(I) - pointer to network interface */
4732 /* addr(I) - pointer to new network address */
4734 /* Walk through all of the currently active NAT sessions, looking for those */
4735 /* which need to have their translated address updated (where the interface */
4736 /* matches the one passed in) and change it, recalculating the checksum sum */
4737 /* difference too. */
4738 /* ------------------------------------------------------------------------ */
4739 void fr_nataddrsync(v
, ifp
, addr
, ifs
)
4745 u_32_t sum1
, sum2
, sumd
;
4750 if (ifs
->ifs_fr_running
<= 0)
4754 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
4756 if (ifs
->ifs_fr_running
<= 0) {
4757 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4762 * Change IP addresses for NAT sessions for any protocol except TCP
4763 * since it will break the TCP connection anyway. The only rules
4764 * which will get changed are those which are "map ... -> 0/32",
4765 * where the rule specifies the address is taken from the interface.
4767 for (nat
= ifs
->ifs_nat_instances
; nat
; nat
= nat
->nat_next
) {
4769 if (((ifp
!= NULL
) && ifp
!= (nat
->nat_ifps
[0])) ||
4770 ((nat
->nat_flags
& IPN_TCP
) != 0))
4772 if ((np
= nat
->nat_ptr
) == NULL
)
4774 if (v
== 4 && np
->in_v
== 4) {
4775 if (np
->in_nip
|| np
->in_outmsk
!= 0xffffffff)
4778 * Change the map-to address to be the same as
4781 sum1
= nat
->nat_outip
.s_addr
;
4782 nat
->nat_outip
= *(struct in_addr
*)addr
;
4783 sum2
= nat
->nat_outip
.s_addr
;
4784 } else if (v
== 6 && np
->in_v
== 6) {
4785 if (!IP6_ISZERO(&np
->in_next6
.in6
) ||
4786 !IP6_ISONES(&np
->in_out
[1].in6
))
4789 * Change the map-to address to be the same as
4792 nat
->nat_outip6
.in6
= *(struct in6_addr
*)addr
;
4796 } else if (((ifp
== NULL
) || (ifp
== nat
->nat_ifps
[0])) &&
4797 !(nat
->nat_flags
& IPN_TCP
) && (np
= nat
->nat_ptr
)) {
4798 if (np
->in_v
== 4 && (v
== 4 || v
== 0)) {
4800 if (np
->in_outmsk
!= 0xffffffff || np
->in_nip
)
4803 * Change the map-to address to be the same as
4806 sum1
= nat
->nat_outip
.s_addr
;
4807 if (fr_ifpaddr(4, FRI_NORMAL
, nat
->nat_ifps
[0],
4808 &in
, NULL
, ifs
) != -1)
4809 nat
->nat_outip
= in
;
4810 sum2
= nat
->nat_outip
.s_addr
;
4811 } else if (np
->in_v
== 6 && (v
== 6 || v
== 0)) {
4812 struct in6_addr in6
;
4813 if (!IP6_ISZERO(&np
->in_next6
.in6
) ||
4814 !IP6_ISONES(&np
->in_out
[1].in6
))
4817 * Change the map-to address to be the same as
4820 if (fr_ifpaddr(6, FRI_NORMAL
, nat
->nat_ifps
[0],
4821 (void *)&in6
, NULL
, ifs
) != -1)
4822 nat
->nat_outip6
.in6
= in6
;
4832 * Readjust the checksum adjustment to take into
4833 * account the new IP#.
4835 CALC_SUMD(sum1
, sum2
, sumd
);
4836 /* XXX - dont change for TCP when solaris does
4837 * hardware checksumming.
4839 sumd
+= nat
->nat_sumd
[0];
4840 nat
->nat_sumd
[0] = (sumd
& 0xffff) + (sumd
>> 16);
4841 nat
->nat_sumd
[1] = nat
->nat_sumd
[0];
4844 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4849 /* ------------------------------------------------------------------------ */
4850 /* Function: fr_natifpsync */
4852 /* Parameters: action(I) - how we are syncing */
4853 /* ifp(I) - pointer to network interface */
4854 /* name(I) - name of interface to sync to */
4856 /* This function is used to resync the mapping of interface names and their */
4857 /* respective 'pointers'. For "action == IPFSYNC_RESYNC", resync all */
4858 /* interfaces by doing a new lookup of name to 'pointer'. For "action == */
4859 /* IPFSYNC_NEWIFP", treat ifp as the new pointer value associated with */
4860 /* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which */
4861 /* there is no longer any interface associated with it. */
4862 /* ------------------------------------------------------------------------ */
4863 void fr_natifpsync(action
, v
, ifp
, name
, ifs
)
4869 #if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
4876 if (ifs
->ifs_fr_running
<= 0)
4880 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
4882 if (ifs
->ifs_fr_running
<= 0) {
4883 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4889 case IPFSYNC_RESYNC
:
4890 for (nat
= ifs
->ifs_nat_instances
; nat
; nat
= nat
->nat_next
) {
4891 nv
= (v
== 0) ? nat
->nat_v
: v
;
4892 if (nat
->nat_v
!= nv
)
4894 if ((ifp
== nat
->nat_ifps
[0]) ||
4895 (nat
->nat_ifps
[0] == (void *)-1)) {
4897 fr_resolvenic(nat
->nat_ifnames
[0], nv
, ifs
);
4900 if ((ifp
== nat
->nat_ifps
[1]) ||
4901 (nat
->nat_ifps
[1] == (void *)-1)) {
4903 fr_resolvenic(nat
->nat_ifnames
[1], nv
, ifs
);
4907 for (n
= ifs
->ifs_nat_list
; (n
!= NULL
); n
= n
->in_next
) {
4908 nv
= (v
== 0) ? (int)n
->in_v
: v
;
4909 if ((int)n
->in_v
!= nv
)
4911 if (n
->in_ifps
[0] == ifp
||
4912 n
->in_ifps
[0] == (void *)-1) {
4914 fr_resolvenic(n
->in_ifnames
[0], nv
, ifs
);
4916 if (n
->in_ifps
[1] == ifp
||
4917 n
->in_ifps
[1] == (void *)-1) {
4919 fr_resolvenic(n
->in_ifnames
[1], nv
, ifs
);
4923 case IPFSYNC_NEWIFP
:
4924 for (nat
= ifs
->ifs_nat_instances
; nat
; nat
= nat
->nat_next
) {
4925 if (nat
->nat_v
!= v
)
4927 if (!strncmp(name
, nat
->nat_ifnames
[0],
4928 sizeof(nat
->nat_ifnames
[0])))
4929 nat
->nat_ifps
[0] = ifp
;
4930 if (!strncmp(name
, nat
->nat_ifnames
[1],
4931 sizeof(nat
->nat_ifnames
[1])))
4932 nat
->nat_ifps
[1] = ifp
;
4934 for (n
= ifs
->ifs_nat_list
; (n
!= NULL
); n
= n
->in_next
) {
4935 if ((int)n
->in_v
!= v
)
4937 if (!strncmp(name
, n
->in_ifnames
[0],
4938 sizeof(n
->in_ifnames
[0])))
4939 n
->in_ifps
[0] = ifp
;
4940 if (!strncmp(name
, n
->in_ifnames
[1],
4941 sizeof(n
->in_ifnames
[1])))
4942 n
->in_ifps
[1] = ifp
;
4945 case IPFSYNC_OLDIFP
:
4946 for (nat
= ifs
->ifs_nat_instances
; nat
; nat
= nat
->nat_next
) {
4947 if (nat
->nat_v
!= v
)
4949 if (ifp
== nat
->nat_ifps
[0])
4950 nat
->nat_ifps
[0] = (void *)-1;
4951 if (ifp
== nat
->nat_ifps
[1])
4952 nat
->nat_ifps
[1] = (void *)-1;
4954 for (n
= ifs
->ifs_nat_list
; (n
!= NULL
); n
= n
->in_next
) {
4955 if ((int)n
->in_v
!= v
)
4957 if (n
->in_ifps
[0] == ifp
)
4958 n
->in_ifps
[0] = (void *)-1;
4959 if (n
->in_ifps
[1] == ifp
)
4960 n
->in_ifps
[1] = (void *)-1;
4964 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
4969 /* ------------------------------------------------------------------------ */
4970 /* Function: fr_natifindexsync */
4972 /* Parameters: ifp - interface, which is being sync'd */
4973 /* newifp - new ifindex value for interface */
4974 /* ifs - IPF's stack */
4976 /* Write Locks: assumes ipf_mutex is locked */
4978 /* Updates all interface index references in NAT rules and NAT entries. */
4979 /* the index, which is about to be updated must match ifp value. */
4980 /* ------------------------------------------------------------------------ */
4981 void fr_natifindexsync(ifp
, newifp
, ifs
)
4989 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
4991 for (nat
= ifs
->ifs_nat_instances
; nat
!= NULL
; nat
= nat
->nat_next
) {
4992 if (ifp
== nat
->nat_ifps
[0])
4993 nat
->nat_ifps
[0] = newifp
;
4995 if (ifp
== nat
->nat_ifps
[1])
4996 nat
->nat_ifps
[1] = newifp
;
4999 for (n
= ifs
->ifs_nat_list
; n
!= NULL
; n
= n
->in_next
) {
5000 if (ifp
== n
->in_ifps
[0])
5001 n
->in_ifps
[0] = newifp
;
5003 if (ifp
== n
->in_ifps
[1])
5004 n
->in_ifps
[1] = newifp
;
5007 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
5011 /* ------------------------------------------------------------------------ */
5012 /* Function: nat_icmpquerytype4 */
5013 /* Returns: int - 1 == success, 0 == failure */
5014 /* Parameters: icmptype(I) - ICMP type number */
5016 /* Tests to see if the ICMP type number passed is a query/response type or */
5018 /* ------------------------------------------------------------------------ */
5019 static INLINE
int nat_icmpquerytype4(icmptype
)
5024 * For the ICMP query NAT code, it is essential that both the query
5025 * and the reply match on the NAT rule. Because the NAT structure
5026 * does not keep track of the icmptype, and a single NAT structure
5027 * is used for all icmp types with the same src, dest and id, we
5028 * simply define the replies as queries as well. The funny thing is,
5029 * altough it seems silly to call a reply a query, this is exactly
5030 * as it is defined in the IPv4 specification
5036 case ICMP_ECHOREPLY
:
5038 /* route aedvertisement/solliciation is currently unsupported: */
5039 /* it would require rewriting the ICMP data section */
5041 case ICMP_TSTAMPREPLY
:
5043 case ICMP_IREQREPLY
:
5045 case ICMP_MASKREPLY
:
5053 /* ------------------------------------------------------------------------ */
5054 /* Function: nat_log */
5056 /* Parameters: nat(I) - pointer to NAT structure */
5057 /* type(I) - type of log entry to create */
5059 /* Creates a NAT log entry. */
5060 /* ------------------------------------------------------------------------ */
5061 void nat_log(nat
, type
, ifs
)
5076 natl
.nlg_inip
= nat
->nat_inip6
;
5077 natl
.nlg_outip
= nat
->nat_outip6
;
5078 natl
.nlg_origip
= nat
->nat_oip6
;
5079 natl
.nlg_bytes
[0] = nat
->nat_bytes
[0];
5080 natl
.nlg_bytes
[1] = nat
->nat_bytes
[1];
5081 natl
.nlg_pkts
[0] = nat
->nat_pkts
[0];
5082 natl
.nlg_pkts
[1] = nat
->nat_pkts
[1];
5083 natl
.nlg_origport
= nat
->nat_oport
;
5084 natl
.nlg_inport
= nat
->nat_inport
;
5085 natl
.nlg_outport
= nat
->nat_outport
;
5086 natl
.nlg_p
= nat
->nat_p
;
5087 natl
.nlg_type
= type
;
5089 natl
.nlg_v
= nat
->nat_v
;
5091 if (nat
->nat_ptr
!= NULL
) {
5092 for (rulen
= 0, np
= ifs
->ifs_nat_list
; np
;
5093 np
= np
->in_next
, rulen
++)
5094 if (np
== nat
->nat_ptr
) {
5095 natl
.nlg_rule
= rulen
;
5101 sizes
[0] = sizeof(natl
);
5104 (void) ipllog(IPL_LOGNAT
, NULL
, items
, sizes
, types
, 1, ifs
);
5109 #if defined(__OpenBSD__)
5110 /* ------------------------------------------------------------------------ */
5111 /* Function: nat_ifdetach */
5113 /* Parameters: ifp(I) - pointer to network interface */
5115 /* Compatibility interface for OpenBSD to trigger the correct updating of */
5116 /* interface references within IPFilter. */
5117 /* ------------------------------------------------------------------------ */
5118 void nat_ifdetach(ifp
, ifs
)
5128 /* ------------------------------------------------------------------------ */
5129 /* Function: fr_ipnatderef */
5131 /* Parameters: inp(I) - pointer to pointer to NAT rule */
5132 /* Write Locks: ipf_nat */
5134 /* ------------------------------------------------------------------------ */
5135 void fr_ipnatderef(inp
, ifs
)
5144 if (in
->in_use
== 0 && (in
->in_flags
& IPN_DELETE
)) {
5146 appr_free(in
->in_apr
);
5148 ifs
->ifs_nat_stats
.ns_rules
--;
5151 if (ifs
->ifs_nat_stats
.ns_rules
== 0)
5152 ifs
->ifs_pfil_delayed_copy
= 1;
5159 /* ------------------------------------------------------------------------ */
5160 /* Function: fr_natderef */
5162 /* Parameters: natp - pointer to pointer to NAT table entry */
5163 /* ifs - ipf stack instance */
5165 /* Decrement the reference counter for this NAT table entry and free it if */
5166 /* there are no more things using it. */
5168 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */
5169 /* structure *because* it only gets called on paths _after_ nat_ref has been*/
5170 /* incremented. If nat_ref == 1 then we shouldn't decrement it here */
5171 /* because nat_delete() will do that and send nat_ref to -1. */
5173 /* Holding the lock on nat_lock is required to serialise nat_delete() being */
5174 /* called from a NAT flush ioctl with a deref happening because of a packet.*/
5175 /* ------------------------------------------------------------------------ */
5176 void fr_natderef(natp
, ifs
)
5185 MUTEX_ENTER(&nat
->nat_lock
);
5186 if (nat
->nat_ref
> 1) {
5188 MUTEX_EXIT(&nat
->nat_lock
);
5191 MUTEX_EXIT(&nat
->nat_lock
);
5193 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
5194 (void) nat_delete(nat
, NL_EXPIRE
, ifs
);
5195 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
5199 /* ------------------------------------------------------------------------ */
5200 /* Function: fr_natclone */
5201 /* Returns: ipstate_t* - NULL == cloning failed, */
5202 /* else pointer to new NAT structure */
5203 /* Parameters: fin(I) - pointer to packet information */
5204 /* nat(I) - pointer to master NAT structure */
5205 /* Write Lock: ipf_nat */
5207 /* Create a "duplicate" NAT table entry from the master. */
5208 /* ------------------------------------------------------------------------ */
5209 nat_t
*fr_natclone(fin
, nat
)
5216 ipf_stack_t
*ifs
= fin
->fin_ifs
;
5219 * Trigger automatic call to nat_flushtable() if the
5220 * table has reached capcity specified by hi watermark.
5222 if (NAT_TAB_WATER_LEVEL(ifs
) > ifs
->ifs_nat_flush_level_hi
)
5223 ifs
->ifs_nat_doflush
= 1;
5226 * If automatic flushing did not do its job, and the table
5227 * has filled up, don't try to create a new entry.
5229 if (ifs
->ifs_nat_stats
.ns_inuse
>= ifs
->ifs_ipf_nattable_max
) {
5230 ifs
->ifs_nat_stats
.ns_memfail
++;
5234 KMALLOC(clone
, nat_t
*);
5237 bcopy((char *)nat
, (char *)clone
, sizeof(*clone
));
5239 MUTEX_NUKE(&clone
->nat_lock
);
5241 clone
->nat_aps
= NULL
;
5243 * Initialize all these so that nat_delete() doesn't cause a crash.
5245 clone
->nat_tqe
.tqe_pnext
= NULL
;
5246 clone
->nat_tqe
.tqe_next
= NULL
;
5247 clone
->nat_tqe
.tqe_ifq
= NULL
;
5248 clone
->nat_tqe
.tqe_parent
= clone
;
5250 clone
->nat_flags
&= ~SI_CLONE
;
5251 clone
->nat_flags
|= SI_CLONED
;
5254 clone
->nat_hm
->hm_ref
++;
5256 if (nat_insert(clone
, fin
->fin_rev
, ifs
) == -1) {
5260 np
= clone
->nat_ptr
;
5262 if (ifs
->ifs_nat_logging
)
5263 nat_log(clone
, (u_int
)np
->in_redir
, ifs
);
5268 MUTEX_ENTER(&fr
->fr_lock
);
5270 MUTEX_EXIT(&fr
->fr_lock
);
5274 * Because the clone is created outside the normal loop of things and
5275 * TCP has special needs in terms of state, initialise the timeout
5276 * state of the new NAT from here.
5278 if (clone
->nat_p
== IPPROTO_TCP
) {
5279 (void) fr_tcp_age(&clone
->nat_tqe
, fin
, ifs
->ifs_nat_tqb
,
5282 #ifdef IPFILTER_SYNC
5283 clone
->nat_sync
= ipfsync_new(SMC_NAT
, fin
, clone
);
5285 if (ifs
->ifs_nat_logging
)
5286 nat_log(clone
, NL_CLONE
, ifs
);
5291 /* ------------------------------------------------------------------------ */
5292 /* Function: nat_wildok */
5293 /* Returns: int - 1 == packet's ports match wildcards */
5294 /* 0 == packet's ports don't match wildcards */
5295 /* Parameters: nat(I) - NAT entry */
5296 /* sport(I) - source port */
5297 /* dport(I) - destination port */
5298 /* flags(I) - wildcard flags */
5299 /* dir(I) - packet direction */
5301 /* Use NAT entry and packet direction to determine which combination of */
5302 /* wildcard flags should be used. */
5303 /* ------------------------------------------------------------------------ */
5304 int nat_wildok(nat
, sport
, dport
, flags
, dir
)
5312 * When called by dir is set to
5313 * nat_inlookup NAT_INBOUND (0)
5314 * nat_outlookup NAT_OUTBOUND (1)
5316 * We simply combine the packet's direction in dir with the original
5317 * "intended" direction of that NAT entry in nat->nat_dir to decide
5318 * which combination of wildcard flags to allow.
5321 switch ((dir
<< 1) | nat
->nat_dir
)
5323 case 3: /* outbound packet / outbound entry */
5324 if (((nat
->nat_inport
== sport
) ||
5325 (flags
& SI_W_SPORT
)) &&
5326 ((nat
->nat_oport
== dport
) ||
5327 (flags
& SI_W_DPORT
)))
5330 case 2: /* outbound packet / inbound entry */
5331 if (((nat
->nat_outport
== sport
) ||
5332 (flags
& SI_W_DPORT
)) &&
5333 ((nat
->nat_oport
== dport
) ||
5334 (flags
& SI_W_SPORT
)))
5337 case 1: /* inbound packet / outbound entry */
5338 if (((nat
->nat_oport
== sport
) ||
5339 (flags
& SI_W_DPORT
)) &&
5340 ((nat
->nat_outport
== dport
) ||
5341 (flags
& SI_W_SPORT
)))
5344 case 0: /* inbound packet / inbound entry */
5345 if (((nat
->nat_oport
== sport
) ||
5346 (flags
& SI_W_SPORT
)) &&
5347 ((nat
->nat_outport
== dport
) ||
5348 (flags
& SI_W_DPORT
)))
5359 /* ------------------------------------------------------------------------ */
5360 /* Function: nat_mssclamp */
5362 /* Parameters: tcp(I) - pointer to TCP header */
5363 /* maxmss(I) - value to clamp the TCP MSS to */
5364 /* csump(I) - pointer to TCP checksum */
5366 /* Check for MSS option and clamp it if necessary. If found and changed, */
5367 /* then the TCP header checksum will be updated to reflect the change in */
5369 /* ------------------------------------------------------------------------ */
5370 static void nat_mssclamp(tcp
, maxmss
, csump
)
5375 u_char
*cp
, *ep
, opt
;
5379 hlen
= TCP_OFF(tcp
) << 2;
5380 if (hlen
> sizeof(*tcp
)) {
5381 cp
= (u_char
*)tcp
+ sizeof(*tcp
);
5382 ep
= (u_char
*)tcp
+ hlen
;
5386 if (opt
== TCPOPT_EOL
)
5388 else if (opt
== TCPOPT_NOP
) {
5396 if ((cp
+ advance
> ep
) || (advance
<= 0))
5403 mss
= cp
[2] * 256 + cp
[3];
5405 cp
[2] = maxmss
/ 256;
5406 cp
[3] = maxmss
& 0xff;
5407 CALC_SUMD(mss
, maxmss
, sumd
);
5408 fix_outcksum(csump
, sumd
);
5412 /* ignore unknown options */
5422 /* ------------------------------------------------------------------------ */
5423 /* Function: fr_setnatqueue */
5425 /* Parameters: nat(I)- pointer to NAT structure */
5426 /* rev(I) - forward(0) or reverse(1) direction */
5427 /* Locks: ipf_nat (read or write) */
5429 /* Put the NAT entry on its default queue entry, using rev as a helped in */
5430 /* determining which queue it should be placed on. */
5431 /* ------------------------------------------------------------------------ */
5432 void fr_setnatqueue(nat
, rev
, ifs
)
5437 ipftq_t
*oifq
, *nifq
;
5439 if (nat
->nat_ptr
!= NULL
)
5440 nifq
= nat
->nat_ptr
->in_tqehead
[rev
];
5448 nifq
= &ifs
->ifs_nat_udptq
;
5451 nifq
= &ifs
->ifs_nat_icmptq
;
5454 nifq
= ifs
->ifs_nat_tqb
+ nat
->nat_tqe
.tqe_state
[rev
];
5457 nifq
= &ifs
->ifs_nat_iptq
;
5462 oifq
= nat
->nat_tqe
.tqe_ifq
;
5464 * If it's currently on a timeout queue, move it from one queue to
5465 * another, else put it on the end of the newly determined queue.
5468 fr_movequeue(&nat
->nat_tqe
, oifq
, nifq
, ifs
);
5470 fr_queueappend(&nat
->nat_tqe
, nifq
, nat
, ifs
);
5474 /* ------------------------------------------------------------------------ */
5475 /* Function: nat_getnext */
5476 /* Returns: int - 0 == ok, else error */
5477 /* Parameters: t(I) - pointer to ipftoken structure */
5478 /* itp(I) - pointer to ipfgeniter_t structure */
5479 /* ifs - ipf stack instance */
5481 /* Fetch the next nat/ipnat/hostmap structure pointer from the linked list */
5482 /* and copy it out to the storage space pointed to by itp. The next item */
5483 /* in the list to look at is put back in the ipftoken struture. */
5484 /* ------------------------------------------------------------------------ */
5485 static int nat_getnext(t
, itp
, ifs
)
5490 hostmap_t
*hm
, *nexthm
= NULL
, zerohm
;
5491 ipnat_t
*ipn
, *nextipnat
= NULL
, zeroipn
;
5492 nat_t
*nat
, *nextnat
= NULL
, zeronat
;
5493 int error
= 0, count
;
5496 if (itp
->igi_nitems
== 0)
5499 READ_ENTER(&ifs
->ifs_ipf_nat
);
5502 * Get "previous" entry from the token and find the next entry.
5504 switch (itp
->igi_type
)
5506 case IPFGENITER_HOSTMAP
:
5509 nexthm
= ifs
->ifs_ipf_hm_maplist
;
5511 nexthm
= hm
->hm_next
;
5515 case IPFGENITER_IPNAT
:
5518 nextipnat
= ifs
->ifs_nat_list
;
5520 nextipnat
= ipn
->in_next
;
5524 case IPFGENITER_NAT
:
5527 nextnat
= ifs
->ifs_nat_instances
;
5529 nextnat
= nat
->nat_next
;
5533 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
5538 * Note, this loop is based on the number of items that a user
5539 * requested. The user can request any number, potentially far more than
5540 * the number of items that actually exist. If a user does that, we'll
5541 * break out of this by setting the value of count to 1 which terminates
5542 * the loop. This should be fine from an ioctl perspective, because the
5543 * last entry that we insert will be the zero entry which terminates the
5546 dst
= itp
->igi_data
;
5547 for (count
= itp
->igi_nitems
; count
> 0; count
--) {
5549 * If we found an entry, add a reference to it and update the token.
5550 * Otherwise, zero out data to be returned and NULL out token.
5552 switch (itp
->igi_type
)
5554 case IPFGENITER_HOSTMAP
:
5555 if (nexthm
!= NULL
) {
5556 ATOMIC_INC32(nexthm
->hm_ref
);
5557 t
->ipt_data
= nexthm
;
5559 bzero(&zerohm
, sizeof(zerohm
));
5564 case IPFGENITER_IPNAT
:
5565 if (nextipnat
!= NULL
) {
5566 ATOMIC_INC32(nextipnat
->in_use
);
5567 t
->ipt_data
= nextipnat
;
5569 bzero(&zeroipn
, sizeof(zeroipn
));
5570 nextipnat
= &zeroipn
;
5574 case IPFGENITER_NAT
:
5575 if (nextnat
!= NULL
) {
5576 MUTEX_ENTER(&nextnat
->nat_lock
);
5578 MUTEX_EXIT(&nextnat
->nat_lock
);
5579 t
->ipt_data
= nextnat
;
5581 bzero(&zeronat
, sizeof(zeronat
));
5591 * Now that we have ref, it's save to give up lock.
5593 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
5596 * Copy out data and clean up references and token as needed.
5598 switch (itp
->igi_type
)
5600 case IPFGENITER_HOSTMAP
:
5601 error
= COPYOUT(nexthm
, dst
, sizeof(*nexthm
));
5604 if (t
->ipt_data
== NULL
) {
5605 ipf_freetoken(t
, ifs
);
5610 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
5612 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
5614 if (nexthm
->hm_next
== NULL
) {
5615 ipf_freetoken(t
, ifs
);
5619 dst
+= sizeof(*nexthm
);
5621 nexthm
= nexthm
->hm_next
;
5625 case IPFGENITER_IPNAT
:
5626 error
= COPYOUT(nextipnat
, dst
, sizeof(*nextipnat
));
5629 if (t
->ipt_data
== NULL
) {
5630 ipf_freetoken(t
, ifs
);
5635 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
5636 fr_ipnatderef(&ipn
, ifs
);
5637 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);
5639 if (nextipnat
->in_next
== NULL
) {
5640 ipf_freetoken(t
, ifs
);
5644 dst
+= sizeof(*nextipnat
);
5646 nextipnat
= nextipnat
->in_next
;
5650 case IPFGENITER_NAT
:
5651 error
= COPYOUT(nextnat
, dst
, sizeof(*nextnat
));
5654 if (t
->ipt_data
== NULL
) {
5655 ipf_freetoken(t
, ifs
);
5660 fr_natderef(&nat
, ifs
);
5661 if (nextnat
->nat_next
== NULL
) {
5662 ipf_freetoken(t
, ifs
);
5666 dst
+= sizeof(*nextnat
);
5668 nextnat
= nextnat
->nat_next
;
5675 if ((count
== 1) || (error
!= 0))
5678 READ_ENTER(&ifs
->ifs_ipf_nat
);
5685 /* ------------------------------------------------------------------------ */
5686 /* Function: nat_iterator */
5687 /* Returns: int - 0 == ok, else error */
5688 /* Parameters: token(I) - pointer to ipftoken structure */
5689 /* itp(I) - pointer to ipfgeniter_t structure */
5691 /* This function acts as a handler for the SIOCGENITER ioctls that use a */
5692 /* generic structure to iterate through a list. There are three different */
5693 /* linked lists of NAT related information to go through: NAT rules, active */
5694 /* NAT mappings and the NAT fragment cache. */
5695 /* ------------------------------------------------------------------------ */
5696 static int nat_iterator(token
, itp
, ifs
)
5703 if (itp
->igi_data
== NULL
)
5706 token
->ipt_subtype
= itp
->igi_type
;
5708 switch (itp
->igi_type
)
5710 case IPFGENITER_HOSTMAP
:
5711 case IPFGENITER_IPNAT
:
5712 case IPFGENITER_NAT
:
5713 error
= nat_getnext(token
, itp
, ifs
);
5715 case IPFGENITER_NATFRAG
:
5716 error
= fr_nextfrag(token
, itp
, &ifs
->ifs_ipfr_natlist
,
5717 &ifs
->ifs_ipfr_nattail
,
5718 &ifs
->ifs_ipf_natfrag
, ifs
);
5729 /* ---------------------------------------------------------------------- */
5730 /* Function: nat_flushtable */
5731 /* Returns: int - 0 == success, -1 == failure */
5732 /* Parameters: flush_option - how to flush the active NAT table */
5733 /* ifs - ipf stack instance */
5734 /* Write Locks: ipf_nat */
5736 /* Flush NAT tables. Three actions currently defined: */
5738 /* FLUSH_TABLE_ALL : Flush all NAT table entries */
5740 /* FLUSH_TABLE_CLOSING : Flush entries with TCP connections which */
5741 /* have started to close on both ends using */
5742 /* ipf_flushclosing(). */
5744 /* FLUSH_TABLE_EXTRA : First, flush entries which are "almost" closed. */
5745 /* Then, if needed, flush entries with TCP */
5746 /* connections which have been idle for a long */
5747 /* time with ipf_extraflush(). */
5748 /* ---------------------------------------------------------------------- */
5749 static int nat_flushtable(flush_option
, ifs
)
5760 switch (flush_option
)
5762 case FLUSH_TABLE_ALL
:
5763 natn
= ifs
->ifs_nat_instances
;
5764 while ((nat
= natn
) != NULL
) {
5765 natn
= nat
->nat_next
;
5766 if (nat_delete(nat
, NL_FLUSH
, ifs
) == 0)
5771 case FLUSH_TABLE_CLOSING
:
5772 removed
= ipf_flushclosing(NAT_FLUSH
,
5773 IPF_TCPS_CLOSE_WAIT
,
5779 case FLUSH_TABLE_EXTRA
:
5780 removed
= ipf_flushclosing(NAT_FLUSH
,
5781 IPF_TCPS_FIN_WAIT_2
,
5787 * Be sure we haven't done this in the last 10 seconds.
5789 if (ifs
->ifs_fr_ticks
- ifs
->ifs_nat_last_force_flush
<
5792 ifs
->ifs_nat_last_force_flush
= ifs
->ifs_fr_ticks
;
5793 removed
+= ipf_extraflush(NAT_FLUSH
,
5794 &ifs
->ifs_nat_tqb
[IPF_TCPS_ESTABLISHED
],
5799 default: /* Flush Nothing */
5808 /* ------------------------------------------------------------------------ */
5809 /* Function: nat_uncreate */
5811 /* Parameters: fin(I) - pointer to packet information */
5813 /* This function is used to remove a NAT entry from the NAT table when we */
5814 /* decide that the create was actually in error. It is thus assumed that */
5815 /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
5816 /* with the translated packet (not the original), we have to reverse the */
5817 /* lookup. Although doing the lookup is expensive (relatively speaking), it */
5818 /* is not anticipated that this will be a frequent occurance for normal */
5819 /* traffic patterns. */
5820 /* ------------------------------------------------------------------------ */
5821 void nat_uncreate(fin
)
5824 ipf_stack_t
*ifs
= fin
->fin_ifs
;
5841 WRITE_ENTER(&ifs
->ifs_ipf_nat
);
5843 if (fin
->fin_out
== 0) {
5844 nat
= nat_outlookup(fin
, nflags
, (u_int
)fin
->fin_p
,
5845 fin
->fin_dst
, fin
->fin_src
);
5847 nat
= nat_inlookup(fin
, nflags
, (u_int
)fin
->fin_p
,
5848 fin
->fin_src
, fin
->fin_dst
);
5852 ifs
->ifs_nat_stats
.ns_uncreate
[fin
->fin_out
][0]++;
5853 (void) nat_delete(nat
, NL_DESTROY
, ifs
);
5855 ifs
->ifs_nat_stats
.ns_uncreate
[fin
->fin_out
][1]++;
5858 RWLOCK_EXIT(&ifs
->ifs_ipf_nat
);