]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ipfilter/netinet/ip_nat.c
This commit was generated by cvs2svn to compensate for changes in r79998,
[FreeBSD/FreeBSD.git] / sys / contrib / ipfilter / netinet / ip_nat.c
1 /*
2  * Copyright (C) 1995-2000 by Darren Reed.
3  *
4  * Redistribution and use in source and binary forms are permitted
5  * provided that this notice is preserved and due credit is given
6  * to the original author and the contributors.
7  *
8  * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
9  */
10 #if !defined(lint)
11 /*static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.16 2000/07/18 13:57:40 darrenr Exp $";*/
12 static const char rcsid[] = "@(#)$FreeBSD$";
13 #endif
14
15 #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
16 #define _KERNEL
17 #endif
18
19 #include <sys/errno.h>
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/time.h>
23 #include <sys/file.h>
24 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
25     defined(_KERNEL)
26 # include "opt_ipfilter_log.h"
27 #endif
28 #if !defined(_KERNEL) && !defined(KERNEL)
29 # include <stdio.h>
30 # include <string.h>
31 # include <stdlib.h>
32 #endif
33 #if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000)
34 # include <sys/filio.h>
35 # include <sys/fcntl.h>
36 #else
37 # include <sys/ioctl.h>
38 #endif
39 #include <sys/fcntl.h>
40 #include <sys/uio.h>
41 #ifndef linux
42 # include <sys/protosw.h>
43 #endif
44 #include <sys/socket.h>
45 #if defined(_KERNEL) && !defined(linux)
46 # include <sys/systm.h>
47 #endif
48 #if !defined(__SVR4) && !defined(__svr4__)
49 # ifndef linux
50 #  include <sys/mbuf.h>
51 # endif
52 #else
53 # include <sys/filio.h>
54 # include <sys/byteorder.h>
55 # ifdef _KERNEL
56 #  include <sys/dditypes.h>
57 # endif
58 # include <sys/stream.h>
59 # include <sys/kmem.h>
60 #endif
61 #if __FreeBSD_version >= 300000
62 # include <sys/queue.h>
63 #endif
64 #include <net/if.h>
65 #if __FreeBSD_version >= 300000
66 # include <net/if_var.h>
67 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
68 #  include "opt_ipfilter.h"
69 # endif
70 #endif
71 #ifdef sun
72 # include <net/af.h>
73 #endif
74 #include <net/route.h>
75 #include <netinet/in.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78
79 #ifdef __sgi
80 # ifdef IFF_DRVRLOCK /* IRIX6 */
81 #include <sys/hashing.h>
82 #include <netinet/in_var.h>
83 # endif
84 #endif
85
86 #ifdef RFC1825
87 # include <vpn/md5.h>
88 # include <vpn/ipsec.h>
89 extern struct ifnet vpnif;
90 #endif
91
92 #ifndef linux
93 # include <netinet/ip_var.h>
94 #endif
95 #include <netinet/tcp.h>
96 #include <netinet/udp.h>
97 #include <netinet/ip_icmp.h>
98 #include "netinet/ip_compat.h"
99 #include <netinet/tcpip.h>
100 #include "netinet/ip_fil.h"
101 #include "netinet/ip_proxy.h"
102 #include "netinet/ip_nat.h"
103 #include "netinet/ip_frag.h"
104 #include "netinet/ip_state.h"
105 #if (__FreeBSD_version >= 300000)
106 # include <sys/malloc.h>
107 #endif
108 #ifndef MIN
109 # define        MIN(a,b)        (((a)<(b))?(a):(b))
110 #endif
111 #undef  SOCKADDR_IN
112 #define SOCKADDR_IN     struct sockaddr_in
113
114 nat_t   **nat_table[2] = { NULL, NULL },
115         *nat_instances = NULL;
116 ipnat_t *nat_list = NULL;
117 u_int   ipf_nattable_sz = NAT_TABLE_SZ;
118 u_int   ipf_natrules_sz = NAT_SIZE;
119 u_int   ipf_rdrrules_sz = RDR_SIZE;
120 u_int   ipf_hostmap_sz = HOSTMAP_SIZE;
121 u_32_t  nat_masks = 0;
122 u_32_t  rdr_masks = 0;
123 ipnat_t **nat_rules = NULL;
124 ipnat_t **rdr_rules = NULL;
125 hostmap_t       **maptable  = NULL;
126
127 u_long  fr_defnatage = DEF_NAT_AGE,
128         fr_defnaticmpage = 6;           /* 3 seconds */
129 natstat_t nat_stats;
130 int     fr_nat_lock = 0;
131 #if     (SOLARIS || defined(__sgi)) && defined(_KERNEL)
132 extern  kmutex_t        ipf_rw;
133 extern  KRWLOCK_T       ipf_nat;
134 #endif
135
136 static  int     nat_flushtable __P((void));
137 static  int     nat_clearlist __P((void));
138 static  void    nat_addnat __P((struct ipnat *));
139 static  void    nat_addrdr __P((struct ipnat *));
140 static  void    nat_delete __P((struct nat *));
141 static  void    nat_delrdr __P((struct ipnat *));
142 static  void    nat_delnat __P((struct ipnat *));
143 static  int     fr_natgetent __P((caddr_t));
144 static  int     fr_natgetsz __P((caddr_t));
145 static  int     fr_natputent __P((caddr_t));
146 static  void    nat_tabmove __P((nat_t *, u_32_t));
147 static  int     nat_match __P((fr_info_t *, ipnat_t *, ip_t *));
148 static  hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
149                                     struct in_addr));
150 static  void    nat_hostmapdel __P((struct hostmap *));
151
152
153 int nat_init()
154 {
155         KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz);
156         if (nat_table[0] != NULL)
157                 bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *));
158         else
159                 return -1;
160
161         KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz);
162         if (nat_table[1] != NULL)
163                 bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *));
164         else
165                 return -1;
166
167         KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz);
168         if (nat_rules != NULL)
169                 bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *));
170         else
171                 return -1;
172
173         KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz);
174         if (rdr_rules != NULL)
175                 bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *));
176         else
177                 return -1;
178
179         KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz);
180         if (maptable != NULL)
181                 bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
182         else
183                 return -1;
184         return 0;
185 }
186
187
188 static void nat_addrdr(n)
189 ipnat_t *n;
190 {
191         ipnat_t **np;
192         u_32_t j;
193         u_int hv;
194         int k;
195
196         k = countbits(n->in_outmsk);
197         if ((k >= 0) && (k != 32))
198                 rdr_masks |= 1 << k;
199         j = (n->in_outip & n->in_outmsk);
200         hv = NAT_HASH_FN(j, 0, ipf_rdrrules_sz);
201         np = rdr_rules + hv;
202         while (*np != NULL)
203                 np = &(*np)->in_rnext;
204         n->in_rnext = NULL;
205         n->in_prnext = np;
206         *np = n;
207 }
208
209
210 static void nat_addnat(n)
211 ipnat_t *n;
212 {
213         ipnat_t **np;
214         u_32_t j;
215         u_int hv;
216         int k;
217
218         k = countbits(n->in_inmsk);
219         if ((k >= 0) && (k != 32))
220                 nat_masks |= 1 << k;
221         j = (n->in_inip & n->in_inmsk);
222         hv = NAT_HASH_FN(j, 0, ipf_natrules_sz);
223         np = nat_rules + hv;
224         while (*np != NULL)
225                 np = &(*np)->in_mnext;
226         n->in_mnext = NULL;
227         n->in_pmnext = np;
228         *np = n;
229 }
230
231
232 static void nat_delrdr(n)
233 ipnat_t *n;
234 {
235         if (n->in_rnext)
236                 n->in_rnext->in_prnext = n->in_prnext;
237         *n->in_prnext = n->in_rnext;
238 }
239
240
241 static void nat_delnat(n)
242 ipnat_t *n;
243 {
244         if (n->in_mnext)
245                 n->in_mnext->in_pmnext = n->in_pmnext;
246         *n->in_pmnext = n->in_mnext;
247 }
248
249
250 /*
251  * check if an ip address has already been allocated for a given mapping that
252  * is not doing port based translation.
253  *
254  * Must be called with ipf_nat held as a write lock.
255  */
256 static struct hostmap *nat_hostmap(np, real, map)
257 ipnat_t *np;
258 struct in_addr real;
259 struct in_addr map;
260 {
261         hostmap_t *hm;
262         u_int hv;
263
264         hv = real.s_addr % HOSTMAP_SIZE;
265         for (hm = maptable[hv]; hm; hm = hm->hm_next)
266                 if ((hm->hm_realip.s_addr == real.s_addr) &&
267                     (np == hm->hm_ipnat)) {
268                         hm->hm_ref++;
269                         return hm;
270                 }
271
272         KMALLOC(hm, hostmap_t *);
273         if (hm) {
274                 hm->hm_next = maptable[hv];
275                 hm->hm_pnext = maptable + hv;
276                 if (maptable[hv])
277                         maptable[hv]->hm_pnext = &hm->hm_next;
278                 maptable[hv] = hm;
279                 hm->hm_ipnat = np;
280                 hm->hm_realip = real;
281                 hm->hm_mapip = map;
282                 hm->hm_ref = 1;
283         }
284         return hm;
285 }
286
287
288 /*
289  * Must be called with ipf_nat held as a write lock.
290  */
291 static void nat_hostmapdel(hm)
292 struct hostmap *hm;
293 {
294         ATOMIC_DEC32(hm->hm_ref);
295         if (hm->hm_ref == 0) {
296                 if (hm->hm_next)
297                         hm->hm_next->hm_pnext = hm->hm_pnext;
298                 *hm->hm_pnext = hm->hm_next;
299                 KFREE(hm);
300         }
301 }
302
303
304 void fix_outcksum(sp, n)
305 u_short *sp;
306 u_32_t n;
307 {
308         register u_short sumshort;
309         register u_32_t sum1;
310
311         if (!n)
312                 return;
313 #if SOLARIS2 >= 6
314         else if (n & NAT_HW_CKSUM) {
315                 *sp = n & 0xffff;
316                 return;
317         }
318 #endif
319         sum1 = (~ntohs(*sp)) & 0xffff;
320         sum1 += (n);
321         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
322         /* Again */
323         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
324         sumshort = ~(u_short)sum1;
325         *(sp) = htons(sumshort);
326 }
327
328
329 void fix_incksum(sp, n)
330 u_short *sp;
331 u_32_t n;
332 {
333         register u_short sumshort;
334         register u_32_t sum1;
335
336         if (!n)
337                 return;
338 #if SOLARIS2 >= 6
339         else if (n & NAT_HW_CKSUM) {
340                 *sp = n & 0xffff;
341                 return;
342         }
343 #endif
344 #ifdef sparc
345         sum1 = (~(*sp)) & 0xffff;
346 #else
347         sum1 = (~ntohs(*sp)) & 0xffff;
348 #endif
349         sum1 += ~(n) & 0xffff;
350         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
351         /* Again */
352         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
353         sumshort = ~(u_short)sum1;
354         *(sp) = htons(sumshort);
355 }
356
357
358 /*
359  * fix_datacksum is used *only* for the adjustments of checksums in the data
360  * section of an IP packet.
361  *
362  * The only situation in which you need to do this is when NAT'ing an 
363  * ICMP error message. Such a message, contains in its body the IP header
364  * of the original IP packet, that causes the error.
365  *
366  * You can't use fix_incksum or fix_outcksum in that case, because for the
367  * kernel the data section of the ICMP error is just data, and no special 
368  * processing like hardware cksum or ntohs processing have been done by the 
369  * kernel on the data section.
370  */
371 void fix_datacksum(sp, n)
372 u_short *sp;
373 u_32_t n;
374 {
375         register u_short sumshort;
376         register u_32_t sum1;
377
378         if (!n)
379                 return;
380
381         sum1 = (~ntohs(*sp)) & 0xffff;
382         sum1 += (n);
383         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
384         /* Again */
385         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
386         sumshort = ~(u_short)sum1;
387         *(sp) = htons(sumshort);
388 }
389
390 /*
391  * How the NAT is organised and works.
392  *
393  * Inside (interface y) NAT       Outside (interface x)
394  * -------------------- -+- -------------------------------------
395  * Packet going          |   out, processsed by ip_natout() for x
396  * ------------>         |   ------------>
397  * src=10.1.1.1          |   src=192.1.1.1
398  *                       |
399  *                       |   in, processed by ip_natin() for x
400  * <------------         |   <------------
401  * dst=10.1.1.1          |   dst=192.1.1.1
402  * -------------------- -+- -------------------------------------
403  * ip_natout() - changes ip_src and if required, sport
404  *             - creates a new mapping, if required.
405  * ip_natin()  - changes ip_dst and if required, dport
406  *
407  * In the NAT table, internal source is recorded as "in" and externally
408  * seen as "out".
409  */
410
411 /*
412  * Handle ioctls which manipulate the NAT.
413  */
414 int nat_ioctl(data, cmd, mode)
415 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
416 u_long cmd;
417 #else
418 int cmd;
419 #endif
420 caddr_t data;
421 int mode;
422 {
423         register ipnat_t *nat, *nt, *n = NULL, **np = NULL;
424         int error = 0, ret, arg;
425         ipnat_t natd;
426         u_32_t i, j;
427
428 #if (BSD >= 199306) && defined(_KERNEL)
429         if ((securelevel >= 2) && (mode & FWRITE))
430                 return EPERM;
431 #endif
432
433         nat = NULL;     /* XXX gcc -Wuninitialized */
434         KMALLOC(nt, ipnat_t *);
435         if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT))
436                 error = IRCOPYPTR(data, (char *)&natd, sizeof(natd));
437         else if (cmd == SIOCIPFFL) {    /* SIOCFLNAT & SIOCCNATL */
438                 error = IRCOPY(data, (char *)&arg, sizeof(arg));
439                 if (error)
440                         error = EFAULT;
441         }
442
443         if (error)
444                 goto done;
445
446         /*
447          * For add/delete, look to see if the NAT entry is already present
448          */
449         WRITE_ENTER(&ipf_nat);
450         if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
451                 nat = &natd;
452                 nat->in_flags &= IPN_USERFLAGS;
453                 if ((nat->in_redir & NAT_MAPBLK) == 0) {
454                         if ((nat->in_flags & IPN_SPLIT) == 0)
455                                 nat->in_inip &= nat->in_inmsk;
456                         if ((nat->in_flags & IPN_IPRANGE) == 0)
457                                 nat->in_outip &= nat->in_outmsk;
458                 }
459                 for (np = &nat_list; (n = *np); np = &n->in_next)
460                         if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
461                                         IPN_CMPSIZ))
462                                 break;
463         }
464
465         switch (cmd)
466         {
467 #ifdef  IPFILTER_LOG
468         case SIOCIPFFB :
469         {
470                 int tmp;
471
472                 if (!(mode & FWRITE))
473                         error = EPERM;
474                 else {
475                         tmp = ipflog_clear(IPL_LOGNAT);
476                         IWCOPY((char *)&tmp, (char *)data, sizeof(tmp));
477                 }
478                 break;
479         }
480 #endif
481         case SIOCADNAT :
482                 if (!(mode & FWRITE)) {
483                         error = EPERM;
484                         break;
485                 }
486                 if (n) {
487                         error = EEXIST;
488                         break;
489                 }
490                 if (nt == NULL) {
491                         error = ENOMEM;
492                         break;
493                 }
494                 n = nt;
495                 nt = NULL;
496                 bcopy((char *)nat, (char *)n, sizeof(*n));
497                 n->in_ifp = (void *)GETUNIT(n->in_ifname, 4);
498                 if (!n->in_ifp)
499                         n->in_ifp = (void *)-1;
500                 if (n->in_plabel[0] != '\0') {
501                         n->in_apr = appr_match(n->in_p, n->in_plabel);
502                         if (!n->in_apr) {
503                                 error = ENOENT;
504                                 break;
505                         }
506                 }
507                 n->in_next = NULL;
508                 *np = n;
509
510                 if (n->in_redir & NAT_REDIRECT) {
511                         n->in_flags &= ~IPN_NOTDST;
512                         nat_addrdr(n);
513                 }
514                 if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
515                         n->in_flags &= ~IPN_NOTSRC;
516                         nat_addnat(n);
517                 }
518
519                 n->in_use = 0;
520                 if (n->in_redir & NAT_MAPBLK)
521                         n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk);
522                 else if (n->in_flags & IPN_AUTOPORTMAP)
523                         n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk);
524                 else if (n->in_flags & IPN_IPRANGE)
525                         n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip);
526                 else if (n->in_flags & IPN_SPLIT)
527                         n->in_space = 2;
528                 else
529                         n->in_space = ~ntohl(n->in_outmsk);
530                 /*
531                  * Calculate the number of valid IP addresses in the output
532                  * mapping range.  In all cases, the range is inclusive of
533                  * the start and ending IP addresses.
534                  * If to a CIDR address, lose 2: broadcast + network address
535                  *                               (so subtract 1)
536                  * If to a range, add one.
537                  * If to a single IP address, set to 1.
538                  */
539                 if (n->in_space) {
540                         if ((n->in_flags & IPN_IPRANGE) != 0)
541                                 n->in_space += 1;
542                         else
543                                 n->in_space -= 1;
544                 } else
545                         n->in_space = 1;
546                 if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) &&
547                     ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0))
548                         n->in_nip = ntohl(n->in_outip) + 1;
549                 else if ((n->in_flags & IPN_SPLIT) &&
550                          (n->in_redir & NAT_REDIRECT))
551                         n->in_nip = ntohl(n->in_inip);
552                 else
553                         n->in_nip = ntohl(n->in_outip);
554                 if (n->in_redir & NAT_MAP) {
555                         n->in_pnext = ntohs(n->in_pmin);
556                         /*
557                          * Multiply by the number of ports made available.
558                          */
559                         if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) {
560                                 n->in_space *= (ntohs(n->in_pmax) -
561                                                 ntohs(n->in_pmin) + 1);
562                                 /*
563                                  * Because two different sources can map to
564                                  * different destinations but use the same
565                                  * local IP#/port #.
566                                  * If the result is smaller than in_space, then
567                                  * we may have wrapped around 32bits.
568                                  */
569                                 i = n->in_inmsk;
570                                 if ((i != 0) && (i != 0xffffffff)) {
571                                         j = n->in_space * (~ntohl(i) + 1);
572                                         if (j >= n->in_space)
573                                                 n->in_space = j;
574                                         else
575                                                 n->in_space = 0xffffffff;
576                                 }
577                         }
578                         /*
579                          * If no protocol is specified, multiple by 256.
580                          */
581                         if ((n->in_flags & IPN_TCPUDP) == 0) {
582                                         j = n->in_space * 256;
583                                         if (j >= n->in_space)
584                                                 n->in_space = j;
585                                         else
586                                                 n->in_space = 0xffffffff;
587                         }
588                 }
589                 /* Otherwise, these fields are preset */
590                 n = NULL;
591                 nat_stats.ns_rules++;
592                 break;
593         case SIOCRMNAT :
594                 if (!(mode & FWRITE)) {
595                         error = EPERM;
596                         n = NULL;
597                         break;
598                 }
599                 if (!n) {
600                         error = ESRCH;
601                         break;
602                 }
603                 if (n->in_redir & NAT_REDIRECT)
604                         nat_delrdr(n);
605                 if (n->in_redir & (NAT_MAPBLK|NAT_MAP))
606                         nat_delnat(n);
607                 if (nat_list == NULL) {
608                         nat_masks = 0;
609                         rdr_masks = 0;
610                 }
611                 *np = n->in_next;
612                 if (!n->in_use) {
613                         if (n->in_apr)
614                                 appr_free(n->in_apr);
615                         KFREE(n);
616                         nat_stats.ns_rules--;
617                 } else {
618                         n->in_flags |= IPN_DELETE;
619                         n->in_next = NULL;
620                 }
621                 n = NULL;
622                 break;
623         case SIOCGNATS :
624                 MUTEX_DOWNGRADE(&ipf_nat);
625                 nat_stats.ns_table[0] = nat_table[0];
626                 nat_stats.ns_table[1] = nat_table[1];
627                 nat_stats.ns_list = nat_list;
628                 nat_stats.ns_nattab_sz = ipf_nattable_sz;
629                 nat_stats.ns_rultab_sz = ipf_natrules_sz;
630                 nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz;
631                 nat_stats.ns_instances = nat_instances;
632                 nat_stats.ns_apslist = ap_sess_list;
633                 error = IWCOPYPTR((char *)&nat_stats, (char *)data,
634                                   sizeof(nat_stats));
635                 break;
636         case SIOCGNATL :
637             {
638                 natlookup_t nl;
639
640                 MUTEX_DOWNGRADE(&ipf_nat);
641                 error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl));
642                 if (error)
643                         break;
644
645                 if (nat_lookupredir(&nl)) {
646                         error = IWCOPYPTR((char *)&nl, (char *)data,
647                                           sizeof(nl));
648                 } else
649                         error = ESRCH;
650                 break;
651             }
652         case SIOCIPFFL :        /* old SIOCFLNAT & SIOCCNATL */
653                 if (!(mode & FWRITE)) {
654                         error = EPERM;
655                         break;
656                 }
657                 error = 0;
658                 if (arg == 0)
659                         ret = nat_flushtable();
660                 else if (arg == 1)
661                         ret = nat_clearlist();
662                 else
663                         error = EINVAL;
664                 MUTEX_DOWNGRADE(&ipf_nat);
665                 if (!error) {
666                         error = IWCOPY((caddr_t)&ret, data, sizeof(ret));
667                         if (error)
668                                 error = EFAULT;
669                 }
670                 break;
671         case SIOCSTLCK :
672                 error = IRCOPY(data, (caddr_t)&arg, sizeof(arg));
673                 if (!error) {
674                         error = IWCOPY((caddr_t)&fr_nat_lock, data,
675                                         sizeof(fr_nat_lock));
676                         if (!error)
677                                 fr_nat_lock = arg;
678                 } else
679                         error = EFAULT;
680                 break;
681         case SIOCSTPUT :
682                 if (fr_nat_lock)
683                         error = fr_natputent(data);
684                 else
685                         error = EACCES;
686                 break;
687         case SIOCSTGSZ :
688                 if (fr_nat_lock)
689                         error = fr_natgetsz(data);
690                 else
691                         error = EACCES;
692                 break;
693         case SIOCSTGET :
694                 if (fr_nat_lock)
695                         error = fr_natgetent(data);
696                 else
697                         error = EACCES;
698                 break;
699         case FIONREAD :
700 #ifdef  IPFILTER_LOG
701                 arg = (int)iplused[IPL_LOGNAT];
702                 MUTEX_DOWNGRADE(&ipf_nat);
703                 error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg));
704                 if (error)
705                         error = EFAULT;
706 #endif
707                 break;
708         default :
709                 error = EINVAL;
710                 break;
711         }
712         RWLOCK_EXIT(&ipf_nat);                  /* READ/WRITE */
713 done:
714         if (nt)
715                 KFREE(nt);
716         return error;
717 }
718
719
720 static int fr_natgetsz(data)
721 caddr_t data;
722 {
723         ap_session_t *aps;
724         nat_t *nat, *n;
725         int error = 0;
726         natget_t ng;
727
728         error = IRCOPY(data, (caddr_t)&ng, sizeof(ng));
729         if (error)
730                 return EFAULT;
731
732         nat = ng.ng_ptr;
733         if (!nat) {
734                 nat = nat_instances;
735                 ng.ng_sz = 0;
736                 if (nat == NULL) {
737                         error = IWCOPY((caddr_t)&ng, data, sizeof(ng));
738                         if (error)
739                                 error = EFAULT;
740                         return error;
741                 }
742         } else {
743                 /*
744                  * Make sure the pointer we're copying from exists in the
745                  * current list of entries.  Security precaution to prevent
746                  * copying of random kernel data.
747                  */
748                 for (n = nat_instances; n; n = n->nat_next)
749                         if (n == nat)
750                                 break;
751                 if (!n)
752                         return ESRCH;
753         }
754
755         ng.ng_sz = sizeof(nat_save_t);
756         aps = nat->nat_aps;
757         if ((aps != NULL) && (aps->aps_data != 0)) {
758                 ng.ng_sz += sizeof(ap_session_t);
759                 ng.ng_sz += aps->aps_psiz;
760         }
761
762         error = IWCOPY((caddr_t)&ng, data, sizeof(ng));
763         if (error)
764                 error = EFAULT;
765         return error;
766 }
767
768
769 static int fr_natgetent(data)
770 caddr_t data;
771 {
772         nat_save_t ipn, *ipnp, *ipnn = NULL;
773         register nat_t *n, *nat;
774         ap_session_t *aps;
775         int error;
776
777         error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp));
778         if (error)
779                 return EFAULT;
780         error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn));
781         if (error)
782                 return EFAULT;
783
784         nat = ipn.ipn_next;
785         if (!nat) {
786                 nat = nat_instances;
787                 if (nat == NULL) {
788                         if (nat_instances == NULL)
789                                 return ENOENT;
790                         return 0;
791                 }
792         } else {
793                 /*
794                  * Make sure the pointer we're copying from exists in the
795                  * current list of entries.  Security precaution to prevent
796                  * copying of random kernel data.
797                  */
798                 for (n = nat_instances; n; n = n->nat_next)
799                         if (n == nat)
800                                 break;
801                 if (!n)
802                         return ESRCH;
803         }
804
805         ipn.ipn_next = nat->nat_next;
806         ipn.ipn_dsize = 0;
807         bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat));
808         ipn.ipn_nat.nat_data = NULL;
809
810         if (nat->nat_ptr) {
811                 bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat,
812                       sizeof(ipn.ipn_ipnat));
813         }
814
815         if (nat->nat_fr)
816                 bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule,
817                       sizeof(ipn.ipn_rule));
818
819         if ((aps = nat->nat_aps)) {
820                 ipn.ipn_dsize = sizeof(*aps);
821                 if (aps->aps_data)
822                         ipn.ipn_dsize += aps->aps_psiz;
823                 KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize);
824                 if (ipnn == NULL)
825                         return ENOMEM;
826                 bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn));
827
828                 bcopy((char *)aps, ipnn->ipn_data, sizeof(*aps));
829                 if (aps->aps_data) {
830                         bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps),
831                               aps->aps_psiz);
832                         ipnn->ipn_dsize += aps->aps_psiz;
833                 }
834                 error = IWCOPY((caddr_t)ipnn, ipnp,
835                                sizeof(ipn) + ipn.ipn_dsize);
836                 if (error)
837                         error = EFAULT;
838                 KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize);
839         } else {
840                 error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn));
841                 if (error)
842                         error = EFAULT;
843         }
844         return error;
845 }
846
847
848 static int fr_natputent(data)
849 caddr_t data;
850 {
851         nat_save_t ipn, *ipnp, *ipnn = NULL;
852         register nat_t *n, *nat;
853         ap_session_t *aps;
854         frentry_t *fr;
855         ipnat_t *in;
856
857         int error;
858
859         error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp));
860         if (error)
861                 return EFAULT;
862         error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn));
863         if (error)
864                 return EFAULT;
865         nat = NULL;
866         if (ipn.ipn_dsize) {
867                 KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize);
868                 if (ipnn == NULL)
869                         return ENOMEM;
870                 bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn));
871                 error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data,
872                                ipn.ipn_dsize);
873                 if (error) {
874                         error = EFAULT;
875                         goto junkput;
876                 }
877         } else
878                 ipnn = NULL;
879
880         KMALLOC(nat, nat_t *);
881         if (nat == NULL) {
882                 error = EFAULT;
883                 goto junkput;
884         }
885
886         bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat));
887         /*
888          * Initialize all these so that nat_delete() doesn't cause a crash.
889          */
890         nat->nat_phnext[0] = NULL;
891         nat->nat_phnext[1] = NULL;
892         fr = nat->nat_fr;
893         nat->nat_fr = NULL;
894         aps = nat->nat_aps;
895         nat->nat_aps = NULL;
896         in = nat->nat_ptr;
897         nat->nat_ptr = NULL;
898         nat->nat_data = NULL;
899
900         /*
901          * Restore the rule associated with this nat session
902          */
903         if (in) {
904                 KMALLOC(in, ipnat_t *);
905                 if (in == NULL) {
906                         error = ENOMEM;
907                         goto junkput;
908                 }
909                 nat->nat_ptr = in;
910                 bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in));
911                 in->in_use = 1;
912                 in->in_flags |= IPN_DELETE;
913                 in->in_next = NULL;
914                 in->in_rnext = NULL;
915                 in->in_prnext = NULL;
916                 in->in_mnext = NULL;
917                 in->in_pmnext = NULL;
918                 in->in_ifp = GETUNIT(in->in_ifname, 4);
919                 if (in->in_plabel[0] != '\0') {
920                         in->in_apr = appr_match(in->in_p, in->in_plabel);
921                 }
922         }
923
924         /*
925          * Restore ap_session_t structure.  Include the private data allocated
926          * if it was there.
927          */
928         if (aps) {
929                 KMALLOC(aps, ap_session_t *);
930                 if (aps == NULL) {
931                         error = ENOMEM;
932                         goto junkput;
933                 }
934                 nat->nat_aps = aps;
935                 aps->aps_next = ap_sess_list;
936                 ap_sess_list = aps;
937                 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps));
938                 if (in)
939                         aps->aps_apr = in->in_apr;
940                 if (aps->aps_psiz) {
941                         KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
942                         if (aps->aps_data == NULL) {
943                                 error = ENOMEM;
944                                 goto junkput;
945                         }
946                         bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data,
947                               aps->aps_psiz);
948                 } else {
949                         aps->aps_psiz = 0;
950                         aps->aps_data = NULL;
951                 }
952         }
953
954         /*
955          * If there was a filtering rule associated with this entry then
956          * build up a new one.
957          */
958         if (fr != NULL) {
959                 if (nat->nat_flags & FI_NEWFR) {
960                         KMALLOC(fr, frentry_t *);
961                         nat->nat_fr = fr;
962                         if (fr == NULL) {
963                                 error = ENOMEM;
964                                 goto junkput;
965                         }
966                         bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr));
967                         ipn.ipn_nat.nat_fr = fr;
968                         error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn));
969                         if (error) {
970                                 error = EFAULT;
971                                 goto junkput;
972                         }
973                 } else {
974                         for (n = nat_instances; n; n = n->nat_next)
975                                 if (n->nat_fr == fr)
976                                         break;
977                         if (!n) {
978                                 error = ESRCH;
979                                 goto junkput;
980                         }
981                 }
982         }
983
984         if (ipnn)
985                 KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize);
986         nat_insert(nat);
987         return 0;
988 junkput:
989         if (ipnn)
990                 KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize);
991         if (nat)
992                 nat_delete(nat);
993         return error;
994 }
995
996
997 /*
998  * Delete a nat entry from the various lists and table.
999  */
1000 static void nat_delete(natd)
1001 struct nat *natd;
1002 {
1003         struct ipnat *ipn;
1004
1005         if (natd->nat_flags & FI_WILDP)
1006                 nat_stats.ns_wilds--;
1007         if (natd->nat_hnext[0])
1008                 natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0];
1009         *natd->nat_phnext[0] = natd->nat_hnext[0];
1010         if (natd->nat_hnext[1])
1011                 natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1];
1012         *natd->nat_phnext[1] = natd->nat_hnext[1];
1013
1014         if (natd->nat_fr != NULL) {
1015                 ATOMIC_DEC32(natd->nat_fr->fr_ref);
1016         }
1017
1018         if (natd->nat_hm != NULL)
1019                 nat_hostmapdel(natd->nat_hm);
1020
1021         /*
1022          * If there is an active reference from the nat entry to its parent
1023          * rule, decrement the rule's reference count and free it too if no
1024          * longer being used.
1025          */
1026         ipn = natd->nat_ptr;
1027         if (ipn != NULL) {
1028                 ipn->in_space++;
1029                 ipn->in_use--;
1030                 if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) {
1031                         if (ipn->in_apr)
1032                                 appr_free(ipn->in_apr);
1033                         KFREE(ipn);
1034                         nat_stats.ns_rules--;
1035                 }
1036         }
1037
1038         MUTEX_DESTROY(&natd->nat_lock);
1039         /*
1040          * If there's a fragment table entry too for this nat entry, then
1041          * dereference that as well.
1042          */
1043         ipfr_forget((void *)natd);
1044         aps_free(natd->nat_aps);
1045         nat_stats.ns_inuse--;
1046         KFREE(natd);
1047 }
1048
1049
1050 /*
1051  * nat_flushtable - clear the NAT table of all mapping entries.
1052  */
1053 static int nat_flushtable()
1054 {
1055         register nat_t *nat, **natp;
1056         register int j = 0;
1057
1058         /*
1059          * ALL NAT mappings deleted, so lets just make the deletions
1060          * quicker.
1061          */
1062         if (nat_table[0] != NULL)
1063                 bzero((char *)nat_table[0],
1064                       sizeof(nat_table[0]) * ipf_nattable_sz);
1065         if (nat_table[1] != NULL)
1066                 bzero((char *)nat_table[1],
1067                       sizeof(nat_table[1]) * ipf_nattable_sz);
1068
1069         for (natp = &nat_instances; (nat = *natp); ) {
1070                 *natp = nat->nat_next;
1071 #ifdef  IPFILTER_LOG
1072                 nat_log(nat, NL_FLUSH);
1073 #endif
1074                 nat_delete(nat);
1075                 j++;
1076         }
1077         nat_stats.ns_inuse = 0;
1078         return j;
1079 }
1080
1081
1082 /*
1083  * nat_clearlist - delete all rules in the active NAT mapping list.
1084  */
1085 static int nat_clearlist()
1086 {
1087         register ipnat_t *n, **np = &nat_list;
1088         int i = 0;
1089
1090         if (nat_rules != NULL)
1091                 bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz);
1092         if (rdr_rules != NULL)
1093                 bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz);
1094
1095         while ((n = *np)) {
1096                 *np = n->in_next;
1097                 if (!n->in_use) {
1098                         if (n->in_apr)
1099                                 appr_free(n->in_apr);
1100                         KFREE(n);
1101                         nat_stats.ns_rules--;
1102                 } else {
1103                         n->in_flags |= IPN_DELETE;
1104                         n->in_next = NULL;
1105                 }
1106                 i++;
1107         }
1108         nat_masks = 0;
1109         rdr_masks = 0;
1110         return i;
1111 }
1112
1113
1114 /*
1115  * Create a new NAT table entry.
1116  * NOTE: assumes write lock on ipf_nat has been obtained already.
1117  */
1118 nat_t *nat_new(np, ip, fin, flags, direction)
1119 ipnat_t *np;
1120 ip_t *ip;
1121 fr_info_t *fin;
1122 u_int flags;
1123 int direction;
1124 {
1125         register u_32_t sum1, sum2, sumd, l;
1126         u_short port = 0, sport = 0, dport = 0, nport = 0;
1127         struct in_addr in, inb;
1128         tcphdr_t *tcp = NULL;
1129         hostmap_t *hm = NULL;
1130         nat_t *nat, *natl;
1131         u_short nflags;
1132 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
1133         qif_t *qf = fin->fin_qif;
1134 #endif
1135
1136         nflags = flags & np->in_flags;
1137         if (flags & IPN_TCPUDP) {
1138                 tcp = (tcphdr_t *)fin->fin_dp;
1139                 sport = tcp->th_sport;
1140                 dport = tcp->th_dport;
1141         }
1142
1143         /* Give me a new nat */
1144         KMALLOC(nat, nat_t *);
1145         if (nat == NULL) {
1146                 nat_stats.ns_memfail++;
1147                 return NULL;
1148         }
1149
1150         bzero((char *)nat, sizeof(*nat));
1151         nat->nat_flags = flags;
1152         if (flags & FI_WILDP)
1153                 nat_stats.ns_wilds++;
1154         /*
1155          * Search the current table for a match.
1156          */
1157         if (direction == NAT_OUTBOUND) {
1158                 /*
1159                  * Values at which the search for a free resouce starts.
1160                  */
1161                 u_32_t st_ip;
1162                 u_short st_port;
1163
1164                 /*
1165                  * If it's an outbound packet which doesn't match any existing
1166                  * record, then create a new port
1167                  */
1168                 l = 0;
1169                 st_ip = np->in_nip;
1170                 st_port = np->in_pnext;
1171
1172                 do {
1173                         port = 0;
1174                         in.s_addr = htonl(np->in_nip);
1175                         if (l == 0) {
1176                                 /*
1177                                  * Check to see if there is an existing NAT
1178                                  * setup for this IP address pair.
1179                                  */
1180                                 hm = nat_hostmap(np, ip->ip_src, in);
1181                                 if (hm != NULL)
1182                                         in.s_addr = hm->hm_mapip.s_addr;
1183                         } else if ((l == 1) && (hm != NULL)) {
1184                                 nat_hostmapdel(hm);
1185                                 hm = NULL;
1186                         }
1187                         in.s_addr = ntohl(in.s_addr);
1188
1189                         nat->nat_hm = hm;
1190
1191                         if ((np->in_outmsk == 0xffffffff) &&
1192                             (np->in_pnext == 0)) {
1193                                 if (l > 0)
1194                                         goto badnat;
1195                         }
1196
1197                         if (np->in_redir & NAT_MAPBLK) {
1198                                 if ((l >= np->in_ppip) || ((l > 0) &&
1199                                      !(flags & IPN_TCPUDP)))
1200                                         goto badnat;
1201                                 /*
1202                                  * map-block - Calculate destination address.
1203                                  */
1204                                 in.s_addr = ntohl(ip->ip_src.s_addr);
1205                                 in.s_addr &= ntohl(~np->in_inmsk);
1206                                 inb.s_addr = in.s_addr;
1207                                 in.s_addr /= np->in_ippip;
1208                                 in.s_addr &= ntohl(~np->in_outmsk);
1209                                 in.s_addr += ntohl(np->in_outip);
1210                                 /*
1211                                  * Calculate destination port.
1212                                  */
1213                                 if ((flags & IPN_TCPUDP) &&
1214                                     (np->in_ppip != 0)) {
1215                                         port = ntohs(sport) + l;
1216                                         port %= np->in_ppip;
1217                                         port += np->in_ppip *
1218                                                 (inb.s_addr % np->in_ippip);
1219                                         port += MAPBLK_MINPORT;
1220                                         port = htons(port);
1221                                 }
1222                         } else if (!np->in_outip &&
1223                                    (np->in_outmsk == 0xffffffff)) {
1224                                 /*
1225                                  * 0/32 - use the interface's IP address.
1226                                  */
1227                                 if ((l > 0) ||
1228                                     fr_ifpaddr(4, fin->fin_ifp, &in) == -1)
1229                                         goto badnat;
1230                                 in.s_addr = ntohl(in.s_addr);
1231                         } else if (!np->in_outip && !np->in_outmsk) {
1232                                 /*
1233                                  * 0/0 - use the original source address/port.
1234                                  */
1235                                 if (l > 0)
1236                                         goto badnat;
1237                                 in.s_addr = ntohl(ip->ip_src.s_addr);
1238                         } else if ((np->in_outmsk != 0xffffffff) &&
1239                                    (np->in_pnext == 0) &&
1240                                    ((l > 0) || (hm == NULL)))
1241                                 np->in_nip++;
1242                         natl = NULL;
1243
1244                         if ((nflags & IPN_TCPUDP) &&
1245                             ((np->in_redir & NAT_MAPBLK) == 0) &&
1246                             (np->in_flags & IPN_AUTOPORTMAP)) {
1247                                 if ((l > 0) && (l % np->in_ppip == 0)) {
1248                                         if (l > np->in_space) {
1249                                                 goto badnat;
1250                                         } else if ((l > np->in_ppip) &&
1251                                                    np->in_outmsk != 0xffffffff)
1252                                                 np->in_nip++;
1253                                 }
1254                                 if (np->in_ppip != 0) {
1255                                         port = ntohs(sport);
1256                                         port += (l % np->in_ppip);
1257                                         port %= np->in_ppip;
1258                                         port += np->in_ppip *
1259                                                 (ntohl(ip->ip_src.s_addr) %
1260                                                  np->in_ippip);
1261                                         port += MAPBLK_MINPORT;
1262                                         port = htons(port);
1263                                 }
1264                         } else if (((np->in_redir & NAT_MAPBLK) == 0) &&
1265                                    (nflags & IPN_TCPUDP) &&
1266                                    (np->in_pnext != 0)) {
1267                                 port = htons(np->in_pnext++);
1268                                 if (np->in_pnext > ntohs(np->in_pmax)) {
1269                                         np->in_pnext = ntohs(np->in_pmin);
1270                                         if (np->in_outmsk != 0xffffffff)
1271                                                 np->in_nip++;
1272                                 }
1273                         }
1274
1275                         if (np->in_flags & IPN_IPRANGE) {
1276                                 if (np->in_nip > ntohl(np->in_outmsk))
1277                                         np->in_nip = ntohl(np->in_outip);
1278                         } else {
1279                                 if ((np->in_outmsk != 0xffffffff) &&
1280                                     ((np->in_nip + 1) & ntohl(np->in_outmsk)) >
1281                                     ntohl(np->in_outip))
1282                                         np->in_nip = ntohl(np->in_outip) + 1;
1283                         }
1284
1285                         if (!port && (flags & IPN_TCPUDP))
1286                                 port = sport;
1287
1288                         /*
1289                          * Here we do a lookup of the connection as seen from
1290                          * the outside.  If an IP# pair already exists, try
1291                          * again.  So if you have A->B becomes C->B, you can
1292                          * also have D->E become C->E but not D->B causing
1293                          * another C->B.  Also take protocol and ports into
1294                          * account when determining whether a pre-existing
1295                          * NAT setup will cause an external conflict where
1296                          * this is appropriate.
1297                          */
1298                         inb.s_addr = htonl(in.s_addr);
1299                         natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP,
1300                                             (u_int)ip->ip_p, ip->ip_dst, inb,
1301                                             (port << 16) | dport, 1);
1302
1303                         /*
1304                          * Has the search wrapped around and come back to the
1305                          * start ?
1306                          */
1307                         if ((natl != NULL) &&
1308                             (np->in_pnext != 0) && (st_port == np->in_pnext) &&
1309                             (np->in_nip != 0) && (st_ip == np->in_nip))
1310                                 goto badnat;
1311                         l++;
1312                 } while (natl != NULL);
1313
1314                 if (np->in_space > 0)
1315                         np->in_space--;
1316
1317                 /* Setup the NAT table */
1318                 nat->nat_inip = ip->ip_src;
1319                 nat->nat_outip.s_addr = htonl(in.s_addr);
1320                 nat->nat_oip = ip->ip_dst;
1321                 if (nat->nat_hm == NULL)
1322                         nat->nat_hm = nat_hostmap(np, ip->ip_src,
1323                                                   nat->nat_outip);
1324
1325                 sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport);
1326                 sum2 = LONG_SUM(in.s_addr) + ntohs(port);
1327
1328                 if (flags & IPN_TCPUDP) {
1329                         nat->nat_inport = sport;
1330                         nat->nat_outport = port;        /* sport */
1331                         nat->nat_oport = dport;
1332                 }
1333         } else {
1334                 /*
1335                  * Otherwise, it's an inbound packet. Most likely, we don't
1336                  * want to rewrite source ports and source addresses. Instead,
1337                  * we want to rewrite to a fixed internal address and fixed
1338                  * internal port.
1339                  */
1340                 if (np->in_flags & IPN_SPLIT) {
1341                         in.s_addr = np->in_nip;
1342                         if (np->in_inip == htonl(in.s_addr))
1343                                 np->in_nip = ntohl(np->in_inmsk);
1344                         else {
1345                                 np->in_nip = ntohl(np->in_inip);
1346                                 if (np->in_flags & IPN_ROUNDR) {
1347                                         nat_delrdr(np);
1348                                         nat_addrdr(np);
1349                                 }
1350                         }
1351                 } else {
1352                         in.s_addr = ntohl(np->in_inip);
1353                         if (np->in_flags & IPN_ROUNDR) {
1354                                 nat_delrdr(np);
1355                                 nat_addrdr(np);
1356                         }
1357                 }
1358                 if (!np->in_pnext)
1359                         nport = dport;
1360                 else {
1361                         /*
1362                          * Whilst not optimized for the case where
1363                          * pmin == pmax, the gain is not significant.
1364                          */
1365                         nport = ntohs(dport) - ntohs(np->in_pmin) +
1366                                 ntohs(np->in_pnext);
1367                         nport = htons(nport);
1368                 }
1369
1370                 /*
1371                  * When the redirect-to address is set to 0.0.0.0, just
1372                  * assume a blank `forwarding' of the packet.  We don't
1373                  * setup any translation for this either.
1374                  */
1375                 if (in.s_addr == 0) {
1376                         if (nport == dport)
1377                                 goto badnat;
1378                         in.s_addr = ntohl(ip->ip_dst.s_addr);
1379                 }
1380
1381                 nat->nat_inip.s_addr = htonl(in.s_addr);
1382                 nat->nat_outip = ip->ip_dst;
1383                 nat->nat_oip = ip->ip_src;
1384
1385                 sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)) + ntohs(dport);
1386                 sum2 = LONG_SUM(in.s_addr) + ntohs(nport);
1387
1388                 if (flags & IPN_TCPUDP) {
1389                         nat->nat_inport = nport;
1390                         nat->nat_outport = dport;
1391                         nat->nat_oport = sport;
1392                 }
1393         }
1394
1395         CALC_SUMD(sum1, sum2, sumd);
1396         nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1397 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
1398         if ((flags == IPN_TCP) && dohwcksum &&
1399             (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) {
1400                 if (direction == NAT_OUTBOUND)
1401                         sum1 = LONG_SUM(ntohl(in.s_addr));
1402                 else
1403                         sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
1404                 sum1 += LONG_SUM(ntohl(ip->ip_dst.s_addr));
1405                 sum1 += 30;
1406                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
1407                 nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff);
1408         } else
1409 #endif
1410                 nat->nat_sumd[1] = nat->nat_sumd[0];
1411
1412         if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {
1413                 if (direction == NAT_OUTBOUND)
1414                         sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
1415                 else
1416                         sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr));
1417
1418                 sum2 = LONG_SUM(in.s_addr);
1419
1420                 CALC_SUMD(sum1, sum2, sumd);
1421                 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
1422         } else
1423                 nat->nat_ipsumd = nat->nat_sumd[0];
1424
1425         in.s_addr = htonl(in.s_addr);
1426
1427 #ifdef  _KERNEL
1428         strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ);
1429 #endif
1430         nat_insert(nat);
1431
1432         nat->nat_dir = direction;
1433         nat->nat_ifp = fin->fin_ifp;
1434         nat->nat_ptr = np;
1435         nat->nat_p = ip->ip_p;
1436         nat->nat_bytes = 0;
1437         nat->nat_pkts = 0;
1438         nat->nat_fr = fin->fin_fr;
1439         if (nat->nat_fr != NULL) {
1440                 ATOMIC_INC32(nat->nat_fr->fr_ref);
1441         }
1442         if (direction == NAT_OUTBOUND) {
1443                 if (flags & IPN_TCPUDP)
1444                         tcp->th_sport = port;
1445         } else {
1446                 if (flags & IPN_TCPUDP)
1447                         tcp->th_dport = nport;
1448         }
1449         np->in_use++;
1450 #ifdef  IPFILTER_LOG
1451         nat_log(nat, (u_int)np->in_redir);
1452 #endif
1453         return nat;
1454 badnat:
1455         nat_stats.ns_badnat++;
1456         if ((hm = nat->nat_hm) != NULL)
1457                 nat_hostmapdel(hm);
1458         KFREE(nat);
1459         return NULL;
1460 }
1461
1462
1463 void    nat_insert(nat)
1464 nat_t   *nat;
1465 {
1466         nat_t **natp;
1467         u_int hv;
1468
1469         MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL);
1470
1471         nat->nat_age = fr_defnatage;
1472         nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0';
1473         if (nat->nat_ifname[0] !='\0') {
1474                 nat->nat_ifp = GETUNIT(nat->nat_ifname, 4);
1475         }
1476
1477         nat->nat_next = nat_instances;
1478         nat_instances = nat;
1479
1480         hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,
1481                          ipf_nattable_sz);
1482         natp = &nat_table[0][hv];
1483         if (*natp)
1484                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
1485         nat->nat_phnext[0] = natp;
1486         nat->nat_hnext[0] = *natp;
1487         *natp = nat;
1488
1489         hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport,
1490                          ipf_nattable_sz);
1491         natp = &nat_table[1][hv];
1492         if (*natp)
1493                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
1494         nat->nat_phnext[1] = natp;
1495         nat->nat_hnext[1] = *natp;
1496         *natp = nat;
1497
1498         nat_stats.ns_added++;
1499         nat_stats.ns_inuse++;
1500 }
1501
1502
1503 nat_t *nat_icmplookup(ip, fin, dir)
1504 ip_t *ip;
1505 fr_info_t *fin;
1506 int dir;
1507 {
1508         icmphdr_t *icmp;
1509         tcphdr_t *tcp = NULL;
1510         ip_t *oip;
1511         int flags = 0, type, minlen;
1512
1513         icmp = (icmphdr_t *)fin->fin_dp;
1514         /*
1515          * Does it at least have the return (basic) IP header ?
1516          * Only a basic IP header (no options) should be with an ICMP error
1517          * header.
1518          */
1519         if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN))
1520                 return NULL;
1521         type = icmp->icmp_type;
1522         /*
1523          * If it's not an error type, then return.
1524          */
1525         if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) &&
1526             (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) &&
1527             (type != ICMP_PARAMPROB))
1528                 return NULL;
1529
1530         oip = (ip_t *)((char *)fin->fin_dp + 8);
1531         minlen = (oip->ip_hl << 2);
1532         if (minlen < sizeof(ip_t))
1533                 return NULL;
1534         if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
1535                 return NULL;
1536         /*
1537          * Is the buffer big enough for all of it ?  It's the size of the IP
1538          * header claimed in the encapsulated part which is of concern.  It
1539          * may be too big to be in this buffer but not so big that it's
1540          * outside the ICMP packet, leading to TCP deref's causing problems.
1541          * This is possible because we don't know how big oip_hl is when we
1542          * do the pullup early in fr_check() and thus can't gaurantee it is
1543          * all here now.
1544          */
1545 #ifdef  _KERNEL
1546         {
1547         mb_t *m;
1548
1549 # if SOLARIS
1550         m = fin->fin_qfm;
1551         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
1552                 return NULL;
1553 # else
1554         m = *(mb_t **)fin->fin_mp;
1555         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
1556             (char *)ip + m->m_len)
1557                 return NULL;
1558 # endif
1559         }
1560 #endif
1561
1562         if (oip->ip_p == IPPROTO_TCP)
1563                 flags = IPN_TCP;
1564         else if (oip->ip_p == IPPROTO_UDP)
1565                 flags = IPN_UDP;
1566         if (flags & IPN_TCPUDP) {
1567                 minlen += 8;            /* + 64bits of data to get ports */
1568                 if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
1569                         return NULL;
1570                 tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
1571                 if (dir == NAT_INBOUND)
1572                         return nat_inlookup(fin->fin_ifp, flags,
1573                                 (u_int)oip->ip_p, oip->ip_dst, oip->ip_src,
1574                                 (tcp->th_sport << 16) | tcp->th_dport, 0);
1575                 else
1576                         return nat_outlookup(fin->fin_ifp, flags,
1577                                 (u_int)oip->ip_p, oip->ip_dst, oip->ip_src,
1578                                 (tcp->th_sport << 16) | tcp->th_dport, 0);
1579         }
1580         if (dir == NAT_INBOUND)
1581                 return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,
1582                         oip->ip_dst, oip->ip_src, 0, 0);
1583         else
1584                 return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,
1585                         oip->ip_dst, oip->ip_src, 0, 0);
1586 }
1587
1588
1589 /*
1590  * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP
1591  * packet gets correctly recognised.
1592  */
1593 nat_t *nat_icmp(ip, fin, nflags, dir)
1594 ip_t *ip;
1595 fr_info_t *fin;
1596 u_int *nflags;
1597 int dir;
1598 {
1599         u_32_t sum1, sum2, sumd, sumd2 = 0;
1600         struct in_addr in;
1601         icmphdr_t *icmp;
1602         udphdr_t *udp;
1603         nat_t *nat;
1604         ip_t *oip;
1605         int flags = 0;
1606
1607         if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK))
1608                 return NULL;
1609         /*
1610          * nat_icmplookup() will return NULL for `defective' packets.
1611          */
1612         if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir)))
1613                 return NULL;
1614         *nflags = IPN_ICMPERR;
1615         icmp = (icmphdr_t *)fin->fin_dp;
1616         oip = (ip_t *)&icmp->icmp_ip;
1617         if (oip->ip_p == IPPROTO_TCP)
1618                 flags = IPN_TCP;
1619         else if (oip->ip_p == IPPROTO_UDP)
1620                 flags = IPN_UDP;
1621         udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
1622         /*
1623          * Need to adjust ICMP header to include the real IP#'s and
1624          * port #'s.  Only apply a checksum change relative to the
1625          * IP address change as it will be modified again in ip_natout
1626          * for both address and port.  Two checksum changes are
1627          * necessary for the two header address changes.  Be careful
1628          * to only modify the checksum once for the port # and twice
1629          * for the IP#.
1630          */
1631
1632         /*
1633          * Step 1
1634          * Fix the IP addresses in the offending IP packet. You also need
1635          * to adjust the IP header checksum of that offending IP packet
1636          * and the ICMP checksum of the ICMP error message itself.
1637          *
1638          * Unfortunately, for UDP and TCP, the IP addresses are also contained
1639          * in the pseudo header that is used to compute the UDP resp. TCP
1640          * checksum. So, we must compensate that as well. Even worse, the
1641          * change in the UDP and TCP checksums require yet another
1642          * adjustment of the ICMP checksum of the ICMP error message.
1643          *
1644          * For the moment we forget about TCP, because that checksum is not
1645          * in the first 8 bytes, so it will not be available in most cases.
1646          */
1647
1648         if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) {
1649                 sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
1650                 in = nat->nat_inip;
1651                 oip->ip_src = in;
1652         } else {
1653                 sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr));
1654                 in = nat->nat_outip;
1655                 oip->ip_dst = in;
1656         }
1657
1658         sum2 = LONG_SUM(ntohl(in.s_addr));
1659
1660         CALC_SUMD(sum1, sum2, sumd);
1661
1662         if (nat->nat_dir == NAT_OUTBOUND) {
1663                 /*
1664                  * Fix IP checksum of the offending IP packet to adjust for
1665                  * the change in the IP address.
1666                  *
1667                  * Normally, you would expect that the ICMP checksum of the 
1668                  * ICMP error message needs to be adjusted as well for the
1669                  * IP address change in oip.
1670                  * However, this is a NOP, because the ICMP checksum is 
1671                  * calculated over the complete ICMP packet, which includes the
1672                  * changed oip IP addresses and oip->ip_sum. However, these 
1673                  * two changes cancel each other out (if the delta for
1674                  * the IP address is x, then the delta for ip_sum is minus x), 
1675                  * so no change in the icmp_cksum is necessary.
1676                  *
1677                  * Be careful that nat_dir refers to the direction of the
1678                  * offending IP packet (oip), not to its ICMP response (icmp)
1679                  */
1680                 fix_datacksum(&oip->ip_sum, sumd);
1681
1682                 /*
1683                  * Fix UDP pseudo header checksum to compensate for the
1684                  * IP address change.
1685                  */
1686                 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1687                         /*
1688                          * The UDP checksum is optional, only adjust it 
1689                          * if it has been set.
1690                          */
1691                         sum1 = ntohs(udp->uh_sum);
1692                         fix_datacksum(&udp->uh_sum, sumd);
1693                         sum2 = ntohs(udp->uh_sum);
1694
1695                         /*
1696                          * Fix ICMP checksum to compensate the UDP 
1697                          * checksum adjustment.
1698                          */
1699                         CALC_SUMD(sum1, sum2, sumd);
1700                         sumd2 = sumd;
1701                 }
1702
1703 #if 0
1704                 /*
1705                  * Fix TCP pseudo header checksum to compensate for the 
1706                  * IP address change. Before we can do the change, we
1707                  * must make sure that oip is sufficient large to hold
1708                  * the TCP checksum (normally it does not!).
1709                  */
1710                 if (oip->ip_p == IPPROTO_TCP) {
1711                 
1712                 }
1713 #endif
1714         } else {
1715
1716                 /*
1717                  * Fix IP checksum of the offending IP packet to adjust for
1718                  * the change in the IP address.
1719                  *
1720                  * Normally, you would expect that the ICMP checksum of the 
1721                  * ICMP error message needs to be adjusted as well for the
1722                  * IP address change in oip.
1723                  * However, this is a NOP, because the ICMP checksum is 
1724                  * calculated over the complete ICMP packet, which includes the
1725                  * changed oip IP addresses and oip->ip_sum. However, these 
1726                  * two changes cancel each other out (if the delta for
1727                  * the IP address is x, then the delta for ip_sum is minus x), 
1728                  * so no change in the icmp_cksum is necessary.
1729                  *
1730                  * Be careful that nat_dir refers to the direction of the
1731                  * offending IP packet (oip), not to its ICMP response (icmp)
1732                  */
1733                 fix_datacksum(&oip->ip_sum, sumd);
1734
1735 /* XXX FV : without having looked at Solaris source code, it seems unlikely
1736  * that SOLARIS would compensate this in the kernel (a body of an IP packet 
1737  * in the data section of an ICMP packet). I have the feeling that this should
1738  * be unconditional, but I'm not in a position to check.
1739  */
1740 #if !SOLARIS && !defined(__sgi)
1741                 /*
1742                  * Fix UDP pseudo header checksum to compensate for the
1743                  * IP address change.
1744                  */
1745                 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1746                         /*
1747                          * The UDP checksum is optional, only adjust it 
1748                          * if it has been set 
1749                          */
1750                         sum1 = ntohs(udp->uh_sum);
1751                         fix_datacksum(&udp->uh_sum, sumd);
1752                         sum2 = ntohs(udp->uh_sum);
1753
1754                         /*
1755                          * Fix ICMP checksum to compensate the UDP 
1756                          * checksum adjustment.
1757                          */
1758                         CALC_SUMD(sum1, sum2, sumd);
1759                         sumd2 = sumd;
1760                 }
1761                 
1762 #if 0
1763                 /* 
1764                  * Fix TCP pseudo header checksum to compensate for the 
1765                  * IP address change. Before we can do the change, we
1766                  * must make sure that oip is sufficient large to hold
1767                  * the TCP checksum (normally it does not!).
1768                  */
1769                 if (oip->ip_p == IPPROTO_TCP) {
1770                 
1771                 };
1772 #endif
1773                 
1774 #endif
1775         }
1776
1777         if ((flags & IPN_TCPUDP) != 0) {
1778                 tcphdr_t *tcp;
1779
1780                 /*
1781                  * XXX - what if this is bogus hl and we go off the end ?
1782                  * In this case, nat_icmpinlookup() will have returned NULL.
1783                  */
1784                 tcp = (tcphdr_t *)udp;
1785
1786                 /*
1787                  * Step 2 :
1788                  * For offending TCP/UDP IP packets, translate the ports as
1789                  * well, based on the NAT specification. Of course such
1790                  * a change must be reflected in the ICMP checksum as well.
1791                  *
1792                  * Advance notice : Now it becomes complicated :-)
1793                  *
1794                  * Since the port fields are part of the TCP/UDP checksum
1795                  * of the offending IP packet, you need to adjust that checksum
1796                  * as well... but, if you change, you must change the icmp
1797                  * checksum *again*, to reflect that change.
1798                  *
1799                  * To further complicate: the TCP checksum is not in the first
1800                  * 8 bytes of the offending ip packet, so it most likely is not
1801                  * available (we might have to fix that if the encounter a
1802                  * device that returns more than 8 data bytes on icmp error)
1803                  */
1804
1805                 if (nat->nat_oport == tcp->th_dport) {
1806                         if (tcp->th_sport != nat->nat_inport) {
1807                                 /*
1808                                  * Fix ICMP checksum to compensate port
1809                                  * adjustment.
1810                                  */
1811                                 sum1 = ntohs(tcp->th_sport);
1812                                 sum2 = ntohs(nat->nat_inport);
1813                                 CALC_SUMD(sum1, sum2, sumd);
1814                                 sumd2 += sumd;
1815                                 tcp->th_sport = nat->nat_inport;
1816
1817                                 /*
1818                                  * Fix udp checksum to compensate port
1819                                  * adjustment.  NOTE : the offending IP packet
1820                                  * flows the other direction compared to the
1821                                  * ICMP message.
1822                                  *
1823                                  * The UDP checksum is optional, only adjust
1824                                  * it if it has been set.
1825                                  */
1826                                 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1827
1828                                         sum1 = ntohs(udp->uh_sum);
1829                                         fix_datacksum(&udp->uh_sum, sumd);
1830                                         sum2 = ntohs(udp->uh_sum);
1831
1832                                         /*
1833                                          * Fix ICMP checksum to 
1834                                          * compensate UDP checksum 
1835                                          * adjustment.
1836                                          */
1837                                         CALC_SUMD(sum1, sum2, sumd);
1838                                         sumd2 += sumd;
1839                                 }
1840                         }
1841                 } else {
1842                         if (tcp->th_dport != nat->nat_outport) {
1843                                 /*
1844                                  * Fix ICMP checksum to compensate port
1845                                  * adjustment.
1846                                  */
1847                                 sum1 = ntohs(tcp->th_dport);
1848                                 sum2 = ntohs(nat->nat_outport);
1849                                 CALC_SUMD(sum1, sum2, sumd);
1850                                 sumd2 += sumd;
1851                                 tcp->th_dport = nat->nat_outport;
1852
1853                                 /*
1854                                  * Fix udp checksum to compensate port
1855                                  * adjustment.   NOTE : the offending IP
1856                                  * packet flows the other direction compared
1857                                  * to the ICMP message.
1858                                  *
1859                                  * The UDP checksum is optional, only adjust
1860                                  * it if it has been set.
1861                                  */
1862                                 if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1863
1864                                         sum1 = ntohs(udp->uh_sum);
1865                                         fix_datacksum(&udp->uh_sum, sumd);
1866                                         sum2 = ntohs(udp->uh_sum);
1867
1868                                         /*
1869                                          * Fix ICMP checksum to compensate
1870                                          * UDP checksum adjustment.
1871                                          */
1872                                         CALC_SUMD(sum1, sum2, sumd);
1873                                         sumd2 += sumd;
1874                                 }
1875                         }
1876                 }
1877                 if (sumd2) {
1878                         sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
1879                         sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
1880                         if (nat->nat_dir == NAT_OUTBOUND) {
1881                                 fix_outcksum(&icmp->icmp_cksum, sumd2);
1882                         } else {
1883                                 fix_incksum(&icmp->icmp_cksum, sumd2);
1884                         }
1885                 }
1886         }
1887         nat->nat_age = fr_defnaticmpage;
1888         return nat;
1889 }
1890
1891
1892 /*
1893  * NB: these lookups don't lock access to the list, it assume it has already
1894  * been done!
1895  */
1896 /*
1897  * Lookup a nat entry based on the mapped destination ip address/port and
1898  * real source address/port.  We use this lookup when receiving a packet,
1899  * we're looking for a table entry, based on the destination address.
1900  * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
1901  */
1902 nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports, rw)
1903 void *ifp;
1904 register u_int flags, p;
1905 struct in_addr src , mapdst;
1906 u_32_t ports;
1907 int rw;
1908 {
1909         register u_short sport, dport;
1910         register nat_t *nat;
1911         register int nflags;
1912         register u_32_t dst;
1913         u_int hv;
1914
1915         dst = mapdst.s_addr;
1916         dport = ports >> 16;
1917         sport = ports & 0xffff;
1918         flags &= IPN_TCPUDP;
1919
1920         hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz);
1921         nat = nat_table[1][hv];
1922         for (; nat; nat = nat->nat_hnext[1]) {
1923                 nflags = nat->nat_flags;
1924                 if ((!ifp || ifp == nat->nat_ifp) &&
1925                     nat->nat_oip.s_addr == src.s_addr &&
1926                     nat->nat_outip.s_addr == dst &&
1927                     (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP)))
1928                      || (p == nat->nat_p)) && (!flags ||
1929                      (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
1930                       ((nat->nat_outport == dport) || (nflags & FI_W_SPORT)))))
1931                         return nat;
1932         }
1933         if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))
1934                 return NULL;
1935         if (!rw) {
1936                 RWLOCK_EXIT(&ipf_nat);
1937         }
1938         hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz);
1939         if (!rw) {
1940                 WRITE_ENTER(&ipf_nat);
1941         }
1942         nat = nat_table[1][hv];
1943         for (; nat; nat = nat->nat_hnext[1]) {
1944                 nflags = nat->nat_flags;
1945                 if (ifp && ifp != nat->nat_ifp)
1946                         continue;
1947                 if (!(nflags & IPN_TCPUDP))
1948                         continue;
1949                 if (!(nflags & FI_WILDP))
1950                         continue;
1951                 if (nat->nat_oip.s_addr != src.s_addr ||
1952                     nat->nat_outip.s_addr != dst)
1953                         continue;
1954                 if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
1955                     ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) {
1956                         nat_tabmove(nat, ports);
1957                         break;
1958                 }
1959         }
1960         if (!rw) {
1961                 MUTEX_DOWNGRADE(&ipf_nat);
1962         }
1963         return nat;
1964 }
1965
1966
1967 /*
1968  * This function is only called for TCP/UDP NAT table entries where the
1969  * original was placed in the table without hashing on the ports and we now
1970  * want to include hashing on port numbers.
1971  */
1972 static void nat_tabmove(nat, ports)
1973 nat_t *nat;
1974 u_32_t ports;
1975 {
1976         register u_short sport, dport;
1977         nat_t **natp;
1978         u_int hv;
1979
1980         dport = ports >> 16;
1981         sport = ports & 0xffff;
1982
1983         if (nat->nat_oport == dport) {
1984                 nat->nat_inport = sport;
1985                 nat->nat_outport = sport;
1986         }
1987
1988         /*
1989          * Remove the NAT entry from the old location
1990          */
1991         if (nat->nat_hnext[0])
1992                 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
1993         *nat->nat_phnext[0] = nat->nat_hnext[0];
1994
1995         if (nat->nat_hnext[1])
1996                 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
1997         *nat->nat_phnext[1] = nat->nat_hnext[1];
1998
1999         /*
2000          * Add into the NAT table in the new position
2001          */
2002         hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, ipf_nattable_sz);
2003         natp = &nat_table[0][hv];
2004         if (*natp)
2005                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
2006         nat->nat_phnext[0] = natp;
2007         nat->nat_hnext[0] = *natp;
2008         *natp = nat;
2009
2010         hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, ipf_nattable_sz);
2011         natp = &nat_table[1][hv];
2012         if (*natp)
2013                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
2014         nat->nat_phnext[1] = natp;
2015         nat->nat_hnext[1] = *natp;
2016         *natp = nat;
2017 }
2018
2019
2020 /*
2021  * Lookup a nat entry based on the source 'real' ip address/port and
2022  * destination address/port.  We use this lookup when sending a packet out,
2023  * we're looking for a table entry, based on the source address.
2024  * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
2025  */
2026 nat_t *nat_outlookup(ifp, flags, p, src, dst, ports, rw)
2027 void *ifp;
2028 register u_int flags, p;
2029 struct in_addr src , dst;
2030 u_32_t ports;
2031 int rw;
2032 {
2033         register u_short sport, dport;
2034         register nat_t *nat;
2035         register int nflags;
2036         u_32_t srcip;
2037         u_int hv;
2038
2039         sport = ports & 0xffff;
2040         dport = ports >> 16;
2041         flags &= IPN_TCPUDP;
2042         srcip = src.s_addr;
2043
2044         hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz);
2045         nat = nat_table[0][hv];
2046         for (; nat; nat = nat->nat_hnext[0]) {
2047                 nflags = nat->nat_flags;
2048
2049                 if ((!ifp || ifp == nat->nat_ifp) &&
2050                     nat->nat_inip.s_addr == srcip &&
2051                     nat->nat_oip.s_addr == dst.s_addr &&
2052                     (((p == 0) && (flags == (nflags & IPN_TCPUDP)))
2053                      || (p == nat->nat_p)) && (!flags ||
2054                      ((nat->nat_inport == sport || nflags & FI_W_SPORT) &&
2055                       (nat->nat_oport == dport || nflags & FI_W_DPORT))))
2056                         return nat;
2057         }
2058         if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))
2059                 return NULL;
2060         if (!rw) {
2061                 RWLOCK_EXIT(&ipf_nat);
2062         }
2063         hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz);
2064         if (!rw) {
2065                 WRITE_ENTER(&ipf_nat);
2066         }
2067         nat = nat_table[0][hv];
2068         for (; nat; nat = nat->nat_hnext[0]) {
2069                 nflags = nat->nat_flags;
2070                 if (ifp && ifp != nat->nat_ifp)
2071                         continue;
2072                 if (!(nflags & IPN_TCPUDP))
2073                         continue;
2074                 if (!(nflags & FI_WILDP))
2075                         continue;
2076                 if ((nat->nat_inip.s_addr != srcip) ||
2077                     (nat->nat_oip.s_addr != dst.s_addr))
2078                         continue;
2079                 if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) &&
2080                     ((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) {
2081                         nat_tabmove(nat, ports);
2082                         break;
2083                 }
2084         }
2085         if (!rw) {
2086                 MUTEX_DOWNGRADE(&ipf_nat);
2087         }
2088         return nat;
2089 }
2090
2091
2092 /*
2093  * Lookup the NAT tables to search for a matching redirect
2094  */
2095 nat_t *nat_lookupredir(np)
2096 register natlookup_t *np;
2097 {
2098         u_32_t ports;
2099         nat_t *nat;
2100
2101         ports = (np->nl_outport << 16) | np->nl_inport;
2102         /*
2103          * If nl_inip is non null, this is a lookup based on the real
2104          * ip address. Else, we use the fake.
2105          */
2106         if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip,
2107                                  np->nl_outip, ports, 0))) {
2108                 np->nl_realip = nat->nat_outip;
2109                 np->nl_realport = nat->nat_outport;
2110         }
2111         return nat;
2112 }
2113
2114
2115 static int nat_match(fin, np, ip)
2116 fr_info_t *fin;
2117 ipnat_t *np;
2118 ip_t *ip;
2119 {
2120         frtuc_t *ft;
2121
2122         if (ip->ip_v != 4)
2123                 return 0;
2124
2125         if (np->in_p && ip->ip_p != np->in_p)
2126                 return 0;
2127         if (fin->fin_out) {
2128                 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
2129                         return 0;
2130                 if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip)
2131                     ^ ((np->in_flags & IPN_NOTSRC) != 0))
2132                         return 0;
2133                 if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip)
2134                     ^ ((np->in_flags & IPN_NOTDST) != 0))
2135                         return 0;
2136         } else {
2137                 if (!(np->in_redir & NAT_REDIRECT))
2138                         return 0;
2139                 if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip)
2140                     ^ ((np->in_flags & IPN_NOTSRC) != 0))
2141                         return 0;
2142                 if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip)
2143                     ^ ((np->in_flags & IPN_NOTDST) != 0))
2144                         return 0;
2145         }
2146
2147         ft = &np->in_tuc;
2148         if (!(fin->fin_fi.fi_fl & FI_TCPUDP) ||
2149             (fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) {
2150                 if (ft->ftu_scmp || ft->ftu_dcmp)
2151                         return 0;
2152                 return 1;
2153         }
2154
2155         return fr_tcpudpchk(ft, fin);
2156 }
2157
2158
2159 /*
2160  * Packets going out on the external interface go through this.
2161  * Here, the source address requires alteration, if anything.
2162  */
2163 int ip_natout(ip, fin)
2164 ip_t *ip;
2165 fr_info_t *fin;
2166 {
2167         register ipnat_t *np = NULL;
2168         register u_32_t ipa;
2169         tcphdr_t *tcp = NULL;
2170         u_short sport = 0, dport = 0, *csump = NULL;
2171         struct ifnet *ifp;
2172         int natadd = 1;
2173         frentry_t *fr;
2174         u_int nflags = 0, hv, msk;
2175         u_32_t iph;
2176         nat_t *nat;
2177         int i;
2178
2179         if (nat_list == NULL || (fr_nat_lock))
2180                 return 0;
2181
2182         if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
2183             fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
2184                 ifp = fr->fr_tif.fd_ifp;
2185         else
2186                 ifp = fin->fin_ifp;
2187
2188         if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
2189                 if (ip->ip_p == IPPROTO_TCP)
2190                         nflags = IPN_TCP;
2191                 else if (ip->ip_p == IPPROTO_UDP)
2192                         nflags = IPN_UDP;
2193                 if ((nflags & IPN_TCPUDP)) {
2194                         tcp = (tcphdr_t *)fin->fin_dp;
2195                         sport = tcp->th_sport;
2196                         dport = tcp->th_dport;
2197                 }
2198         }
2199
2200         ipa = ip->ip_src.s_addr;
2201
2202         READ_ENTER(&ipf_nat);
2203
2204         if ((ip->ip_p == IPPROTO_ICMP) &&
2205             (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND)))
2206                 ;
2207         else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) &&
2208             (nat = ipfr_nat_knownfrag(ip, fin)))
2209                 natadd = 0;
2210         else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p,
2211                                       ip->ip_src, ip->ip_dst,
2212                                       (dport << 16) | sport, 0))) {
2213                 nflags = nat->nat_flags;
2214                 if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {
2215                         if ((nflags & FI_W_SPORT) &&
2216                             (nat->nat_inport != sport))
2217                                 nat->nat_inport = sport;
2218                         else if ((nflags & FI_W_DPORT) &&
2219                                  (nat->nat_oport != dport))
2220                                 nat->nat_oport = dport;
2221                         if (nat->nat_outport == 0)
2222                                 nat->nat_outport = sport;
2223                         nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT);
2224                         nflags = nat->nat_flags;
2225                         nat_stats.ns_wilds--;
2226                 }
2227         } else {
2228                 RWLOCK_EXIT(&ipf_nat);
2229                 WRITE_ENTER(&ipf_nat);
2230                 /*
2231                  * If there is no current entry in the nat table for this IP#,
2232                  * create one for it (if there is a matching rule).
2233                  */
2234                 msk = 0xffffffff;
2235                 i = 32;
2236 maskloop:
2237                 iph = ipa & htonl(msk);
2238                 hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz);
2239                 for (np = nat_rules[hv]; np; np = np->in_mnext)
2240                 {
2241                         if ((np->in_ifp && (np->in_ifp != ifp)) ||
2242                             !np->in_space)
2243                                 continue;
2244                         if ((np->in_flags & IPN_RF) &&
2245                             !(np->in_flags & nflags))
2246                                 continue;
2247                         if (np->in_flags & IPN_FILTER) {
2248                                 if (!nat_match(fin, np, ip))
2249                                         continue;
2250                         } else if ((ipa & np->in_inmsk) != np->in_inip)
2251                                 continue;
2252                         if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) {
2253                                 if (*np->in_plabel && !appr_ok(ip, tcp, np))
2254                                         continue;
2255                                 /*
2256                                  * If it's a redirection, then we don't want to
2257                                  * create new outgoing port stuff.
2258                                  * Redirections are only for incoming
2259                                  * connections.
2260                                  */
2261                                 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
2262                                         continue;
2263                                 if ((nat = nat_new(np, ip, fin, (u_int)nflags,
2264                                                     NAT_OUTBOUND))) {
2265                                         np->in_hits++;
2266                                         break;
2267                                 }
2268                         }
2269                 }
2270                 if ((np == NULL) && (i > 0)) {
2271                         do {
2272                                 i--;
2273                                 msk <<= 1;
2274                         } while ((i >= 0) && ((nat_masks & (1 << i)) == 0));
2275                         if (i >= 0)
2276                                 goto maskloop;
2277                 }
2278                 MUTEX_DOWNGRADE(&ipf_nat);
2279         }
2280
2281         /*
2282          * NOTE: ipf_nat must now only be held as a read lock
2283          */
2284         if (nat) {
2285                 np = nat->nat_ptr;
2286                 if (natadd && (fin->fin_fi.fi_fl & FI_FRAG) &&
2287                     np && (np->in_flags & IPN_FRAG))
2288                         ipfr_nat_newfrag(ip, fin, 0, nat);
2289                 MUTEX_ENTER(&nat->nat_lock);
2290                 nat->nat_age = fr_defnatage;
2291                 nat->nat_bytes += ip->ip_len;
2292                 nat->nat_pkts++;
2293                 MUTEX_EXIT(&nat->nat_lock);
2294
2295                 /*
2296                  * Fix up checksums, not by recalculating them, but
2297                  * simply computing adjustments.
2298                  */
2299                 if (nflags == IPN_ICMPERR) {
2300                         u_32_t s1, s2, sumd;
2301
2302                         s1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
2303                         s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
2304                         CALC_SUMD(s1, s2, sumd);
2305
2306                         if (nat->nat_dir == NAT_OUTBOUND)
2307                                 fix_incksum(&ip->ip_sum, sumd);
2308                         else
2309                                 fix_outcksum(&ip->ip_sum, sumd);
2310                 }
2311 #if SOLARIS || defined(__sgi)
2312                 else {
2313                         if (nat->nat_dir == NAT_OUTBOUND)
2314                                 fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
2315                         else
2316                                 fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
2317                 }
2318 #endif
2319                 ip->ip_src = nat->nat_outip;
2320
2321                 if (!(ip->ip_off & IP_OFFMASK) &&
2322                     !(fin->fin_fi.fi_fl & FI_SHORT)) {
2323
2324                         if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
2325                                 tcp->th_sport = nat->nat_outport;
2326                                 fin->fin_data[0] = ntohs(tcp->th_sport);
2327                         }
2328
2329                         if (ip->ip_p == IPPROTO_TCP) {
2330                                 csump = &tcp->th_sum;
2331                                 MUTEX_ENTER(&nat->nat_lock);
2332                                 fr_tcp_age(&nat->nat_age,
2333                                            nat->nat_tcpstate, fin, 1);
2334                                 if (nat->nat_age < fr_defnaticmpage)
2335                                         nat->nat_age = fr_defnaticmpage;
2336 #ifdef LARGE_NAT
2337                                 else if (nat->nat_age > fr_defnatage)
2338                                         nat->nat_age = fr_defnatage;
2339 #endif
2340                                 /*
2341                                  * Increase this because we may have
2342                                  * "keep state" following this too and
2343                                  * packet storms can occur if this is
2344                                  * removed too quickly.
2345                                  */
2346                                 if (nat->nat_age == fr_tcpclosed)
2347                                         nat->nat_age = fr_tcplastack;
2348                                 MUTEX_EXIT(&nat->nat_lock);
2349                         } else if (ip->ip_p == IPPROTO_UDP) {
2350                                 udphdr_t *udp = (udphdr_t *)tcp;
2351
2352                                 if (udp->uh_sum)
2353                                         csump = &udp->uh_sum;
2354                         } else if (ip->ip_p == IPPROTO_ICMP) {
2355                                 nat->nat_age = fr_defnaticmpage;
2356                         }
2357
2358                         if (csump) {
2359                                 if (nat->nat_dir == NAT_OUTBOUND)
2360                                         fix_outcksum(csump, nat->nat_sumd[1]);
2361                                 else
2362                                         fix_incksum(csump, nat->nat_sumd[1]);
2363                         }
2364                 }
2365
2366                 if ((np->in_apr != NULL) && (np->in_dport == 0 ||
2367                      (tcp != NULL && dport == np->in_dport))) {
2368                         i = appr_check(ip, fin, nat);
2369                         if (i == 0)
2370                                 i = 1;
2371                 } else
2372                         i = 1;
2373                 ATOMIC_INCL(nat_stats.ns_mapped[1]);
2374                 RWLOCK_EXIT(&ipf_nat);  /* READ */
2375                 return i;
2376         }
2377         RWLOCK_EXIT(&ipf_nat);                  /* READ/WRITE */
2378         return 0;
2379 }
2380
2381
2382 /*
2383  * Packets coming in from the external interface go through this.
2384  * Here, the destination address requires alteration, if anything.
2385  */
2386 int ip_natin(ip, fin)
2387 ip_t *ip;
2388 fr_info_t *fin;
2389 {
2390         register struct in_addr src;
2391         register struct in_addr in;
2392         register ipnat_t *np;
2393         u_int nflags = 0, natadd = 1, hv, msk;
2394         struct ifnet *ifp = fin->fin_ifp;
2395         tcphdr_t *tcp = NULL;
2396         u_short sport = 0, dport = 0, *csump = NULL;
2397         nat_t *nat;
2398         u_32_t iph;
2399         int i;
2400
2401         if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock))
2402                 return 0;
2403
2404         if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
2405                 if (ip->ip_p == IPPROTO_TCP)
2406                         nflags = IPN_TCP;
2407                 else if (ip->ip_p == IPPROTO_UDP)
2408                         nflags = IPN_UDP;
2409                 if ((nflags & IPN_TCPUDP)) {
2410                         tcp = (tcphdr_t *)fin->fin_dp;
2411                         dport = tcp->th_dport;
2412                         sport = tcp->th_sport;
2413                 }
2414         }
2415
2416         in = ip->ip_dst;
2417         /* make sure the source address is to be redirected */
2418         src = ip->ip_src;
2419
2420         READ_ENTER(&ipf_nat);
2421
2422         if ((ip->ip_p == IPPROTO_ICMP) &&
2423             (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND)))
2424                 ;
2425         else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) &&
2426                  (nat = ipfr_nat_knownfrag(ip, fin)))
2427                 natadd = 0;
2428         else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p,
2429                                      ip->ip_src, in, (dport << 16) | sport,
2430                                      0))) {
2431                 nflags = nat->nat_flags;
2432                 if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {
2433                         if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT))
2434                                 nat->nat_oport = sport;
2435                         else if ((nat->nat_outport != dport) &&
2436                                  (nflags & FI_W_SPORT))
2437                                 nat->nat_outport = dport;
2438                         nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT);
2439                         nflags = nat->nat_flags;
2440                         nat_stats.ns_wilds--;
2441                 }
2442         } else {
2443                 RWLOCK_EXIT(&ipf_nat);
2444                 WRITE_ENTER(&ipf_nat);
2445                 /*
2446                  * If there is no current entry in the nat table for this IP#,
2447                  * create one for it (if there is a matching rule).
2448                  */
2449                 msk = 0xffffffff;
2450                 i = 32;
2451 maskloop:
2452                 iph = in.s_addr & htonl(msk);
2453                 hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz);
2454                 for (np = rdr_rules[hv]; np; np = np->in_rnext) {
2455                         if ((np->in_ifp && (np->in_ifp != ifp)) ||
2456                             (np->in_p && (np->in_p != ip->ip_p)) ||
2457                             (np->in_flags && !(nflags & np->in_flags)))
2458                                 continue;
2459                         if (np->in_flags & IPN_FILTER) {
2460                                 if (!nat_match(fin, np, ip))
2461                                         continue;
2462                         } else if ((in.s_addr & np->in_outmsk) != np->in_outip)
2463                                 continue;
2464                         if ((np->in_redir & NAT_REDIRECT) &&
2465                             (!np->in_pmin || (np->in_flags & IPN_FILTER) ||
2466                              ((ntohs(np->in_pmax) >= ntohs(dport)) &&
2467                               (ntohs(dport) >= ntohs(np->in_pmin)))))
2468                                 if ((nat = nat_new(np, ip, fin, nflags,
2469                                                     NAT_INBOUND))) {
2470                                         np->in_hits++;
2471                                         break;
2472                                 }
2473                 }
2474
2475                 if ((np == NULL) && (i > 0)) {
2476                         do {
2477                                 i--;
2478                                 msk <<= 1;
2479                         } while ((i >= 0) && ((rdr_masks & (1 << i)) == 0));
2480                         if (i >= 0)
2481                                 goto maskloop;
2482                 }
2483                 MUTEX_DOWNGRADE(&ipf_nat);
2484         }
2485
2486         /*
2487          * NOTE: ipf_nat must now only be held as a read lock
2488          */
2489         if (nat) {
2490                 np = nat->nat_ptr;
2491                 fin->fin_fr = nat->nat_fr;
2492                 if (natadd && (fin->fin_fi.fi_fl & FI_FRAG) &&
2493                     np && (np->in_flags & IPN_FRAG))
2494                         ipfr_nat_newfrag(ip, fin, 0, nat);
2495                 if ((np->in_apr != NULL) && (np->in_dport == 0 ||
2496                     (tcp != NULL && sport == np->in_dport))) {
2497                         i = appr_check(ip, fin, nat);
2498                         if (i == -1) {
2499                                 RWLOCK_EXIT(&ipf_nat);
2500                                 return i;
2501                         }
2502                 }
2503
2504                 MUTEX_ENTER(&nat->nat_lock);
2505                 if (nflags != IPN_ICMPERR)
2506                         nat->nat_age = fr_defnatage;
2507
2508                 nat->nat_bytes += ip->ip_len;
2509                 nat->nat_pkts++;
2510                 MUTEX_EXIT(&nat->nat_lock);
2511                 ip->ip_dst = nat->nat_inip;
2512                 fin->fin_fi.fi_daddr = nat->nat_inip.s_addr;
2513
2514                 /*
2515                  * Fix up checksums, not by recalculating them, but
2516                  * simply computing adjustments.
2517                  */
2518 #if SOLARIS || defined(__sgi)
2519                 if (nat->nat_dir == NAT_OUTBOUND)
2520                         fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
2521                 else
2522                         fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
2523 #endif
2524                 if (!(ip->ip_off & IP_OFFMASK) &&
2525                     !(fin->fin_fi.fi_fl & FI_SHORT)) {
2526
2527                         if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
2528                                 tcp->th_dport = nat->nat_inport;
2529                                 fin->fin_data[1] = ntohs(tcp->th_dport);
2530                         }
2531
2532                         if (ip->ip_p == IPPROTO_TCP) {
2533                                 csump = &tcp->th_sum;
2534                                 MUTEX_ENTER(&nat->nat_lock);
2535                                 fr_tcp_age(&nat->nat_age,
2536                                            nat->nat_tcpstate, fin, 0);
2537                                 if (nat->nat_age < fr_defnaticmpage)
2538                                         nat->nat_age = fr_defnaticmpage;
2539 #ifdef LARGE_NAT
2540                                 else if (nat->nat_age > fr_defnatage)
2541                                         nat->nat_age = fr_defnatage;
2542 #endif
2543                                 /*
2544                                  * Increase this because we may have
2545                                  * "keep state" following this too and
2546                                  * packet storms can occur if this is
2547                                  * removed too quickly.
2548                                  */
2549                                 if (nat->nat_age == fr_tcpclosed)
2550                                         nat->nat_age = fr_tcplastack;
2551                                 MUTEX_EXIT(&nat->nat_lock);
2552                         } else if (ip->ip_p == IPPROTO_UDP) {
2553                                 udphdr_t *udp = (udphdr_t *)tcp;
2554
2555                                 if (udp->uh_sum)
2556                                         csump = &udp->uh_sum;
2557                         } else if (ip->ip_p == IPPROTO_ICMP) {
2558                                 nat->nat_age = fr_defnaticmpage;
2559                         }
2560
2561                         if (csump) {
2562                                 if (nat->nat_dir == NAT_OUTBOUND)
2563                                         fix_incksum(csump, nat->nat_sumd[0]);
2564                                 else
2565                                         fix_outcksum(csump, nat->nat_sumd[0]);
2566                         }
2567                 }
2568                 ATOMIC_INCL(nat_stats.ns_mapped[0]);
2569                 RWLOCK_EXIT(&ipf_nat);                  /* READ */
2570                 return 1;
2571         }
2572         RWLOCK_EXIT(&ipf_nat);                  /* READ/WRITE */
2573         return 0;
2574 }
2575
2576
2577 /*
2578  * Free all memory used by NAT structures allocated at runtime.
2579  */
2580 void ip_natunload()
2581 {
2582         WRITE_ENTER(&ipf_nat);
2583         (void) nat_clearlist();
2584         (void) nat_flushtable();
2585         RWLOCK_EXIT(&ipf_nat);
2586
2587         if (nat_table[0] != NULL) {
2588                 KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz);
2589                 nat_table[0] = NULL;
2590         }
2591         if (nat_table[1] != NULL) {
2592                 KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz);
2593                 nat_table[1] = NULL;
2594         }
2595         if (nat_rules != NULL) {
2596                 KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz);
2597                 nat_rules = NULL;
2598         }
2599         if (rdr_rules != NULL) {
2600                 KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz);
2601                 rdr_rules = NULL;
2602         }
2603         if (maptable != NULL) {
2604                 KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
2605                 maptable = NULL;
2606         }
2607 }
2608
2609
2610 /*
2611  * Slowly expire held state for NAT entries.  Timeouts are set in
2612  * expectation of this being called twice per second.
2613  */
2614 void ip_natexpire()
2615 {
2616         register struct nat *nat, **natp;
2617 #if defined(_KERNEL) && !SOLARIS
2618         int s;
2619 #endif
2620
2621         SPL_NET(s);
2622         WRITE_ENTER(&ipf_nat);
2623         for (natp = &nat_instances; (nat = *natp); ) {
2624                 nat->nat_age--;
2625                 if (nat->nat_age) {
2626                         natp = &nat->nat_next;
2627                         continue;
2628                 }
2629                 *natp = nat->nat_next;
2630 #ifdef  IPFILTER_LOG
2631                 nat_log(nat, NL_EXPIRE);
2632 #endif
2633                 nat_delete(nat);
2634                 nat_stats.ns_expire++;
2635         }
2636         RWLOCK_EXIT(&ipf_nat);
2637         SPL_X(s);
2638 }
2639
2640
2641 /*
2642  */
2643 void ip_natsync(ifp)
2644 void *ifp;
2645 {
2646         register ipnat_t *n;
2647         register nat_t *nat;
2648         register u_32_t sum1, sum2, sumd;
2649         struct in_addr in;
2650         ipnat_t *np;
2651         void *ifp2;
2652 #if defined(_KERNEL) && !SOLARIS
2653         int s;
2654 #endif
2655
2656         /*
2657          * Change IP addresses for NAT sessions for any protocol except TCP
2658          * since it will break the TCP connection anyway.
2659          */
2660         SPL_NET(s);
2661         WRITE_ENTER(&ipf_nat);
2662         for (nat = nat_instances; nat; nat = nat->nat_next)
2663                 if (((ifp == NULL) || (ifp == nat->nat_ifp)) &&
2664                     !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) &&
2665                     (np->in_outmsk == 0xffffffff) && !np->in_nip) {
2666                         ifp2 = nat->nat_ifp;
2667                         /*
2668                          * Change the map-to address to be the same as the
2669                          * new one.
2670                          */
2671                         sum1 = nat->nat_outip.s_addr;
2672                         if (fr_ifpaddr(4, ifp2, &in) != -1)
2673                                 nat->nat_outip = in;
2674                         sum2 = nat->nat_outip.s_addr;
2675
2676                         if (sum1 == sum2)
2677                                 continue;
2678                         /*
2679                          * Readjust the checksum adjustment to take into
2680                          * account the new IP#.
2681                          */
2682                         CALC_SUMD(sum1, sum2, sumd);
2683                         /* XXX - dont change for TCP when solaris does
2684                          * hardware checksumming.
2685                          */
2686                         sumd += nat->nat_sumd[0];
2687                         nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
2688                         nat->nat_sumd[1] = nat->nat_sumd[0];
2689                 }
2690
2691         for (n = nat_list; (n != NULL); n = n->in_next)
2692                 if (n->in_ifp == ifp) {
2693                         n->in_ifp = (void *)GETUNIT(n->in_ifname, 4);
2694                         if (!n->in_ifp)
2695                                 n->in_ifp = (void *)-1;
2696                 }
2697         RWLOCK_EXIT(&ipf_nat);
2698         SPL_X(s);
2699 }
2700
2701
2702 #ifdef  IPFILTER_LOG
2703 void nat_log(nat, type)
2704 struct nat *nat;
2705 u_int type;
2706 {
2707         struct ipnat *np;
2708         struct natlog natl;
2709         void *items[1];
2710         size_t sizes[1];
2711         int rulen, types[1];
2712
2713         natl.nl_inip = nat->nat_inip;
2714         natl.nl_outip = nat->nat_outip;
2715         natl.nl_origip = nat->nat_oip;
2716         natl.nl_bytes = nat->nat_bytes;
2717         natl.nl_pkts = nat->nat_pkts;
2718         natl.nl_origport = nat->nat_oport;
2719         natl.nl_inport = nat->nat_inport;
2720         natl.nl_outport = nat->nat_outport;
2721         natl.nl_p = nat->nat_p;
2722         natl.nl_type = type;
2723         natl.nl_rule = -1;
2724 #ifndef LARGE_NAT
2725         if (nat->nat_ptr != NULL) {
2726                 for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++)
2727                         if (np == nat->nat_ptr) {
2728                                 natl.nl_rule = rulen;
2729                                 break;
2730                         }
2731         }
2732 #endif
2733         items[0] = &natl;
2734         sizes[0] = sizeof(natl);
2735         types[0] = 0;
2736
2737         (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1);
2738 }
2739 #endif