]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/contrib/ipfilter/netinet/ip_nat.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / contrib / ipfilter / netinet / ip_nat.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL  1
12 # define        _KERNEL 1
13 #endif
14 #include <sys/errno.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/time.h>
18 #include <sys/file.h>
19 #if defined(_KERNEL) && \
20     (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000))
21 # include <sys/kauth.h>
22 #endif
23 #if !defined(_KERNEL)
24 # include <stdio.h>
25 # include <string.h>
26 # include <stdlib.h>
27 # define KERNEL
28 # ifdef _OpenBSD__
29 struct file;
30 # endif
31 # include <sys/uio.h>
32 # undef KERNEL
33 #endif
34 #if defined(_KERNEL) && \
35     defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
36 # include <sys/filio.h>
37 # include <sys/fcntl.h>
38 #else
39 # include <sys/ioctl.h>
40 #endif
41 #if !defined(AIX)
42 # include <sys/fcntl.h>
43 #endif
44 #if !defined(linux)
45 # include <sys/protosw.h>
46 #endif
47 #include <sys/socket.h>
48 #if defined(_KERNEL)
49 # include <sys/systm.h>
50 # if !defined(__SVR4) && !defined(__svr4__)
51 #  include <sys/mbuf.h>
52 # endif
53 #endif
54 #if defined(__SVR4) || defined(__svr4__)
55 # include <sys/filio.h>
56 # include <sys/byteorder.h>
57 # ifdef KERNEL
58 #  include <sys/dditypes.h>
59 # endif
60 # include <sys/stream.h>
61 # include <sys/kmem.h>
62 #endif
63 #if __FreeBSD_version >= 300000
64 # include <sys/queue.h>
65 #endif
66 #include <net/if.h>
67 #if __FreeBSD_version >= 300000
68 # include <net/if_var.h>
69 #endif
70 #ifdef sun
71 # include <net/af.h>
72 #endif
73 #include <netinet/in.h>
74 #include <netinet/in_systm.h>
75 #include <netinet/ip.h>
76
77 #ifdef RFC1825
78 # include <vpn/md5.h>
79 # include <vpn/ipsec.h>
80 extern struct ifnet vpnif;
81 #endif
82
83 #if !defined(linux)
84 # include <netinet/ip_var.h>
85 #endif
86 #include <netinet/tcp.h>
87 #include <netinet/udp.h>
88 #include <netinet/ip_icmp.h>
89 #include "netinet/ip_compat.h"
90 #include <netinet/tcpip.h>
91 #include "netinet/ipl.h"
92 #include "netinet/ip_fil.h"
93 #include "netinet/ip_nat.h"
94 #include "netinet/ip_frag.h"
95 #include "netinet/ip_state.h"
96 #include "netinet/ip_proxy.h"
97 #include "netinet/ip_lookup.h"
98 #include "netinet/ip_dstlist.h"
99 #include "netinet/ip_sync.h"
100 #if FREEBSD_GE_REV(300000)
101 # include <sys/malloc.h>
102 #endif
103 #ifdef HAS_SYS_MD5_H
104 # include <sys/md5.h>
105 #else
106 # include "md5.h"
107 #endif
108 /* END OF INCLUDES */
109
110 #undef  SOCKADDR_IN
111 #define SOCKADDR_IN     struct sockaddr_in
112
113 #if !defined(lint)
114 static const char sccsid[] = "@(#)ip_nat.c      1.11 6/5/96 (C) 1995 Darren Reed";
115 static const char rcsid[] = "@(#)$FreeBSD$";
116 /* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.102 2007/10/16 10:08:10 darrenr Exp $"; */
117 #endif
118
119
120 #define NATFSUM(n,v,f)  ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \
121                          (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3])
122 #define NBUMP(x)        softn->(x)++
123 #define NBUMPD(x, y)    do { \
124                                 softn->x.y++; \
125                                 DT(y); \
126                         } while (0)
127 #define NBUMPSIDE(y,x)  softn->ipf_nat_stats.ns_side[y].x++
128 #define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \
129                              DT(x); } while (0)
130 #define NBUMPSIDEX(y,x,z) \
131                         do { softn->ipf_nat_stats.ns_side[y].x++; \
132                              DT(z); } while (0)
133 #define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \
134                              DT1(x, fr_info_t *, fin); } while (0)
135
136 frentry_t       ipfnatblock;
137
138 static ipftuneable_t ipf_nat_tuneables[] = {
139         /* nat */
140         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) },
141                 "nat_lock",     0,      1,
142                 stsizeof(ipf_nat_softc_t, ipf_nat_lock),
143                 IPFT_RDONLY,            NULL,   NULL },
144         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) },
145                 "nat_table_size", 1,    0x7fffffff,
146                 stsizeof(ipf_nat_softc_t, ipf_nat_table_sz),
147                 0,                      NULL,   ipf_nat_rehash },
148         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) },
149                 "nat_table_max", 1,     0x7fffffff,
150                 stsizeof(ipf_nat_softc_t, ipf_nat_table_max),
151                 0,                      NULL,   NULL },
152         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) },
153                 "nat_rules_size", 1,    0x7fffffff,
154                 stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz),
155                 0,                      NULL,   ipf_nat_rehash_rules },
156         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) },
157                 "rdr_rules_size", 1,    0x7fffffff,
158                 stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz),
159                 0,                      NULL,   ipf_nat_rehash_rules },
160         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) },
161                 "hostmap_size", 1,      0x7fffffff,
162                 stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz),
163                 0,                      NULL,   ipf_nat_hostmap_rehash },
164         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) },
165                 "nat_maxbucket",1,      0x7fffffff,
166                 stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket),
167                 0,                      NULL,   NULL },
168         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) },
169                 "nat_logging",  0,      1,
170                 stsizeof(ipf_nat_softc_t, ipf_nat_logging),
171                 0,                      NULL,   NULL },
172         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) },
173                 "nat_doflush",  0,      1,
174                 stsizeof(ipf_nat_softc_t, ipf_nat_doflush),
175                 0,                      NULL,   NULL },
176         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) },
177                 "nat_table_wm_low",     1,      99,
178                 stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low),
179                 0,                      NULL,   NULL },
180         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) },
181                 "nat_table_wm_high",    2,      100,
182                 stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high),
183                 0,                      NULL,   NULL },
184         { { 0 },
185                 NULL,                   0,      0,
186                 0,
187                 0,                      NULL,   NULL }
188 };
189
190 /* ======================================================================== */
191 /* How the NAT is organised and works.                                      */
192 /*                                                                          */
193 /* Inside (interface y) NAT       Outside (interface x)                     */
194 /* -------------------- -+- -------------------------------------           */
195 /* Packet going          |   out, processsed by ipf_nat_checkout() for x    */
196 /* ------------>         |   ------------>                                  */
197 /* src=10.1.1.1          |   src=192.1.1.1                                  */
198 /*                       |                                                  */
199 /*                       |   in, processed by ipf_nat_checkin() for x       */
200 /* <------------         |   <------------                                  */
201 /* dst=10.1.1.1          |   dst=192.1.1.1                                  */
202 /* -------------------- -+- -------------------------------------           */
203 /* ipf_nat_checkout() - changes ip_src and if required, sport               */
204 /*             - creates a new mapping, if required.                        */
205 /* ipf_nat_checkin()  - changes ip_dst and if required, dport               */
206 /*                                                                          */
207 /* In the NAT table, internal source is recorded as "in" and externally     */
208 /* seen as "out".                                                           */
209 /* ======================================================================== */
210
211
212 #if SOLARIS && !defined(INSTANCES)
213 extern  int             pfil_delayed_copy;
214 #endif
215
216 static  int     ipf_nat_flush_entry __P((ipf_main_softc_t *, void *));
217 static  int     ipf_nat_getent __P((ipf_main_softc_t *, caddr_t, int));
218 static  int     ipf_nat_getsz __P((ipf_main_softc_t *, caddr_t, int));
219 static  int     ipf_nat_putent __P((ipf_main_softc_t *, caddr_t, int));
220 static  void    ipf_nat_addmap __P((ipf_nat_softc_t *, ipnat_t *));
221 static  void    ipf_nat_addrdr __P((ipf_nat_softc_t *, ipnat_t *));
222 static  int     ipf_nat_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *));
223 static  int     ipf_nat_clearlist __P((ipf_main_softc_t *, ipf_nat_softc_t *));
224 static  int     ipf_nat_cmp_rules __P((ipnat_t *, ipnat_t *));
225 static  int     ipf_nat_decap __P((fr_info_t *, nat_t *));
226 static  void    ipf_nat_delrule __P((ipf_main_softc_t *, ipf_nat_softc_t *,
227                                      ipnat_t *, int));
228 static  int     ipf_nat_extraflush __P((ipf_main_softc_t *, ipf_nat_softc_t *, int));
229 static  int     ipf_nat_finalise __P((fr_info_t *, nat_t *));
230 static  int     ipf_nat_flushtable __P((ipf_main_softc_t *, ipf_nat_softc_t *));
231 static  int     ipf_nat_getnext __P((ipf_main_softc_t *, ipftoken_t *,
232                                      ipfgeniter_t *, ipfobj_t *));
233 static  int     ipf_nat_gettable __P((ipf_main_softc_t *, ipf_nat_softc_t *,
234                                       char *));
235 static  hostmap_t *ipf_nat_hostmap __P((ipf_nat_softc_t *, ipnat_t *,
236                                         struct in_addr, struct in_addr,
237                                         struct in_addr, u_32_t));
238 static  int     ipf_nat_icmpquerytype __P((int));
239 static  int     ipf_nat_iterator __P((ipf_main_softc_t *, ipftoken_t *,
240                                       ipfgeniter_t *, ipfobj_t *));
241 static  int     ipf_nat_match __P((fr_info_t *, ipnat_t *));
242 static  int     ipf_nat_matcharray __P((nat_t *, int *, u_long));
243 static  int     ipf_nat_matchflush __P((ipf_main_softc_t *, ipf_nat_softc_t *,
244                                         caddr_t));
245 static  void    ipf_nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *,
246                                       u_short *));
247 static  int     ipf_nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
248 static  int     ipf_nat_newdivert __P((fr_info_t *, nat_t *, natinfo_t *));
249 static  int     ipf_nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
250 static  int     ipf_nat_newrewrite __P((fr_info_t *, nat_t *, natinfo_t *));
251 static  int     ipf_nat_nextaddr __P((fr_info_t *, nat_addr_t *, u_32_t *,
252                                       u_32_t *));
253 static  int     ipf_nat_nextaddrinit __P((ipf_main_softc_t *, char *,
254                                           nat_addr_t *, int, void *));
255 static  int     ipf_nat_resolverule __P((ipf_main_softc_t *, ipnat_t *));
256 static  int     ipf_nat_ruleaddrinit __P((ipf_main_softc_t *,
257                                           ipf_nat_softc_t *, ipnat_t *));
258 static  void    ipf_nat_rule_fini __P((ipf_main_softc_t *, ipnat_t *));
259 static  int     ipf_nat_rule_init __P((ipf_main_softc_t *, ipf_nat_softc_t *,
260                                        ipnat_t *));
261 static  int     ipf_nat_siocaddnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
262                                         ipnat_t *, int));
263 static  void    ipf_nat_siocdelnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
264                                         ipnat_t *, int));
265 static  void    ipf_nat_tabmove __P((ipf_nat_softc_t *, nat_t *));
266
267 /* ------------------------------------------------------------------------ */
268 /* Function:    ipf_nat_main_load                                           */
269 /* Returns:     int - 0 == success, -1 == failure                           */
270 /* Parameters:  Nil                                                         */
271 /*                                                                          */
272 /* The only global NAT structure that needs to be initialised is the filter */
273 /* rule that is used with blocking packets.                                 */
274 /* ------------------------------------------------------------------------ */
275 int
276 ipf_nat_main_load()
277 {
278         bzero((char *)&ipfnatblock, sizeof(ipfnatblock));
279         ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK;
280         ipfnatblock.fr_ref = 1;
281
282         return 0;
283 }
284
285
286 /* ------------------------------------------------------------------------ */
287 /* Function:    ipf_nat_main_unload                                         */
288 /* Returns:     int - 0 == success, -1 == failure                           */
289 /* Parameters:  Nil                                                         */
290 /*                                                                          */
291 /* A null-op function that exists as a placeholder so that the flow in      */
292 /* other functions is obvious.                                              */
293 /* ------------------------------------------------------------------------ */
294 int
295 ipf_nat_main_unload()
296 {
297         return 0;
298 }
299
300
301 /* ------------------------------------------------------------------------ */
302 /* Function:    ipf_nat_soft_create                                         */
303 /* Returns:     void * - NULL = failure, else pointer to NAT context        */
304 /* Parameters:  softc(I) - pointer to soft context main structure           */
305 /*                                                                          */
306 /* Allocate the initial soft context structure for NAT and populate it with */
307 /* some default values. Creating the tables is left until we call _init so  */
308 /* that sizes can be changed before we get under way.                       */
309 /* ------------------------------------------------------------------------ */
310 void *
311 ipf_nat_soft_create(softc)
312         ipf_main_softc_t *softc;
313 {
314         ipf_nat_softc_t *softn;
315
316         KMALLOC(softn, ipf_nat_softc_t *);
317         if (softn == NULL)
318                 return NULL;
319
320         bzero((char *)softn, sizeof(*softn));
321
322         softn->ipf_nat_tune = ipf_tune_array_copy(softn,
323                                                   sizeof(ipf_nat_tuneables),
324                                                   ipf_nat_tuneables);
325         if (softn->ipf_nat_tune == NULL) {
326                 ipf_nat_soft_destroy(softc, softn);
327                 return NULL;
328         }
329         if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) {
330                 ipf_nat_soft_destroy(softc, softn);
331                 return NULL;
332         }
333
334         softn->ipf_nat_list_tail = &softn->ipf_nat_list;
335
336         softn->ipf_nat_table_max = NAT_TABLE_MAX;
337         softn->ipf_nat_table_sz = NAT_TABLE_SZ;
338         softn->ipf_nat_maprules_sz = NAT_SIZE;
339         softn->ipf_nat_rdrrules_sz = RDR_SIZE;
340         softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE;
341         softn->ipf_nat_doflush = 0;
342 #ifdef  IPFILTER_LOG
343         softn->ipf_nat_logging = 1;
344 #else
345         softn->ipf_nat_logging = 0;
346 #endif
347
348         softn->ipf_nat_defage = DEF_NAT_AGE;
349         softn->ipf_nat_defipage = IPF_TTLVAL(60);
350         softn->ipf_nat_deficmpage = IPF_TTLVAL(3);
351         softn->ipf_nat_table_wm_high = 99;
352         softn->ipf_nat_table_wm_low = 90;
353
354         return softn;
355 }
356
357 /* ------------------------------------------------------------------------ */
358 /* Function:    ipf_nat_soft_destroy                                        */
359 /* Returns:     Nil                                                         */
360 /* Parameters:  softc(I) - pointer to soft context main structure           */
361 /*                                                                          */
362 /* ------------------------------------------------------------------------ */
363 void
364 ipf_nat_soft_destroy(softc, arg)
365         ipf_main_softc_t *softc;
366         void *arg;
367 {
368         ipf_nat_softc_t *softn = arg;
369
370         if (softn->ipf_nat_tune != NULL) {
371                 ipf_tune_array_unlink(softc, softn->ipf_nat_tune);
372                 KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables));
373                 softn->ipf_nat_tune = NULL;
374         }
375
376         KFREE(softn);
377 }
378
379
380 /* ------------------------------------------------------------------------ */
381 /* Function:    ipf_nat_init                                                */
382 /* Returns:     int - 0 == success, -1 == failure                           */
383 /* Parameters:  softc(I) - pointer to soft context main structure           */
384 /*                                                                          */
385 /* Initialise all of the NAT locks, tables and other structures.            */
386 /* ------------------------------------------------------------------------ */
387 int
388 ipf_nat_soft_init(softc, arg)
389         ipf_main_softc_t *softc;
390         void *arg;
391 {
392         ipf_nat_softc_t *softn = arg;
393         ipftq_t *tq;
394         int i;
395
396         KMALLOCS(softn->ipf_nat_table[0], nat_t **, \
397                  sizeof(nat_t *) * softn->ipf_nat_table_sz);
398
399         if (softn->ipf_nat_table[0] != NULL) {
400                 bzero((char *)softn->ipf_nat_table[0],
401                       softn->ipf_nat_table_sz * sizeof(nat_t *));
402         } else {
403                 return -1;
404         }
405
406         KMALLOCS(softn->ipf_nat_table[1], nat_t **, \
407                  sizeof(nat_t *) * softn->ipf_nat_table_sz);
408
409         if (softn->ipf_nat_table[1] != NULL) {
410                 bzero((char *)softn->ipf_nat_table[1],
411                       softn->ipf_nat_table_sz * sizeof(nat_t *));
412         } else {
413                 return -2;
414         }
415
416         KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \
417                  sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
418
419         if (softn->ipf_nat_map_rules != NULL) {
420                 bzero((char *)softn->ipf_nat_map_rules,
421                       softn->ipf_nat_maprules_sz * sizeof(ipnat_t *));
422         } else {
423                 return -3;
424         }
425
426         KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \
427                  sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
428
429         if (softn->ipf_nat_rdr_rules != NULL) {
430                 bzero((char *)softn->ipf_nat_rdr_rules,
431                       softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *));
432         } else {
433                 return -4;
434         }
435
436         KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \
437                  sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
438
439         if (softn->ipf_hm_maptable != NULL) {
440                 bzero((char *)softn->ipf_hm_maptable,
441                       sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
442         } else {
443                 return -5;
444         }
445         softn->ipf_hm_maplist = NULL;
446
447         KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *,
448                  softn->ipf_nat_table_sz * sizeof(u_int));
449
450         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) {
451                 return -6;
452         }
453         bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
454               softn->ipf_nat_table_sz * sizeof(u_int));
455
456         KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *,
457                  softn->ipf_nat_table_sz * sizeof(u_int));
458
459         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) {
460                 return -7;
461         }
462
463         bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
464               softn->ipf_nat_table_sz * sizeof(u_int));
465
466         if (softn->ipf_nat_maxbucket == 0) {
467                 for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1)
468                         softn->ipf_nat_maxbucket++;
469                 softn->ipf_nat_maxbucket *= 2;
470         }
471
472         ipf_sttab_init(softc, softn->ipf_nat_tcptq);
473         /*
474          * Increase this because we may have "keep state" following this too
475          * and packet storms can occur if this is removed too quickly.
476          */
477         softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
478         softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next =
479                                                         &softn->ipf_nat_udptq;
480
481         IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage,
482                    "nat ipftq udp tab");
483         softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq;
484
485         IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage,
486                    "nat ipftq udpack tab");
487         softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq;
488
489         IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage,
490                    "nat icmp ipftq tab");
491         softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq;
492
493         IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage,
494                    "nat icmpack ipftq tab");
495         softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq;
496
497         IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage,
498                    "nat ip ipftq tab");
499         softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending;
500
501         IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab");
502         softn->ipf_nat_pending.ifq_next = NULL;
503
504         for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) {
505                 if (tq->ifq_ttl < softn->ipf_nat_deficmpage)
506                         tq->ifq_ttl = softn->ipf_nat_deficmpage;
507 #ifdef LARGE_NAT
508                 else if (tq->ifq_ttl > softn->ipf_nat_defage)
509                         tq->ifq_ttl = softn->ipf_nat_defage;
510 #endif
511         }
512
513         /*
514          * Increase this because we may have "keep state" following
515          * this too and packet storms can occur if this is removed
516          * too quickly.
517          */
518         softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
519
520         MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex");
521         MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex");
522
523         softn->ipf_nat_inited = 1;
524
525         return 0;
526 }
527
528
529 /* ------------------------------------------------------------------------ */
530 /* Function:    ipf_nat_soft_fini                                           */
531 /* Returns:     Nil                                                         */
532 /* Parameters:  softc(I) - pointer to soft context main structure           */
533 /*                                                                          */
534 /* Free all memory used by NAT structures allocated at runtime.             */
535 /* ------------------------------------------------------------------------ */
536 int
537 ipf_nat_soft_fini(softc, arg)
538         ipf_main_softc_t *softc;
539         void *arg;
540 {
541         ipf_nat_softc_t *softn = arg;
542         ipftq_t *ifq, *ifqnext;
543
544         (void) ipf_nat_clearlist(softc, softn);
545         (void) ipf_nat_flushtable(softc, softn);
546
547         /*
548          * Proxy timeout queues are not cleaned here because although they
549          * exist on the NAT list, ipf_proxy_unload is called after unload
550          * and the proxies actually are responsible for them being created.
551          * Should the proxy timeouts have their own list?  There's no real
552          * justification as this is the only complication.
553          */
554         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
555                 ifqnext = ifq->ifq_next;
556                 if (ipf_deletetimeoutqueue(ifq) == 0)
557                         ipf_freetimeoutqueue(softc, ifq);
558         }
559
560         if (softn->ipf_nat_table[0] != NULL) {
561                 KFREES(softn->ipf_nat_table[0],
562                        sizeof(nat_t *) * softn->ipf_nat_table_sz);
563                 softn->ipf_nat_table[0] = NULL;
564         }
565         if (softn->ipf_nat_table[1] != NULL) {
566                 KFREES(softn->ipf_nat_table[1],
567                        sizeof(nat_t *) * softn->ipf_nat_table_sz);
568                 softn->ipf_nat_table[1] = NULL;
569         }
570         if (softn->ipf_nat_map_rules != NULL) {
571                 KFREES(softn->ipf_nat_map_rules,
572                        sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
573                 softn->ipf_nat_map_rules = NULL;
574         }
575         if (softn->ipf_nat_rdr_rules != NULL) {
576                 KFREES(softn->ipf_nat_rdr_rules,
577                        sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
578                 softn->ipf_nat_rdr_rules = NULL;
579         }
580         if (softn->ipf_hm_maptable != NULL) {
581                 KFREES(softn->ipf_hm_maptable,
582                        sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
583                 softn->ipf_hm_maptable = NULL;
584         }
585         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
586                 KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
587                        sizeof(u_int) * softn->ipf_nat_table_sz);
588                 softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL;
589         }
590         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
591                 KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
592                        sizeof(u_int) * softn->ipf_nat_table_sz);
593                 softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL;
594         }
595
596         if (softn->ipf_nat_inited == 1) {
597                 softn->ipf_nat_inited = 0;
598                 ipf_sttab_destroy(softn->ipf_nat_tcptq);
599
600                 MUTEX_DESTROY(&softn->ipf_nat_new);
601                 MUTEX_DESTROY(&softn->ipf_nat_io);
602
603                 MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock);
604                 MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock);
605                 MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock);
606                 MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock);
607                 MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock);
608                 MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock);
609         }
610
611         return 0;
612 }
613
614
615 /* ------------------------------------------------------------------------ */
616 /* Function:    ipf_nat_setlock                                             */
617 /* Returns:     Nil                                                         */
618 /* Parameters:  arg(I) - pointer to soft state information                  */
619 /*              tmp(I) - new lock value                                     */
620 /*                                                                          */
621 /* Set the "lock status" of NAT to the value in tmp.                        */
622 /* ------------------------------------------------------------------------ */
623 void
624 ipf_nat_setlock(arg, tmp)
625         void *arg;
626         int tmp;
627 {
628         ipf_nat_softc_t *softn = arg;
629
630         softn->ipf_nat_lock = tmp;
631 }
632
633
634 /* ------------------------------------------------------------------------ */
635 /* Function:    ipf_nat_addrdr                                              */
636 /* Returns:     Nil                                                         */
637 /* Parameters:  n(I) - pointer to NAT rule to add                           */
638 /*                                                                          */
639 /* Adds a redirect rule to the hash table of redirect rules and the list of */
640 /* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
641 /* use by redirect rules.                                                   */
642 /* ------------------------------------------------------------------------ */
643 static void
644 ipf_nat_addrdr(softn, n)
645         ipf_nat_softc_t *softn;
646         ipnat_t *n;
647 {
648         ipnat_t **np;
649         u_32_t j;
650         u_int hv;
651         u_int rhv;
652         int k;
653
654         if (n->in_odstatype == FRI_NORMAL) {
655                 k = count4bits(n->in_odstmsk);
656                 ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask);
657                 j = (n->in_odstaddr & n->in_odstmsk);
658                 rhv = NAT_HASH_FN(j, 0, 0xffffffff);
659         } else {
660                 ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask);
661                 j = 0;
662                 rhv = 0;
663         }
664         hv = rhv % softn->ipf_nat_rdrrules_sz;
665         np = softn->ipf_nat_rdr_rules + hv;
666         while (*np != NULL)
667                 np = &(*np)->in_rnext;
668         n->in_rnext = NULL;
669         n->in_prnext = np;
670         n->in_hv[0] = hv;
671         n->in_use++;
672         *np = n;
673 }
674
675
676 /* ------------------------------------------------------------------------ */
677 /* Function:    ipf_nat_addmap                                              */
678 /* Returns:     Nil                                                         */
679 /* Parameters:  n(I) - pointer to NAT rule to add                           */
680 /*                                                                          */
681 /* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
682 /* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
683 /* redirect rules.                                                          */
684 /* ------------------------------------------------------------------------ */
685 static void
686 ipf_nat_addmap(softn, n)
687         ipf_nat_softc_t *softn;
688         ipnat_t *n;
689 {
690         ipnat_t **np;
691         u_32_t j;
692         u_int hv;
693         u_int rhv;
694         int k;
695
696         if (n->in_osrcatype == FRI_NORMAL) {
697                 k = count4bits(n->in_osrcmsk);
698                 ipf_inet_mask_add(k, &softn->ipf_nat_map_mask);
699                 j = (n->in_osrcaddr & n->in_osrcmsk);
700                 rhv = NAT_HASH_FN(j, 0, 0xffffffff);
701         } else {
702                 ipf_inet_mask_add(0, &softn->ipf_nat_map_mask);
703                 j = 0;
704                 rhv = 0;
705         }
706         hv = rhv % softn->ipf_nat_maprules_sz;
707         np = softn->ipf_nat_map_rules + hv;
708         while (*np != NULL)
709                 np = &(*np)->in_mnext;
710         n->in_mnext = NULL;
711         n->in_pmnext = np;
712         n->in_hv[1] = rhv;
713         n->in_use++;
714         *np = n;
715 }
716
717
718 /* ------------------------------------------------------------------------ */
719 /* Function:    ipf_nat_delrdr                                              */
720 /* Returns:     Nil                                                         */
721 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
722 /*                                                                          */
723 /* Removes a redirect rule from the hash table of redirect rules.           */
724 /* ------------------------------------------------------------------------ */
725 void
726 ipf_nat_delrdr(softn, n)
727         ipf_nat_softc_t *softn;
728         ipnat_t *n;
729 {
730         if (n->in_odstatype == FRI_NORMAL) {
731                 int k = count4bits(n->in_odstmsk);
732                 ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask);
733         } else {
734                 ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask);
735         }
736         if (n->in_rnext)
737                 n->in_rnext->in_prnext = n->in_prnext;
738         *n->in_prnext = n->in_rnext;
739         n->in_use--;
740 }
741
742
743 /* ------------------------------------------------------------------------ */
744 /* Function:    ipf_nat_delmap                                              */
745 /* Returns:     Nil                                                         */
746 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
747 /*                                                                          */
748 /* Removes a NAT map rule from the hash table of NAT map rules.             */
749 /* ------------------------------------------------------------------------ */
750 void
751 ipf_nat_delmap(softn, n)
752         ipf_nat_softc_t *softn;
753         ipnat_t *n;
754 {
755         if (n->in_osrcatype == FRI_NORMAL) {
756                 int k = count4bits(n->in_osrcmsk);
757                 ipf_inet_mask_del(k, &softn->ipf_nat_map_mask);
758         } else {
759                 ipf_inet_mask_del(0, &softn->ipf_nat_map_mask);
760         }
761         if (n->in_mnext != NULL)
762                 n->in_mnext->in_pmnext = n->in_pmnext;
763         *n->in_pmnext = n->in_mnext;
764         n->in_use--;
765 }
766
767
768 /* ------------------------------------------------------------------------ */
769 /* Function:    ipf_nat_hostmap                                             */
770 /* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
771 /*                                else a pointer to the hostmapping to use  */
772 /* Parameters:  np(I)   - pointer to NAT rule                               */
773 /*              real(I) - real IP address                                   */
774 /*              map(I)  - mapped IP address                                 */
775 /*              port(I) - destination port number                           */
776 /* Write Locks: ipf_nat                                                     */
777 /*                                                                          */
778 /* Check if an ip address has already been allocated for a given mapping    */
779 /* that is not doing port based translation.  If is not yet allocated, then */
780 /* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
781 /* ------------------------------------------------------------------------ */
782 static struct hostmap *
783 ipf_nat_hostmap(softn, np, src, dst, map, port)
784         ipf_nat_softc_t *softn;
785         ipnat_t *np;
786         struct in_addr src;
787         struct in_addr dst;
788         struct in_addr map;
789         u_32_t port;
790 {
791         hostmap_t *hm;
792         u_int hv, rhv;
793
794         hv = (src.s_addr ^ dst.s_addr);
795         hv += src.s_addr;
796         hv += dst.s_addr;
797         rhv = hv;
798         hv %= softn->ipf_nat_hostmap_sz;
799         for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext)
800                 if ((hm->hm_osrcip.s_addr == src.s_addr) &&
801                     (hm->hm_odstip.s_addr == dst.s_addr) &&
802                     ((np == NULL) || (np == hm->hm_ipnat)) &&
803                     ((port == 0) || (port == hm->hm_port))) {
804                         softn->ipf_nat_stats.ns_hm_addref++;
805                         hm->hm_ref++;
806                         return hm;
807                 }
808
809         if (np == NULL) {
810                 softn->ipf_nat_stats.ns_hm_nullnp++;
811                 return NULL;
812         }
813
814         KMALLOC(hm, hostmap_t *);
815         if (hm) {
816                 hm->hm_next = softn->ipf_hm_maplist;
817                 hm->hm_pnext = &softn->ipf_hm_maplist;
818                 if (softn->ipf_hm_maplist != NULL)
819                         softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
820                 softn->ipf_hm_maplist = hm;
821                 hm->hm_hnext = softn->ipf_hm_maptable[hv];
822                 hm->hm_phnext = softn->ipf_hm_maptable + hv;
823                 if (softn->ipf_hm_maptable[hv] != NULL)
824                         softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
825                 softn->ipf_hm_maptable[hv] = hm;
826                 hm->hm_ipnat = np;
827                 np->in_use++;
828                 hm->hm_osrcip = src;
829                 hm->hm_odstip = dst;
830                 hm->hm_nsrcip = map;
831                 hm->hm_ndstip.s_addr = 0;
832                 hm->hm_ref = 1;
833                 hm->hm_port = port;
834                 hm->hm_hv = rhv;
835                 hm->hm_v = 4;
836                 softn->ipf_nat_stats.ns_hm_new++;
837         } else {
838                 softn->ipf_nat_stats.ns_hm_newfail++;
839         }
840         return hm;
841 }
842
843
844 /* ------------------------------------------------------------------------ */
845 /* Function:    ipf_nat_hostmapdel                                          */
846 /* Returns:     Nil                                                         */
847 /* Parameters:  hmp(I) - pointer to hostmap structure pointer               */
848 /* Write Locks: ipf_nat                                                     */
849 /*                                                                          */
850 /* Decrement the references to this hostmap structure by one.  If this      */
851 /* reaches zero then remove it and free it.                                 */
852 /* ------------------------------------------------------------------------ */
853 void
854 ipf_nat_hostmapdel(softc, hmp)
855         ipf_main_softc_t *softc;
856         struct hostmap **hmp;
857 {
858         struct hostmap *hm;
859
860         hm = *hmp;
861         *hmp = NULL;
862
863         hm->hm_ref--;
864         if (hm->hm_ref == 0) {
865                 ipf_nat_rule_deref(softc, &hm->hm_ipnat);
866                 if (hm->hm_hnext)
867                         hm->hm_hnext->hm_phnext = hm->hm_phnext;
868                 *hm->hm_phnext = hm->hm_hnext;
869                 if (hm->hm_next)
870                         hm->hm_next->hm_pnext = hm->hm_pnext;
871                 *hm->hm_pnext = hm->hm_next;
872                 KFREE(hm);
873         }
874 }
875
876
877 /* ------------------------------------------------------------------------ */
878 /* Function:    ipf_fix_outcksum                                            */
879 /* Returns:     Nil                                                         */
880 /* Parameters:  fin(I) - pointer to packet information                      */
881 /*              sp(I)  - location of 16bit checksum to update               */
882 /*              n((I)  - amount to adjust checksum by                       */
883 /*                                                                          */
884 /* Adjusts the 16bit checksum by "n" for packets going out.                 */
885 /* ------------------------------------------------------------------------ */
886 void
887 ipf_fix_outcksum(cksum, sp, n, partial)
888         int cksum;
889         u_short *sp;
890         u_32_t n, partial;
891 {
892         u_short sumshort;
893         u_32_t sum1;
894
895         if (n == 0)
896                 return;
897
898         if (cksum == 4) {
899                 *sp = 0;
900                 return;
901         }
902         if (cksum == 2) {
903                 sum1 = partial;
904                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
905                 *sp = htons(sum1);
906                 return;
907         }
908         sum1 = (~ntohs(*sp)) & 0xffff;
909         sum1 += (n);
910         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
911         /* Again */
912         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
913         sumshort = ~(u_short)sum1;
914         *(sp) = htons(sumshort);
915 }
916
917
918 /* ------------------------------------------------------------------------ */
919 /* Function:    ipf_fix_incksum                                             */
920 /* Returns:     Nil                                                         */
921 /* Parameters:  fin(I) - pointer to packet information                      */
922 /*              sp(I)  - location of 16bit checksum to update               */
923 /*              n((I)  - amount to adjust checksum by                       */
924 /*                                                                          */
925 /* Adjusts the 16bit checksum by "n" for packets going in.                  */
926 /* ------------------------------------------------------------------------ */
927 void
928 ipf_fix_incksum(cksum, sp, n, partial)
929         int cksum;
930         u_short *sp;
931         u_32_t n, partial;
932 {
933         u_short sumshort;
934         u_32_t sum1;
935
936         if (n == 0)
937                 return;
938
939         if (cksum == 4) {
940                 *sp = 0;
941                 return;
942         }
943         if (cksum == 2) {
944                 sum1 = partial;
945                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
946                 *sp = htons(sum1);
947                 return;
948         }
949
950         sum1 = (~ntohs(*sp)) & 0xffff;
951         sum1 += ~(n) & 0xffff;
952         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
953         /* Again */
954         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
955         sumshort = ~(u_short)sum1;
956         *(sp) = htons(sumshort);
957 }
958
959
960 /* ------------------------------------------------------------------------ */
961 /* Function:    ipf_fix_datacksum                                           */
962 /* Returns:     Nil                                                         */
963 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
964 /*              n((I)  - amount to adjust checksum by                       */
965 /*                                                                          */
966 /* Fix_datacksum is used *only* for the adjustments of checksums in the     */
967 /* data section of an IP packet.                                            */
968 /*                                                                          */
969 /* The only situation in which you need to do this is when NAT'ing an       */
970 /* ICMP error message. Such a message, contains in its body the IP header   */
971 /* of the original IP packet, that causes the error.                        */
972 /*                                                                          */
973 /* You can't use fix_incksum or fix_outcksum in that case, because for the  */
974 /* kernel the data section of the ICMP error is just data, and no special   */
975 /* processing like hardware cksum or ntohs processing have been done by the */
976 /* kernel on the data section.                                              */
977 /* ------------------------------------------------------------------------ */
978 void
979 ipf_fix_datacksum(sp, n)
980         u_short *sp;
981         u_32_t n;
982 {
983         u_short sumshort;
984         u_32_t sum1;
985
986         if (n == 0)
987                 return;
988
989         sum1 = (~ntohs(*sp)) & 0xffff;
990         sum1 += (n);
991         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
992         /* Again */
993         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
994         sumshort = ~(u_short)sum1;
995         *(sp) = htons(sumshort);
996 }
997
998
999 /* ------------------------------------------------------------------------ */
1000 /* Function:    ipf_nat_ioctl                                               */
1001 /* Returns:     int - 0 == success, != 0 == failure                         */
1002 /* Parameters:  softc(I) - pointer to soft context main structure           */
1003 /*              data(I)  - pointer to ioctl data                            */
1004 /*              cmd(I)   - ioctl command integer                            */
1005 /*              mode(I)  - file mode bits used with open                    */
1006 /*              uid(I)   - uid of calling process                           */
1007 /*              ctx(I)   - pointer used as key for finding context          */
1008 /*                                                                          */
1009 /* Processes an ioctl call made to operate on the IP Filter NAT device.     */
1010 /* ------------------------------------------------------------------------ */
1011 int
1012 ipf_nat_ioctl(softc, data, cmd, mode, uid, ctx)
1013         ipf_main_softc_t *softc;
1014         ioctlcmd_t cmd;
1015         caddr_t data;
1016         int mode, uid;
1017         void *ctx;
1018 {
1019         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1020         int error = 0, ret, arg, getlock;
1021         ipnat_t *nat, *nt, *n;
1022         ipnat_t natd;
1023         SPL_INT(s);
1024
1025 #if BSD_GE_YEAR(199306) && defined(_KERNEL)
1026 # if NETBSD_GE_REV(399002000)
1027         if ((mode & FWRITE) &&
1028              kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL,
1029                                      KAUTH_REQ_NETWORK_FIREWALL_FW,
1030                                      NULL, NULL, NULL))
1031 # else
1032 #  if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034)
1033         if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE))
1034 #  else
1035         if ((securelevel >= 3) && (mode & FWRITE))
1036 #  endif
1037 # endif
1038         {
1039                 IPFERROR(60001);
1040                 return EPERM;
1041         }
1042 #endif
1043
1044 #if defined(__osf__) && defined(_KERNEL)
1045         getlock = 0;
1046 #else
1047         getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
1048 #endif
1049
1050         n = NULL;
1051         nt = NULL;
1052         nat = NULL;
1053
1054         if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) ||
1055             (cmd == (ioctlcmd_t)SIOCPURGENAT)) {
1056                 if (mode & NAT_SYSSPACE) {
1057                         bcopy(data, (char *)&natd, sizeof(natd));
1058                         nat = &natd;
1059                         error = 0;
1060                 } else {
1061                         bzero(&natd, sizeof(natd));
1062                         error = ipf_inobj(softc, data, NULL, &natd,
1063                                           IPFOBJ_IPNAT);
1064                         if (error != 0)
1065                                 goto done;
1066
1067                         if (natd.in_size < sizeof(ipnat_t)) {
1068                                 error = EINVAL;
1069                                 goto done;
1070                         }
1071                         KMALLOCS(nt, ipnat_t *, natd.in_size);
1072                         if (nt == NULL) {
1073                                 IPFERROR(60070);
1074                                 error = ENOMEM;
1075                                 goto done;
1076                         }
1077                         bzero(nt, natd.in_size);
1078                         error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT,
1079                                             natd.in_size);
1080                         if (error)
1081                                 goto done;
1082                         nat = nt;
1083                 }
1084
1085                 /*
1086                  * For add/delete, look to see if the NAT entry is
1087                  * already present
1088                  */
1089                 nat->in_flags &= IPN_USERFLAGS;
1090                 if ((nat->in_redir & NAT_MAPBLK) == 0) {
1091                         if (nat->in_osrcatype == FRI_NORMAL ||
1092                             nat->in_osrcatype == FRI_NONE)
1093                                 nat->in_osrcaddr &= nat->in_osrcmsk;
1094                         if (nat->in_odstatype == FRI_NORMAL ||
1095                             nat->in_odstatype == FRI_NONE)
1096                                 nat->in_odstaddr &= nat->in_odstmsk;
1097                         if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) {
1098                                 if (nat->in_nsrcatype == FRI_NORMAL)
1099                                         nat->in_nsrcaddr &= nat->in_nsrcmsk;
1100                                 if (nat->in_ndstatype == FRI_NORMAL)
1101                                         nat->in_ndstaddr &= nat->in_ndstmsk;
1102                         }
1103                 }
1104
1105                 error = ipf_nat_rule_init(softc, softn, nat);
1106                 if (error != 0)
1107                         goto done;
1108
1109                 MUTEX_ENTER(&softn->ipf_nat_io);
1110                 for (n = softn->ipf_nat_list; n != NULL; n = n->in_next)
1111                         if (ipf_nat_cmp_rules(nat, n) == 0)
1112                                 break;
1113         }
1114
1115         switch (cmd)
1116         {
1117 #ifdef  IPFILTER_LOG
1118         case SIOCIPFFB :
1119         {
1120                 int tmp;
1121
1122                 if (!(mode & FWRITE)) {
1123                         IPFERROR(60002);
1124                         error = EPERM;
1125                 } else {
1126                         tmp = ipf_log_clear(softc, IPL_LOGNAT);
1127                         error = BCOPYOUT(&tmp, data, sizeof(tmp));
1128                         if (error != 0) {
1129                                 IPFERROR(60057);
1130                                 error = EFAULT;
1131                         }
1132                 }
1133                 break;
1134         }
1135
1136         case SIOCSETLG :
1137                 if (!(mode & FWRITE)) {
1138                         IPFERROR(60003);
1139                         error = EPERM;
1140                 } else {
1141                         error = BCOPYIN(data, &softn->ipf_nat_logging,
1142                                         sizeof(softn->ipf_nat_logging));
1143                         if (error != 0)
1144                                 error = EFAULT;
1145                 }
1146                 break;
1147
1148         case SIOCGETLG :
1149                 error = BCOPYOUT(&softn->ipf_nat_logging, data,
1150                                  sizeof(softn->ipf_nat_logging));
1151                 if (error != 0) {
1152                         IPFERROR(60004);
1153                         error = EFAULT;
1154                 }
1155                 break;
1156
1157         case FIONREAD :
1158                 arg = ipf_log_bytesused(softc, IPL_LOGNAT);
1159                 error = BCOPYOUT(&arg, data, sizeof(arg));
1160                 if (error != 0) {
1161                         IPFERROR(60005);
1162                         error = EFAULT;
1163                 }
1164                 break;
1165 #endif
1166         case SIOCADNAT :
1167                 if (!(mode & FWRITE)) {
1168                         IPFERROR(60006);
1169                         error = EPERM;
1170                 } else if (n != NULL) {
1171                         natd.in_flineno = n->in_flineno;
1172                         (void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT);
1173                         IPFERROR(60007);
1174                         error = EEXIST;
1175                 } else if (nt == NULL) {
1176                         IPFERROR(60008);
1177                         error = ENOMEM;
1178                 }
1179                 if (error != 0) {
1180                         MUTEX_EXIT(&softn->ipf_nat_io);
1181                         break;
1182                 }
1183                 if (nat != nt)
1184                         bcopy((char *)nat, (char *)nt, sizeof(*n));
1185                 error = ipf_nat_siocaddnat(softc, softn, nt, getlock);
1186                 MUTEX_EXIT(&softn->ipf_nat_io);
1187                 if (error == 0) {
1188                         nat = NULL;
1189                         nt = NULL;
1190                 }
1191                 break;
1192
1193         case SIOCRMNAT :
1194         case SIOCPURGENAT :
1195                 if (!(mode & FWRITE)) {
1196                         IPFERROR(60009);
1197                         error = EPERM;
1198                         n = NULL;
1199                 } else if (n == NULL) {
1200                         IPFERROR(60010);
1201                         error = ESRCH;
1202                 }
1203
1204                 if (error != 0) {
1205                         MUTEX_EXIT(&softn->ipf_nat_io);
1206                         break;
1207                 }
1208                 if (cmd == (ioctlcmd_t)SIOCPURGENAT) {
1209                         error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT,
1210                                              n->in_size);
1211                         if (error) {
1212                                 MUTEX_EXIT(&softn->ipf_nat_io);
1213                                 goto done;
1214                         }
1215                         n->in_flags |= IPN_PURGE;
1216                 }
1217                 ipf_nat_siocdelnat(softc, softn, n, getlock);
1218
1219                 MUTEX_EXIT(&softn->ipf_nat_io);
1220                 n = NULL;
1221                 break;
1222
1223         case SIOCGNATS :
1224             {
1225                 natstat_t *nsp = &softn->ipf_nat_stats;
1226
1227                 nsp->ns_side[0].ns_table = softn->ipf_nat_table[0];
1228                 nsp->ns_side[1].ns_table = softn->ipf_nat_table[1];
1229                 nsp->ns_list = softn->ipf_nat_list;
1230                 nsp->ns_maptable = softn->ipf_hm_maptable;
1231                 nsp->ns_maplist = softn->ipf_hm_maplist;
1232                 nsp->ns_nattab_sz = softn->ipf_nat_table_sz;
1233                 nsp->ns_nattab_max = softn->ipf_nat_table_max;
1234                 nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz;
1235                 nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz;
1236                 nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz;
1237                 nsp->ns_instances = softn->ipf_nat_instances;
1238                 nsp->ns_ticks = softc->ipf_ticks;
1239 #ifdef IPFILTER_LOGGING
1240                 nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT);
1241                 nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT);
1242 #else
1243                 nsp->ns_log_ok = 0;
1244                 nsp->ns_log_fail = 0;
1245 #endif
1246                 error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT);
1247                 break;
1248             }
1249
1250         case SIOCGNATL :
1251             {
1252                 natlookup_t nl;
1253
1254                 error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP);
1255                 if (error == 0) {
1256                         void *ptr;
1257
1258                         if (getlock) {
1259                                 READ_ENTER(&softc->ipf_nat);
1260                         }
1261
1262                         switch (nl.nl_v)
1263                         {
1264                         case 4 :
1265                                 ptr = ipf_nat_lookupredir(&nl);
1266                                 break;
1267 #ifdef USE_INET6
1268                         case 6 :
1269                                 ptr = ipf_nat6_lookupredir(&nl);
1270                                 break;
1271 #endif
1272                         default:
1273                                 ptr = NULL;
1274                                 break;
1275                         }
1276
1277                         if (getlock) {
1278                                 RWLOCK_EXIT(&softc->ipf_nat);
1279                         }
1280                         if (ptr != NULL) {
1281                                 error = ipf_outobj(softc, data, &nl,
1282                                                    IPFOBJ_NATLOOKUP);
1283                         } else {
1284                                 IPFERROR(60011);
1285                                 error = ESRCH;
1286                         }
1287                 }
1288                 break;
1289             }
1290
1291         case SIOCIPFFL :        /* old SIOCFLNAT & SIOCCNATL */
1292                 if (!(mode & FWRITE)) {
1293                         IPFERROR(60012);
1294                         error = EPERM;
1295                         break;
1296                 }
1297                 if (getlock) {
1298                         WRITE_ENTER(&softc->ipf_nat);
1299                 }
1300
1301                 error = BCOPYIN(data, &arg, sizeof(arg));
1302                 if (error != 0) {
1303                         IPFERROR(60013);
1304                         error = EFAULT;
1305                 } else {
1306                         if (arg == 0)
1307                                 ret = ipf_nat_flushtable(softc, softn);
1308                         else if (arg == 1)
1309                                 ret = ipf_nat_clearlist(softc, softn);
1310                         else
1311                                 ret = ipf_nat_extraflush(softc, softn, arg);
1312                         ipf_proxy_flush(softc->ipf_proxy_soft, arg);
1313                 }
1314
1315                 if (getlock) {
1316                         RWLOCK_EXIT(&softc->ipf_nat);
1317                 }
1318                 if (error == 0) {
1319                         error = BCOPYOUT(&ret, data, sizeof(ret));
1320                 }
1321                 break;
1322
1323         case SIOCMATCHFLUSH :
1324                 if (!(mode & FWRITE)) {
1325                         IPFERROR(60014);
1326                         error = EPERM;
1327                         break;
1328                 }
1329                 if (getlock) {
1330                         WRITE_ENTER(&softc->ipf_nat);
1331                 }
1332
1333                 error = ipf_nat_matchflush(softc, softn, data);
1334
1335                 if (getlock) {
1336                         RWLOCK_EXIT(&softc->ipf_nat);
1337                 }
1338                 break;
1339
1340         case SIOCPROXY :
1341                 error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx);
1342                 break;
1343
1344         case SIOCSTLCK :
1345                 if (!(mode & FWRITE)) {
1346                         IPFERROR(60015);
1347                         error = EPERM;
1348                 } else {
1349                         error = ipf_lock(data, &softn->ipf_nat_lock);
1350                 }
1351                 break;
1352
1353         case SIOCSTPUT :
1354                 if ((mode & FWRITE) != 0) {
1355                         error = ipf_nat_putent(softc, data, getlock);
1356                 } else {
1357                         IPFERROR(60016);
1358                         error = EACCES;
1359                 }
1360                 break;
1361
1362         case SIOCSTGSZ :
1363                 if (softn->ipf_nat_lock) {
1364                         error = ipf_nat_getsz(softc, data, getlock);
1365                 } else {
1366                         IPFERROR(60017);
1367                         error = EACCES;
1368                 }
1369                 break;
1370
1371         case SIOCSTGET :
1372                 if (softn->ipf_nat_lock) {
1373                         error = ipf_nat_getent(softc, data, getlock);
1374                 } else {
1375                         IPFERROR(60018);
1376                         error = EACCES;
1377                 }
1378                 break;
1379
1380         case SIOCGENITER :
1381             {
1382                 ipfgeniter_t iter;
1383                 ipftoken_t *token;
1384                 ipfobj_t obj;
1385
1386                 error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
1387                 if (error != 0)
1388                         break;
1389
1390                 SPL_SCHED(s);
1391                 token = ipf_token_find(softc, iter.igi_type, uid, ctx);
1392                 if (token != NULL) {
1393                         error  = ipf_nat_iterator(softc, token, &iter, &obj);
1394                         WRITE_ENTER(&softc->ipf_tokens);
1395                         ipf_token_deref(softc, token);
1396                         RWLOCK_EXIT(&softc->ipf_tokens);
1397                 }
1398                 SPL_X(s);
1399                 break;
1400             }
1401
1402         case SIOCIPFDELTOK :
1403                 error = BCOPYIN(data, &arg, sizeof(arg));
1404                 if (error == 0) {
1405                         SPL_SCHED(s);
1406                         error = ipf_token_del(softc, arg, uid, ctx);
1407                         SPL_X(s);
1408                 } else {
1409                         IPFERROR(60019);
1410                         error = EFAULT;
1411                 }
1412                 break;
1413
1414         case SIOCGTQTAB :
1415                 error = ipf_outobj(softc, data, softn->ipf_nat_tcptq,
1416                                    IPFOBJ_STATETQTAB);
1417                 break;
1418
1419         case SIOCGTABL :
1420                 error = ipf_nat_gettable(softc, softn, data);
1421                 break;
1422
1423         default :
1424                 IPFERROR(60020);
1425                 error = EINVAL;
1426                 break;
1427         }
1428 done:
1429         if (nat != NULL)
1430                 ipf_nat_rule_fini(softc, nat);
1431         if (nt != NULL)
1432                 KFREES(nt, nt->in_size);
1433         return error;
1434 }
1435
1436
1437 /* ------------------------------------------------------------------------ */
1438 /* Function:    ipf_nat_siocaddnat                                          */
1439 /* Returns:     int - 0 == success, != 0 == failure                         */
1440 /* Parameters:  softc(I) - pointer to soft context main structure           */
1441 /*              softn(I) - pointer to NAT context structure                 */
1442 /*              n(I)       - pointer to new NAT rule                        */
1443 /*              np(I)      - pointer to where to insert new NAT rule        */
1444 /*              getlock(I) - flag indicating if lock on  is held            */
1445 /* Mutex Locks: ipf_nat_io                                                   */
1446 /*                                                                          */
1447 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
1448 /* from information passed to the kernel, then add it  to the appropriate   */
1449 /* NAT rule table(s).                                                       */
1450 /* ------------------------------------------------------------------------ */
1451 static int
1452 ipf_nat_siocaddnat(softc, softn, n, getlock)
1453         ipf_main_softc_t *softc;
1454         ipf_nat_softc_t *softn;
1455         ipnat_t *n;
1456         int getlock;
1457 {
1458         int error = 0;
1459
1460         if (ipf_nat_resolverule(softc, n) != 0) {
1461                 IPFERROR(60022);
1462                 return ENOENT;
1463         }
1464
1465         if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) {
1466                 IPFERROR(60023);
1467                 return EINVAL;
1468         }
1469
1470         if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
1471                 /*
1472                  * Prerecord whether or not the destination of the divert
1473                  * is local or not to the interface the packet is going
1474                  * to be sent out.
1475                  */
1476                 n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
1477                                                 n->in_ifps[1], &n->in_ndstip6);
1478         }
1479
1480         if (getlock) {
1481                 WRITE_ENTER(&softc->ipf_nat);
1482         }
1483         n->in_next = NULL;
1484         n->in_pnext = softn->ipf_nat_list_tail;
1485         *n->in_pnext = n;
1486         softn->ipf_nat_list_tail = &n->in_next;
1487         n->in_use++;
1488
1489         if (n->in_redir & NAT_REDIRECT) {
1490                 n->in_flags &= ~IPN_NOTDST;
1491                 switch (n->in_v[0])
1492                 {
1493                 case 4 :
1494                         ipf_nat_addrdr(softn, n);
1495                         break;
1496 #ifdef USE_INET6
1497                 case 6 :
1498                         ipf_nat6_addrdr(softn, n);
1499                         break;
1500 #endif
1501                 default :
1502                         break;
1503                 }
1504                 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr);
1505         }
1506
1507         if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
1508                 n->in_flags &= ~IPN_NOTSRC;
1509                 switch (n->in_v[0])
1510                 {
1511                 case 4 :
1512                         ipf_nat_addmap(softn, n);
1513                         break;
1514 #ifdef USE_INET6
1515                 case 6 :
1516                         ipf_nat6_addmap(softn, n);
1517                         break;
1518 #endif
1519                 default :
1520                         break;
1521                 }
1522                 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map);
1523         }
1524
1525         if (n->in_age[0] != 0)
1526                 n->in_tqehead[0] = ipf_addtimeoutqueue(softc,
1527                                                        &softn->ipf_nat_utqe,
1528                                                        n->in_age[0]);
1529
1530         if (n->in_age[1] != 0)
1531                 n->in_tqehead[1] = ipf_addtimeoutqueue(softc,
1532                                                        &softn->ipf_nat_utqe,
1533                                                        n->in_age[1]);
1534
1535         MUTEX_INIT(&n->in_lock, "ipnat rule lock");
1536
1537         n = NULL;
1538         ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
1539 #if SOLARIS && !defined(INSTANCES)
1540         pfil_delayed_copy = 0;
1541 #endif
1542         if (getlock) {
1543                 RWLOCK_EXIT(&softc->ipf_nat);                   /* WRITE */
1544         }
1545
1546         return error;
1547 }
1548
1549
1550 /* ------------------------------------------------------------------------ */
1551 /* Function:    ipf_nat_ruleaddrinit                                        */
1552 /* Parameters:  softc(I) - pointer to soft context main structure           */
1553 /*              softn(I) - pointer to NAT context structure                 */
1554 /*              n(I)     - pointer to NAT rule                              */
1555 /*                                                                          */
1556 /* Initialise all of the NAT address structures in a NAT rule.              */
1557 /* ------------------------------------------------------------------------ */
1558 static int
1559 ipf_nat_ruleaddrinit(softc, softn, n)
1560         ipf_main_softc_t *softc;
1561         ipf_nat_softc_t *softn;
1562         ipnat_t *n;
1563 {
1564         int idx, error;
1565
1566         if ((n->in_ndst.na_atype == FRI_LOOKUP) &&
1567             (n->in_ndst.na_type != IPLT_DSTLIST)) {
1568                 IPFERROR(60071);
1569                 return EINVAL;
1570         }
1571         if ((n->in_nsrc.na_atype == FRI_LOOKUP) &&
1572             (n->in_nsrc.na_type != IPLT_DSTLIST)) {
1573                 IPFERROR(60069);
1574                 return EINVAL;
1575         }
1576
1577         if (n->in_redir == NAT_BIMAP) {
1578                 n->in_ndstaddr = n->in_osrcaddr;
1579                 n->in_ndstmsk = n->in_osrcmsk;
1580                 n->in_odstaddr = n->in_nsrcaddr;
1581                 n->in_odstmsk = n->in_nsrcmsk;
1582
1583         }
1584
1585         if (n->in_redir & NAT_REDIRECT)
1586                 idx = 1;
1587         else
1588                 idx = 0;
1589         /*
1590          * Initialise all of the address fields.
1591          */
1592         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
1593                                      n->in_ifps[idx]);
1594         if (error != 0)
1595                 return error;
1596
1597         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
1598                                      n->in_ifps[idx]);
1599         if (error != 0)
1600                 return error;
1601
1602         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
1603                                      n->in_ifps[idx]);
1604         if (error != 0)
1605                 return error;
1606
1607         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
1608                                      n->in_ifps[idx]);
1609         if (error != 0)
1610                 return error;
1611
1612         if (n->in_redir & NAT_DIVERTUDP)
1613                 ipf_nat_builddivertmp(softn, n);
1614
1615         return 0;
1616 }
1617
1618
1619 /* ------------------------------------------------------------------------ */
1620 /* Function:    ipf_nat_resolvrule                                          */
1621 /* Returns:     Nil                                                         */
1622 /* Parameters:  softc(I) - pointer to soft context main structure           */
1623 /*              n(I)     - pointer to NAT rule                              */
1624 /*                                                                          */
1625 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
1626 /* from information passed to the kernel, then add it  to the appropriate   */
1627 /* NAT rule table(s).                                                       */
1628 /* ------------------------------------------------------------------------ */
1629 static int
1630 ipf_nat_resolverule(softc, n)
1631         ipf_main_softc_t *softc;
1632         ipnat_t *n;
1633 {
1634         char *base;
1635
1636         base = n->in_names;
1637
1638         n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0],
1639                                        n->in_v[0]);
1640
1641         if (n->in_ifnames[1] == -1) {
1642                 n->in_ifnames[1] = n->in_ifnames[0];
1643                 n->in_ifps[1] = n->in_ifps[0];
1644         } else {
1645                 n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1],
1646                                                n->in_v[1]);
1647         }
1648
1649         if (n->in_plabel != -1) {
1650                 if (n->in_redir & NAT_REDIRECT)
1651                         n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
1652                                                      n->in_pr[0],
1653                                                      base + n->in_plabel);
1654                 else
1655                         n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
1656                                                      n->in_pr[1],
1657                                                      base + n->in_plabel);
1658                 if (n->in_apr == NULL)
1659                         return -1;
1660         }
1661         return 0;
1662 }
1663
1664
1665 /* ------------------------------------------------------------------------ */
1666 /* Function:    ipf_nat_siocdelnat                                          */
1667 /* Returns:     int - 0 == success, != 0 == failure                         */
1668 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1669 /*              softn(I)   - pointer to NAT context structure               */
1670 /*              n(I)       - pointer to new NAT rule                        */
1671 /*              getlock(I) - flag indicating if lock on  is held            */
1672 /* Mutex Locks: ipf_nat_io                                                  */
1673 /*                                                                          */
1674 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
1675 /* from information passed to the kernel, then add it  to the appropriate   */
1676 /* NAT rule table(s).                                                       */
1677 /* ------------------------------------------------------------------------ */
1678 static void
1679 ipf_nat_siocdelnat(softc, softn, n, getlock)
1680         ipf_main_softc_t *softc;
1681         ipf_nat_softc_t *softn;
1682         ipnat_t *n;
1683         int getlock;
1684 {
1685 #ifdef IPF_NAT6
1686         int i;
1687 #endif
1688
1689         if (getlock) {
1690                 WRITE_ENTER(&softc->ipf_nat);
1691         }
1692
1693         ipf_nat_delrule(softc, softn, n, 1);
1694
1695         if (getlock) {
1696                 RWLOCK_EXIT(&softc->ipf_nat);                   /* READ/WRITE */
1697         }
1698 }
1699
1700
1701 /* ------------------------------------------------------------------------ */
1702 /* Function:    ipf_nat_getsz                                               */
1703 /* Returns:     int - 0 == success, != 0 is the error value.                */
1704 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1705 /*              data(I)    - pointer to natget structure with kernel        */
1706 /*                           pointer get the size of.                       */
1707 /*              getlock(I) - flag indicating whether or not the caller      */
1708 /*                           holds a lock on ipf_nat                        */
1709 /*                                                                          */
1710 /* Handle SIOCSTGSZ.                                                        */
1711 /* Return the size of the nat list entry to be copied back to user space.   */
1712 /* The size of the entry is stored in the ng_sz field and the enture natget */
1713 /* structure is copied back to the user.                                    */
1714 /* ------------------------------------------------------------------------ */
1715 static int
1716 ipf_nat_getsz(softc, data, getlock)
1717         ipf_main_softc_t *softc;
1718         caddr_t data;
1719         int getlock;
1720 {
1721         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1722         ap_session_t *aps;
1723         nat_t *nat, *n;
1724         natget_t ng;
1725         int error;
1726
1727         error = BCOPYIN(data, &ng, sizeof(ng));
1728         if (error != 0) {
1729                 IPFERROR(60024);
1730                 return EFAULT;
1731         }
1732
1733         if (getlock) {
1734                 READ_ENTER(&softc->ipf_nat);
1735         }
1736
1737         nat = ng.ng_ptr;
1738         if (!nat) {
1739                 nat = softn->ipf_nat_instances;
1740                 ng.ng_sz = 0;
1741                 /*
1742                  * Empty list so the size returned is 0.  Simple.
1743                  */
1744                 if (nat == NULL) {
1745                         if (getlock) {
1746                                 RWLOCK_EXIT(&softc->ipf_nat);
1747                         }
1748                         error = BCOPYOUT(&ng, data, sizeof(ng));
1749                         if (error != 0) {
1750                                 IPFERROR(60025);
1751                                 return EFAULT;
1752                         }
1753                         return 0;
1754                 }
1755         } else {
1756                 /*
1757                  * Make sure the pointer we're copying from exists in the
1758                  * current list of entries.  Security precaution to prevent
1759                  * copying of random kernel data.
1760                  */
1761                 for (n = softn->ipf_nat_instances; n; n = n->nat_next)
1762                         if (n == nat)
1763                                 break;
1764                 if (n == NULL) {
1765                         if (getlock) {
1766                                 RWLOCK_EXIT(&softc->ipf_nat);
1767                         }
1768                         IPFERROR(60026);
1769                         return ESRCH;
1770                 }
1771         }
1772
1773         /*
1774          * Incluse any space required for proxy data structures.
1775          */
1776         ng.ng_sz = sizeof(nat_save_t);
1777         aps = nat->nat_aps;
1778         if (aps != NULL) {
1779                 ng.ng_sz += sizeof(ap_session_t) - 4;
1780                 if (aps->aps_data != 0)
1781                         ng.ng_sz += aps->aps_psiz;
1782         }
1783         if (getlock) {
1784                 RWLOCK_EXIT(&softc->ipf_nat);
1785         }
1786
1787         error = BCOPYOUT(&ng, data, sizeof(ng));
1788         if (error != 0) {
1789                 IPFERROR(60027);
1790                 return EFAULT;
1791         }
1792         return 0;
1793 }
1794
1795
1796 /* ------------------------------------------------------------------------ */
1797 /* Function:    ipf_nat_getent                                              */
1798 /* Returns:     int - 0 == success, != 0 is the error value.                */
1799 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1800 /*              data(I)    - pointer to natget structure with kernel pointer*/
1801 /*                           to NAT structure to copy out.                  */
1802 /*              getlock(I) - flag indicating whether or not the caller      */
1803 /*                           holds a lock on ipf_nat                        */
1804 /*                                                                          */
1805 /* Handle SIOCSTGET.                                                        */
1806 /* Copies out NAT entry to user space.  Any additional data held for a      */
1807 /* proxy is also copied, as to is the NAT rule which was responsible for it */
1808 /* ------------------------------------------------------------------------ */
1809 static int
1810 ipf_nat_getent(softc, data, getlock)
1811         ipf_main_softc_t *softc;
1812         caddr_t data;
1813         int getlock;
1814 {
1815         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1816         int error, outsize;
1817         ap_session_t *aps;
1818         nat_save_t *ipn, ipns;
1819         nat_t *n, *nat;
1820
1821         error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE);
1822         if (error != 0)
1823                 return error;
1824
1825         if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) {
1826                 IPFERROR(60028);
1827                 return EINVAL;
1828         }
1829
1830         KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize);
1831         if (ipn == NULL) {
1832                 IPFERROR(60029);
1833                 return ENOMEM;
1834         }
1835
1836         if (getlock) {
1837                 READ_ENTER(&softc->ipf_nat);
1838         }
1839
1840         ipn->ipn_dsize = ipns.ipn_dsize;
1841         nat = ipns.ipn_next;
1842         if (nat == NULL) {
1843                 nat = softn->ipf_nat_instances;
1844                 if (nat == NULL) {
1845                         if (softn->ipf_nat_instances == NULL) {
1846                                 IPFERROR(60030);
1847                                 error = ENOENT;
1848                         }
1849                         goto finished;
1850                 }
1851         } else {
1852                 /*
1853                  * Make sure the pointer we're copying from exists in the
1854                  * current list of entries.  Security precaution to prevent
1855                  * copying of random kernel data.
1856                  */
1857                 for (n = softn->ipf_nat_instances; n; n = n->nat_next)
1858                         if (n == nat)
1859                                 break;
1860                 if (n == NULL) {
1861                         IPFERROR(60031);
1862                         error = ESRCH;
1863                         goto finished;
1864                 }
1865         }
1866         ipn->ipn_next = nat->nat_next;
1867
1868         /*
1869          * Copy the NAT structure.
1870          */
1871         bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat));
1872
1873         /*
1874          * If we have a pointer to the NAT rule it belongs to, save that too.
1875          */
1876         if (nat->nat_ptr != NULL)
1877                 bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat,
1878                       ipn->ipn_ipnat.in_size);
1879
1880         /*
1881          * If we also know the NAT entry has an associated filter rule,
1882          * save that too.
1883          */
1884         if (nat->nat_fr != NULL)
1885                 bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr,
1886                       sizeof(ipn->ipn_fr));
1887
1888         /*
1889          * Last but not least, if there is an application proxy session set
1890          * up for this NAT entry, then copy that out too, including any
1891          * private data saved along side it by the proxy.
1892          */
1893         aps = nat->nat_aps;
1894         outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data);
1895         if (aps != NULL) {
1896                 char *s;
1897
1898                 if (outsize < sizeof(*aps)) {
1899                         IPFERROR(60032);
1900                         error = ENOBUFS;
1901                         goto finished;
1902                 }
1903
1904                 s = ipn->ipn_data;
1905                 bcopy((char *)aps, s, sizeof(*aps));
1906                 s += sizeof(*aps);
1907                 outsize -= sizeof(*aps);
1908                 if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz))
1909                         bcopy(aps->aps_data, s, aps->aps_psiz);
1910                 else {
1911                         IPFERROR(60033);
1912                         error = ENOBUFS;
1913                 }
1914         }
1915         if (error == 0) {
1916                 if (getlock) {
1917                         READ_ENTER(&softc->ipf_nat);
1918                         getlock = 0;
1919                 }
1920                 error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE,
1921                                      ipns.ipn_dsize);
1922         }
1923
1924 finished:
1925         if (getlock) {
1926                 READ_ENTER(&softc->ipf_nat);
1927         }
1928         if (ipn != NULL) {
1929                 KFREES(ipn, ipns.ipn_dsize);
1930         }
1931         return error;
1932 }
1933
1934
1935 /* ------------------------------------------------------------------------ */
1936 /* Function:    ipf_nat_putent                                              */
1937 /* Returns:     int - 0 == success, != 0 is the error value.                */
1938 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1939 /*              data(I)    - pointer to natget structure with NAT           */
1940 /*                           structure information to load into the kernel  */
1941 /*              getlock(I) - flag indicating whether or not a write lock    */
1942 /*                           on is already held.                            */
1943 /*                                                                          */
1944 /* Handle SIOCSTPUT.                                                        */
1945 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */
1946 /* firewall rule data structures, if pointers to them indicate so.          */
1947 /* ------------------------------------------------------------------------ */
1948 static int
1949 ipf_nat_putent(softc, data, getlock)
1950         ipf_main_softc_t *softc;
1951         caddr_t data;
1952         int getlock;
1953 {
1954         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1955         nat_save_t ipn, *ipnn;
1956         ap_session_t *aps;
1957         nat_t *n, *nat;
1958         frentry_t *fr;
1959         fr_info_t fin;
1960         ipnat_t *in;
1961         int error;
1962
1963         error = ipf_inobj(softc, data, NULL, &ipn, IPFOBJ_NATSAVE);
1964         if (error != 0)
1965                 return error;
1966
1967         /*
1968          * Initialise early because of code at junkput label.
1969          */
1970         n = NULL;
1971         in = NULL;
1972         aps = NULL;
1973         nat = NULL;
1974         ipnn = NULL;
1975         fr = NULL;
1976
1977         /*
1978          * New entry, copy in the rest of the NAT entry if it's size is more
1979          * than just the nat_t structure.
1980          */
1981         if (ipn.ipn_dsize > sizeof(ipn)) {
1982                 if (ipn.ipn_dsize > 81920) {
1983                         IPFERROR(60034);
1984                         error = ENOMEM;
1985                         goto junkput;
1986                 }
1987
1988                 KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize);
1989                 if (ipnn == NULL) {
1990                         IPFERROR(60035);
1991                         return ENOMEM;
1992                 }
1993
1994                 bzero(ipnn, ipn.ipn_dsize);
1995                 error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE,
1996                                     ipn.ipn_dsize);
1997                 if (error != 0) {
1998                         goto junkput;
1999                 }
2000         } else
2001                 ipnn = &ipn;
2002
2003         KMALLOC(nat, nat_t *);
2004         if (nat == NULL) {
2005                 IPFERROR(60037);
2006                 error = ENOMEM;
2007                 goto junkput;
2008         }
2009
2010         bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat));
2011
2012         switch (nat->nat_v[0])
2013         {
2014         case 4:
2015 #ifdef USE_INET6
2016         case 6 :
2017 #endif
2018                 break;
2019         default :
2020                 IPFERROR(60061);
2021                 error = EPROTONOSUPPORT;
2022                 goto junkput;
2023                 /*NOTREACHED*/
2024         }
2025
2026         /*
2027          * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
2028          */
2029         bzero((char *)nat, offsetof(struct nat, nat_tqe));
2030         nat->nat_tqe.tqe_pnext = NULL;
2031         nat->nat_tqe.tqe_next = NULL;
2032         nat->nat_tqe.tqe_ifq = NULL;
2033         nat->nat_tqe.tqe_parent = nat;
2034
2035         /*
2036          * Restore the rule associated with this nat session
2037          */
2038         in = ipnn->ipn_nat.nat_ptr;
2039         if (in != NULL) {
2040                 KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size);
2041                 nat->nat_ptr = in;
2042                 if (in == NULL) {
2043                         IPFERROR(60038);
2044                         error = ENOMEM;
2045                         goto junkput;
2046                 }
2047                 bcopy((char *)&ipnn->ipn_ipnat, (char *)in,
2048                       ipnn->ipn_ipnat.in_size);
2049                 in->in_use = 1;
2050                 in->in_flags |= IPN_DELETE;
2051
2052                 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
2053
2054                 if (ipf_nat_resolverule(softc, in) != 0) {
2055                         IPFERROR(60039);
2056                         error = ESRCH;
2057                         goto junkput;
2058                 }
2059         }
2060
2061         /*
2062          * Check that the NAT entry doesn't already exist in the kernel.
2063          *
2064          * For NAT_OUTBOUND, we're lookup for a duplicate MAP entry.  To do
2065          * this, we check to see if the inbound combination of addresses and
2066          * ports is already known.  Similar logic is applied for NAT_INBOUND.
2067          *
2068          */
2069         bzero((char *)&fin, sizeof(fin));
2070         fin.fin_v = nat->nat_v[0];
2071         fin.fin_p = nat->nat_pr[0];
2072         fin.fin_rev = nat->nat_rev;
2073         fin.fin_ifp = nat->nat_ifps[0];
2074         fin.fin_data[0] = ntohs(nat->nat_ndport);
2075         fin.fin_data[1] = ntohs(nat->nat_nsport);
2076
2077         switch (nat->nat_dir)
2078         {
2079         case NAT_OUTBOUND :
2080         case NAT_DIVERTOUT :
2081                 if (getlock) {
2082                         READ_ENTER(&softc->ipf_nat);
2083                 }
2084
2085                 fin.fin_v = nat->nat_v[1];
2086                 if (nat->nat_v[1] == 4) {
2087                         n = ipf_nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
2088                                              nat->nat_ndstip, nat->nat_nsrcip);
2089 #ifdef USE_INET6
2090                 } else if (nat->nat_v[1] == 6) {
2091                         n = ipf_nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
2092                                               &nat->nat_ndst6.in6,
2093                                               &nat->nat_nsrc6.in6);
2094 #endif
2095                 }
2096
2097                 if (getlock) {
2098                         RWLOCK_EXIT(&softc->ipf_nat);
2099                 }
2100                 if (n != NULL) {
2101                         IPFERROR(60040);
2102                         error = EEXIST;
2103                         goto junkput;
2104                 }
2105                 break;
2106
2107         case NAT_INBOUND :
2108         case NAT_DIVERTIN :
2109                 if (getlock) {
2110                         READ_ENTER(&softc->ipf_nat);
2111                 }
2112
2113                 if (fin.fin_v == 4) {
2114                         n = ipf_nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
2115                                               nat->nat_ndstip,
2116                                               nat->nat_nsrcip);
2117 #ifdef USE_INET6
2118                 } else if (fin.fin_v == 6) {
2119                         n = ipf_nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
2120                                                &nat->nat_ndst6.in6,
2121                                                &nat->nat_nsrc6.in6);
2122 #endif
2123                 }
2124
2125                 if (getlock) {
2126                         RWLOCK_EXIT(&softc->ipf_nat);
2127                 }
2128                 if (n != NULL) {
2129                         IPFERROR(60041);
2130                         error = EEXIST;
2131                         goto junkput;
2132                 }
2133                 break;
2134
2135         default :
2136                 IPFERROR(60042);
2137                 error = EINVAL;
2138                 goto junkput;
2139         }
2140
2141         /*
2142          * Restore ap_session_t structure.  Include the private data allocated
2143          * if it was there.
2144          */
2145         aps = nat->nat_aps;
2146         if (aps != NULL) {
2147                 KMALLOC(aps, ap_session_t *);
2148                 nat->nat_aps = aps;
2149                 if (aps == NULL) {
2150                         IPFERROR(60043);
2151                         error = ENOMEM;
2152                         goto junkput;
2153                 }
2154                 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps));
2155                 if (in != NULL)
2156                         aps->aps_apr = in->in_apr;
2157                 else
2158                         aps->aps_apr = NULL;
2159                 if (aps->aps_psiz != 0) {
2160                         if (aps->aps_psiz > 81920) {
2161                                 IPFERROR(60044);
2162                                 error = ENOMEM;
2163                                 goto junkput;
2164                         }
2165                         KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
2166                         if (aps->aps_data == NULL) {
2167                                 IPFERROR(60045);
2168                                 error = ENOMEM;
2169                                 goto junkput;
2170                         }
2171                         bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data,
2172                               aps->aps_psiz);
2173                 } else {
2174                         aps->aps_psiz = 0;
2175                         aps->aps_data = NULL;
2176                 }
2177         }
2178
2179         /*
2180          * If there was a filtering rule associated with this entry then
2181          * build up a new one.
2182          */
2183         fr = nat->nat_fr;
2184         if (fr != NULL) {
2185                 if ((nat->nat_flags & SI_NEWFR) != 0) {
2186                         KMALLOC(fr, frentry_t *);
2187                         nat->nat_fr = fr;
2188                         if (fr == NULL) {
2189                                 IPFERROR(60046);
2190                                 error = ENOMEM;
2191                                 goto junkput;
2192                         }
2193                         ipnn->ipn_nat.nat_fr = fr;
2194                         fr->fr_ref = 1;
2195                         (void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE);
2196                         bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
2197
2198                         fr->fr_ref = 1;
2199                         fr->fr_dsize = 0;
2200                         fr->fr_data = NULL;
2201                         fr->fr_type = FR_T_NONE;
2202
2203                         MUTEX_NUKE(&fr->fr_lock);
2204                         MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
2205                 } else {
2206                         if (getlock) {
2207                                 READ_ENTER(&softc->ipf_nat);
2208                         }
2209                         for (n = softn->ipf_nat_instances; n; n = n->nat_next)
2210                                 if (n->nat_fr == fr)
2211                                         break;
2212
2213                         if (n != NULL) {
2214                                 MUTEX_ENTER(&fr->fr_lock);
2215                                 fr->fr_ref++;
2216                                 MUTEX_EXIT(&fr->fr_lock);
2217                         }
2218                         if (getlock) {
2219                                 RWLOCK_EXIT(&softc->ipf_nat);
2220                         }
2221
2222                         if (n == NULL) {
2223                                 IPFERROR(60047);
2224                                 error = ESRCH;
2225                                 goto junkput;
2226                         }
2227                 }
2228         }
2229
2230         if (ipnn != &ipn) {
2231                 KFREES(ipnn, ipn.ipn_dsize);
2232                 ipnn = NULL;
2233         }
2234
2235         if (getlock) {
2236                 WRITE_ENTER(&softc->ipf_nat);
2237         }
2238
2239         if (fin.fin_v == 4)
2240                 error = ipf_nat_finalise(&fin, nat);
2241 #ifdef USE_INET6
2242         else
2243                 error = ipf_nat6_finalise(&fin, nat);
2244 #endif
2245
2246         if (getlock) {
2247                 RWLOCK_EXIT(&softc->ipf_nat);
2248         }
2249
2250         if (error == 0)
2251                 return 0;
2252
2253         IPFERROR(60048);
2254         error = ENOMEM;
2255
2256 junkput:
2257         if (fr != NULL) {
2258                 (void) ipf_derefrule(softc, &fr);
2259         }
2260
2261         if ((ipnn != NULL) && (ipnn != &ipn)) {
2262                 KFREES(ipnn, ipn.ipn_dsize);
2263         }
2264         if (nat != NULL) {
2265                 if (aps != NULL) {
2266                         if (aps->aps_data != NULL) {
2267                                 KFREES(aps->aps_data, aps->aps_psiz);
2268                         }
2269                         KFREE(aps);
2270                 }
2271                 if (in != NULL) {
2272                         if (in->in_apr)
2273                                 ipf_proxy_deref(in->in_apr);
2274                         KFREES(in, in->in_size);
2275                 }
2276                 KFREE(nat);
2277         }
2278         return error;
2279 }
2280
2281
2282 /* ------------------------------------------------------------------------ */
2283 /* Function:    ipf_nat_delete                                              */
2284 /* Returns:     Nil                                                         */
2285 /* Parameters:  softc(I)   - pointer to soft context main structure         */
2286 /*              nat(I)     - pointer to NAT structure to delete             */
2287 /*              logtype(I) - type of LOG record to create before deleting   */
2288 /* Write Lock:  ipf_nat                                                     */
2289 /*                                                                          */
2290 /* Delete a nat entry from the various lists and table.  If NAT logging is  */
2291 /* enabled then generate a NAT log record for this event.                   */
2292 /* ------------------------------------------------------------------------ */
2293 void
2294 ipf_nat_delete(softc, nat, logtype)
2295         ipf_main_softc_t *softc;
2296         struct nat *nat;
2297         int logtype;
2298 {
2299         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2300         int madeorphan = 0, bkt, removed = 0;
2301         nat_stat_side_t *nss;
2302         struct ipnat *ipn;
2303
2304         if (logtype != 0 && softn->ipf_nat_logging != 0)
2305                 ipf_nat_log(softc, softn, nat, logtype);
2306
2307         /*
2308          * Take it as a general indication that all the pointers are set if
2309          * nat_pnext is set.
2310          */
2311         if (nat->nat_pnext != NULL) {
2312                 removed = 1;
2313
2314                 bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz;
2315                 nss = &softn->ipf_nat_stats.ns_side[0];
2316                 nss->ns_bucketlen[bkt]--;
2317                 if (nss->ns_bucketlen[bkt] == 0) {
2318                         nss->ns_inuse--;
2319                 }
2320
2321                 bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz;
2322                 nss = &softn->ipf_nat_stats.ns_side[1];
2323                 nss->ns_bucketlen[bkt]--;
2324                 if (nss->ns_bucketlen[bkt] == 0) {
2325                         nss->ns_inuse--;
2326                 }
2327
2328                 *nat->nat_pnext = nat->nat_next;
2329                 if (nat->nat_next != NULL) {
2330                         nat->nat_next->nat_pnext = nat->nat_pnext;
2331                         nat->nat_next = NULL;
2332                 }
2333                 nat->nat_pnext = NULL;
2334
2335                 *nat->nat_phnext[0] = nat->nat_hnext[0];
2336                 if (nat->nat_hnext[0] != NULL) {
2337                         nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
2338                         nat->nat_hnext[0] = NULL;
2339                 }
2340                 nat->nat_phnext[0] = NULL;
2341
2342                 *nat->nat_phnext[1] = nat->nat_hnext[1];
2343                 if (nat->nat_hnext[1] != NULL) {
2344                         nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
2345                         nat->nat_hnext[1] = NULL;
2346                 }
2347                 nat->nat_phnext[1] = NULL;
2348
2349                 if ((nat->nat_flags & SI_WILDP) != 0) {
2350                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds);
2351                 }
2352                 madeorphan = 1;
2353         }
2354
2355         if (nat->nat_me != NULL) {
2356                 *nat->nat_me = NULL;
2357                 nat->nat_me = NULL;
2358                 nat->nat_ref--;
2359                 ASSERT(nat->nat_ref >= 0);
2360         }
2361
2362         if (nat->nat_tqe.tqe_ifq != NULL) {
2363                 /*
2364                  * No call to ipf_freetimeoutqueue() is made here, they are
2365                  * garbage collected in ipf_nat_expire().
2366                  */
2367                 (void) ipf_deletequeueentry(&nat->nat_tqe);
2368         }
2369
2370         if (nat->nat_sync) {
2371                 ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
2372                 nat->nat_sync = NULL;
2373         }
2374
2375         if (logtype == NL_EXPIRE)
2376                 softn->ipf_nat_stats.ns_expire++;
2377
2378         MUTEX_ENTER(&nat->nat_lock);
2379         /*
2380          * NL_DESTROY should only be passed in when we've got nat_ref >= 2.
2381          * This happens when a nat'd packet is blocked and we want to throw
2382          * away the NAT session.
2383          */
2384         if (logtype == NL_DESTROY) {
2385                 if (nat->nat_ref > 2) {
2386                         nat->nat_ref -= 2;
2387                         MUTEX_EXIT(&nat->nat_lock);
2388                         if (removed)
2389                                 softn->ipf_nat_stats.ns_orphans++;
2390                         return;
2391                 }
2392         } else if (nat->nat_ref > 1) {
2393                 nat->nat_ref--;
2394                 MUTEX_EXIT(&nat->nat_lock);
2395                 if (madeorphan == 1)
2396                         softn->ipf_nat_stats.ns_orphans++;
2397                 return;
2398         }
2399         ASSERT(nat->nat_ref >= 0);
2400         MUTEX_EXIT(&nat->nat_lock);
2401
2402         nat->nat_ref = 0;
2403
2404         if (madeorphan == 0)
2405                 softn->ipf_nat_stats.ns_orphans--;
2406
2407         /*
2408          * At this point, nat_ref can be either 0 or -1
2409          */
2410         softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--;
2411
2412         if (nat->nat_fr != NULL) {
2413                 (void) ipf_derefrule(softc, &nat->nat_fr);
2414         }
2415
2416         if (nat->nat_hm != NULL) {
2417                 ipf_nat_hostmapdel(softc, &nat->nat_hm);
2418         }
2419
2420         /*
2421          * If there is an active reference from the nat entry to its parent
2422          * rule, decrement the rule's reference count and free it too if no
2423          * longer being used.
2424          */
2425         ipn = nat->nat_ptr;
2426         nat->nat_ptr = NULL;
2427
2428         if (ipn != NULL) {
2429                 ipn->in_space++;
2430                 ipf_nat_rule_deref(softc, &ipn);
2431         }
2432
2433         if (nat->nat_aps != NULL) {
2434                 ipf_proxy_free(softc, nat->nat_aps);
2435                 nat->nat_aps = NULL;
2436         }
2437
2438         MUTEX_DESTROY(&nat->nat_lock);
2439
2440         softn->ipf_nat_stats.ns_active--;
2441
2442         /*
2443          * If there's a fragment table entry too for this nat entry, then
2444          * dereference that as well.  This is after nat_lock is released
2445          * because of Tru64.
2446          */
2447         ipf_frag_natforget(softc, (void *)nat);
2448
2449         KFREE(nat);
2450 }
2451
2452
2453 /* ------------------------------------------------------------------------ */
2454 /* Function:    ipf_nat_flushtable                                          */
2455 /* Returns:     int - number of NAT rules deleted                           */
2456 /* Parameters:  softc(I) - pointer to soft context main structure           */
2457 /*              softn(I) - pointer to NAT context structure                 */
2458 /* Write Lock:  ipf_nat                                                     */
2459 /*                                                                          */
2460 /* Deletes all currently active NAT sessions.  In deleting each NAT entry a */
2461 /* log record should be emitted in ipf_nat_delete() if NAT logging is       */
2462 /* enabled.                                                                 */
2463 /* ------------------------------------------------------------------------ */
2464 /*
2465  * nat_flushtable - clear the NAT table of all mapping entries.
2466  */
2467 static int
2468 ipf_nat_flushtable(softc, softn)
2469         ipf_main_softc_t *softc;
2470         ipf_nat_softc_t *softn;
2471 {
2472         nat_t *nat;
2473         int j = 0;
2474
2475         /*
2476          * ALL NAT mappings deleted, so lets just make the deletions
2477          * quicker.
2478          */
2479         if (softn->ipf_nat_table[0] != NULL)
2480                 bzero((char *)softn->ipf_nat_table[0],
2481                       sizeof(softn->ipf_nat_table[0]) *
2482                       softn->ipf_nat_table_sz);
2483         if (softn->ipf_nat_table[1] != NULL)
2484                 bzero((char *)softn->ipf_nat_table[1],
2485                       sizeof(softn->ipf_nat_table[1]) *
2486                       softn->ipf_nat_table_sz);
2487
2488         while ((nat = softn->ipf_nat_instances) != NULL) {
2489                 ipf_nat_delete(softc, nat, NL_FLUSH);
2490                 j++;
2491         }
2492
2493         return j;
2494 }
2495
2496
2497 /* ------------------------------------------------------------------------ */
2498 /* Function:    ipf_nat_clearlist                                           */
2499 /* Returns:     int - number of NAT/RDR rules deleted                       */
2500 /* Parameters:  softc(I) - pointer to soft context main structure           */
2501 /*              softn(I) - pointer to NAT context structure                 */
2502 /*                                                                          */
2503 /* Delete all rules in the current list of rules.  There is nothing elegant */
2504 /* about this cleanup: simply free all entries on the list of rules and     */
2505 /* clear out the tables used for hashed NAT rule lookups.                   */
2506 /* ------------------------------------------------------------------------ */
2507 static int
2508 ipf_nat_clearlist(softc, softn)
2509         ipf_main_softc_t *softc;
2510         ipf_nat_softc_t *softn;
2511 {
2512         ipnat_t *n;
2513         int i = 0;
2514
2515         if (softn->ipf_nat_map_rules != NULL) {
2516                 bzero((char *)softn->ipf_nat_map_rules,
2517                       sizeof(*softn->ipf_nat_map_rules) *
2518                       softn->ipf_nat_maprules_sz);
2519         }
2520         if (softn->ipf_nat_rdr_rules != NULL) {
2521                 bzero((char *)softn->ipf_nat_rdr_rules,
2522                       sizeof(*softn->ipf_nat_rdr_rules) *
2523                       softn->ipf_nat_rdrrules_sz);
2524         }
2525
2526         while ((n = softn->ipf_nat_list) != NULL) {
2527                 ipf_nat_delrule(softc, softn, n, 0);
2528                 i++;
2529         }
2530 #if SOLARIS && !defined(INSTANCES)
2531         pfil_delayed_copy = 1;
2532 #endif
2533         return i;
2534 }
2535
2536
2537 /* ------------------------------------------------------------------------ */
2538 /* Function:    ipf_nat_delrule                                             */
2539 /* Returns:     Nil                                                         */
2540 /* Parameters:  softc(I) - pointer to soft context main structure           */
2541 /*              softn(I) - pointer to NAT context structure                 */
2542 /*              np(I)    - pointer to NAT rule to delete                    */
2543 /*              purge(I) - 1 == allow purge, 0 == prevent purge             */
2544 /* Locks:       WRITE(ipf_nat)                                              */
2545 /*                                                                          */
2546 /* Preventing "purge" from occuring is allowed because when all of the NAT  */
2547 /* rules are being removed, allowing the "purge" to walk through the list   */
2548 /* of NAT sessions, possibly multiple times, would be a large performance   */
2549 /* hit, on the order of O(N^2).                                             */
2550 /* ------------------------------------------------------------------------ */
2551 static void
2552 ipf_nat_delrule(softc, softn, np, purge)
2553         ipf_main_softc_t *softc;
2554         ipf_nat_softc_t *softn;
2555         ipnat_t *np;
2556         int purge;
2557 {
2558
2559         if (np->in_pnext != NULL) {
2560                 *np->in_pnext = np->in_next;
2561                 if (np->in_next != NULL)
2562                         np->in_next->in_pnext = np->in_pnext;
2563                 if (softn->ipf_nat_list_tail == &np->in_next)
2564                         softn->ipf_nat_list_tail = np->in_pnext;
2565         }
2566
2567         if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) {
2568                 nat_t *next;
2569                 nat_t *nat;
2570
2571                 for (next = softn->ipf_nat_instances; (nat = next) != NULL;) {
2572                         next = nat->nat_next;
2573                         if (nat->nat_ptr == np)
2574                                 ipf_nat_delete(softc, nat, NL_PURGE);
2575                 }
2576         }
2577
2578         if ((np->in_flags & IPN_DELETE) == 0) {
2579                 if (np->in_redir & NAT_REDIRECT) {
2580                         switch (np->in_v[0])
2581                         {
2582                         case 4 :
2583                                 ipf_nat_delrdr(softn, np);
2584                                 break;
2585 #ifdef USE_INET6
2586                         case 6 :
2587                                 ipf_nat6_delrdr(softn, np);
2588                                 break;
2589 #endif
2590                         }
2591                 }
2592                 if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) {
2593                         switch (np->in_v[0])
2594                         {
2595                         case 4 :
2596                                 ipf_nat_delmap(softn, np);
2597                                 break;
2598 #ifdef USE_INET6
2599                         case 6 :
2600                                 ipf_nat6_delmap(softn, np);
2601                                 break;
2602 #endif
2603                         }
2604                 }
2605         }
2606
2607         np->in_flags |= IPN_DELETE;
2608         ipf_nat_rule_deref(softc, &np);
2609 }
2610
2611
2612 /* ------------------------------------------------------------------------ */
2613 /* Function:    ipf_nat_newmap                                              */
2614 /* Returns:     int - -1 == error, 0 == success                             */
2615 /* Parameters:  fin(I) - pointer to packet information                      */
2616 /*              nat(I) - pointer to NAT entry                               */
2617 /*              ni(I)  - pointer to structure with misc. information needed */
2618 /*                       to create new NAT entry.                           */
2619 /*                                                                          */
2620 /* Given an empty NAT structure, populate it with new information about a   */
2621 /* new NAT session, as defined by the matching NAT rule.                    */
2622 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2623 /* to the new IP address for the translation.                               */
2624 /* ------------------------------------------------------------------------ */
2625 static int
2626 ipf_nat_newmap(fin, nat, ni)
2627         fr_info_t *fin;
2628         nat_t *nat;
2629         natinfo_t *ni;
2630 {
2631         ipf_main_softc_t *softc = fin->fin_main_soft;
2632         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2633         u_short st_port, dport, sport, port, sp, dp;
2634         struct in_addr in, inb;
2635         hostmap_t *hm;
2636         u_32_t flags;
2637         u_32_t st_ip;
2638         ipnat_t *np;
2639         nat_t *natl;
2640         int l;
2641
2642         /*
2643          * If it's an outbound packet which doesn't match any existing
2644          * record, then create a new port
2645          */
2646         l = 0;
2647         hm = NULL;
2648         np = ni->nai_np;
2649         st_ip = np->in_snip;
2650         st_port = np->in_spnext;
2651         flags = nat->nat_flags;
2652
2653         if (flags & IPN_ICMPQUERY) {
2654                 sport = fin->fin_data[1];
2655                 dport = 0;
2656         } else {
2657                 sport = htons(fin->fin_data[0]);
2658                 dport = htons(fin->fin_data[1]);
2659         }
2660
2661         /*
2662          * Do a loop until we either run out of entries to try or we find
2663          * a NAT mapping that isn't currently being used.  This is done
2664          * because the change to the source is not (usually) being fixed.
2665          */
2666         do {
2667                 port = 0;
2668                 in.s_addr = htonl(np->in_snip);
2669                 if (l == 0) {
2670                         /*
2671                          * Check to see if there is an existing NAT
2672                          * setup for this IP address pair.
2673                          */
2674                         hm = ipf_nat_hostmap(softn, np, fin->fin_src,
2675                                              fin->fin_dst, in, 0);
2676                         if (hm != NULL)
2677                                 in.s_addr = hm->hm_nsrcip.s_addr;
2678                 } else if ((l == 1) && (hm != NULL)) {
2679                         ipf_nat_hostmapdel(softc, &hm);
2680                 }
2681                 in.s_addr = ntohl(in.s_addr);
2682
2683                 nat->nat_hm = hm;
2684
2685                 if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) {
2686                         if (l > 0) {
2687                                 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1);
2688                                 return -1;
2689                         }
2690                 }
2691
2692                 if (np->in_redir == NAT_BIMAP &&
2693                     np->in_osrcmsk == np->in_nsrcmsk) {
2694                         /*
2695                          * map the address block in a 1:1 fashion
2696                          */
2697                         in.s_addr = np->in_nsrcaddr;
2698                         in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk;
2699                         in.s_addr = ntohl(in.s_addr);
2700
2701                 } else if (np->in_redir & NAT_MAPBLK) {
2702                         if ((l >= np->in_ppip) || ((l > 0) &&
2703                              !(flags & IPN_TCPUDP))) {
2704                                 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2);
2705                                 return -1;
2706                         }
2707                         /*
2708                          * map-block - Calculate destination address.
2709                          */
2710                         in.s_addr = ntohl(fin->fin_saddr);
2711                         in.s_addr &= ntohl(~np->in_osrcmsk);
2712                         inb.s_addr = in.s_addr;
2713                         in.s_addr /= np->in_ippip;
2714                         in.s_addr &= ntohl(~np->in_nsrcmsk);
2715                         in.s_addr += ntohl(np->in_nsrcaddr);
2716                         /*
2717                          * Calculate destination port.
2718                          */
2719                         if ((flags & IPN_TCPUDP) &&
2720                             (np->in_ppip != 0)) {
2721                                 port = ntohs(sport) + l;
2722                                 port %= np->in_ppip;
2723                                 port += np->in_ppip *
2724                                         (inb.s_addr % np->in_ippip);
2725                                 port += MAPBLK_MINPORT;
2726                                 port = htons(port);
2727                         }
2728
2729                 } else if ((np->in_nsrcaddr == 0) &&
2730                            (np->in_nsrcmsk == 0xffffffff)) {
2731                         i6addr_t in6;
2732
2733                         /*
2734                          * 0/32 - use the interface's IP address.
2735                          */
2736                         if ((l > 0) ||
2737                             ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
2738                                        &in6, NULL) == -1) {
2739                                 NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1);
2740                                 return -1;
2741                         }
2742                         in.s_addr = ntohl(in6.in4.s_addr);
2743
2744                 } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
2745                         /*
2746                          * 0/0 - use the original source address/port.
2747                          */
2748                         if (l > 0) {
2749                                 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3);
2750                                 return -1;
2751                         }
2752                         in.s_addr = ntohl(fin->fin_saddr);
2753
2754                 } else if ((np->in_nsrcmsk != 0xffffffff) &&
2755                            (np->in_spnext == 0) && ((l > 0) || (hm == NULL)))
2756                         np->in_snip++;
2757
2758                 natl = NULL;
2759
2760                 if ((flags & IPN_TCPUDP) &&
2761                     ((np->in_redir & NAT_MAPBLK) == 0) &&
2762                     (np->in_flags & IPN_AUTOPORTMAP)) {
2763                         /*
2764                          * "ports auto" (without map-block)
2765                          */
2766                         if ((l > 0) && (l % np->in_ppip == 0)) {
2767                                 if ((l > np->in_ppip) &&
2768                                     np->in_nsrcmsk != 0xffffffff)
2769                                         np->in_snip++;
2770                         }
2771                         if (np->in_ppip != 0) {
2772                                 port = ntohs(sport);
2773                                 port += (l % np->in_ppip);
2774                                 port %= np->in_ppip;
2775                                 port += np->in_ppip *
2776                                         (ntohl(fin->fin_saddr) %
2777                                          np->in_ippip);
2778                                 port += MAPBLK_MINPORT;
2779                                 port = htons(port);
2780                         }
2781
2782                 } else if (((np->in_redir & NAT_MAPBLK) == 0) &&
2783                            (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
2784                         /*
2785                          * Standard port translation.  Select next port.
2786                          */
2787                         if (np->in_flags & IPN_SEQUENTIAL) {
2788                                 port = np->in_spnext;
2789                         } else {
2790                                 port = ipf_random() % (np->in_spmax -
2791                                                        np->in_spmin + 1);
2792                                 port += np->in_spmin;
2793                         }
2794                         port = htons(port);
2795                         np->in_spnext++;
2796
2797                         if (np->in_spnext > np->in_spmax) {
2798                                 np->in_spnext = np->in_spmin;
2799                                 if (np->in_nsrcmsk != 0xffffffff)
2800                                         np->in_snip++;
2801                         }
2802                 }
2803
2804                 if (np->in_flags & IPN_SIPRANGE) {
2805                         if (np->in_snip > ntohl(np->in_nsrcmsk))
2806                                 np->in_snip = ntohl(np->in_nsrcaddr);
2807                 } else {
2808                         if ((np->in_nsrcmsk != 0xffffffff) &&
2809                             ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) >
2810                             ntohl(np->in_nsrcaddr))
2811                                 np->in_snip = ntohl(np->in_nsrcaddr) + 1;
2812                 }
2813
2814                 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
2815                         port = sport;
2816
2817                 /*
2818                  * Here we do a lookup of the connection as seen from
2819                  * the outside.  If an IP# pair already exists, try
2820                  * again.  So if you have A->B becomes C->B, you can
2821                  * also have D->E become C->E but not D->B causing
2822                  * another C->B.  Also take protocol and ports into
2823                  * account when determining whether a pre-existing
2824                  * NAT setup will cause an external conflict where
2825                  * this is appropriate.
2826                  */
2827                 inb.s_addr = htonl(in.s_addr);
2828                 sp = fin->fin_data[0];
2829                 dp = fin->fin_data[1];
2830                 fin->fin_data[0] = fin->fin_data[1];
2831                 fin->fin_data[1] = ntohs(port);
2832                 natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
2833                                         (u_int)fin->fin_p, fin->fin_dst, inb);
2834                 fin->fin_data[0] = sp;
2835                 fin->fin_data[1] = dp;
2836
2837                 /*
2838                  * Has the search wrapped around and come back to the
2839                  * start ?
2840                  */
2841                 if ((natl != NULL) &&
2842                     (np->in_spnext != 0) && (st_port == np->in_spnext) &&
2843                     (np->in_snip != 0) && (st_ip == np->in_snip)) {
2844                         NBUMPSIDED(1, ns_wrap);
2845                         return -1;
2846                 }
2847                 l++;
2848         } while (natl != NULL);
2849
2850         /* Setup the NAT table */
2851         nat->nat_osrcip = fin->fin_src;
2852         nat->nat_nsrcaddr = htonl(in.s_addr);
2853         nat->nat_odstip = fin->fin_dst;
2854         nat->nat_ndstip = fin->fin_dst;
2855         if (nat->nat_hm == NULL)
2856                 nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
2857                                               fin->fin_dst, nat->nat_nsrcip,
2858                                               0);
2859
2860         if (flags & IPN_TCPUDP) {
2861                 nat->nat_osport = sport;
2862                 nat->nat_nsport = port; /* sport */
2863                 nat->nat_odport = dport;
2864                 nat->nat_ndport = dport;
2865                 ((tcphdr_t *)fin->fin_dp)->th_sport = port;
2866         } else if (flags & IPN_ICMPQUERY) {
2867                 nat->nat_oicmpid = fin->fin_data[1];
2868                 ((icmphdr_t *)fin->fin_dp)->icmp_id = port;
2869                 nat->nat_nicmpid = port;
2870         }
2871         return 0;
2872 }
2873
2874
2875 /* ------------------------------------------------------------------------ */
2876 /* Function:    ipf_nat_newrdr                                              */
2877 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
2878 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
2879 /* Parameters:  fin(I) - pointer to packet information                      */
2880 /*              nat(I) - pointer to NAT entry                               */
2881 /*              ni(I)  - pointer to structure with misc. information needed */
2882 /*                       to create new NAT entry.                           */
2883 /*                                                                          */
2884 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2885 /* to the new IP address for the translation.                               */
2886 /* ------------------------------------------------------------------------ */
2887 static int
2888 ipf_nat_newrdr(fin, nat, ni)
2889         fr_info_t *fin;
2890         nat_t *nat;
2891         natinfo_t *ni;
2892 {
2893         ipf_main_softc_t *softc = fin->fin_main_soft;
2894         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2895         u_short nport, dport, sport;
2896         struct in_addr in, inb;
2897         u_short sp, dp;
2898         hostmap_t *hm;
2899         u_32_t flags;
2900         ipnat_t *np;
2901         nat_t *natl;
2902         int move;
2903
2904         move = 1;
2905         hm = NULL;
2906         in.s_addr = 0;
2907         np = ni->nai_np;
2908         flags = nat->nat_flags;
2909
2910         if (flags & IPN_ICMPQUERY) {
2911                 dport = fin->fin_data[1];
2912                 sport = 0;
2913         } else {
2914                 sport = htons(fin->fin_data[0]);
2915                 dport = htons(fin->fin_data[1]);
2916         }
2917
2918         /* TRACE sport, dport */
2919
2920
2921         /*
2922          * If the matching rule has IPN_STICKY set, then we want to have the
2923          * same rule kick in as before.  Why would this happen?  If you have
2924          * a collection of rdr rules with "round-robin sticky", the current
2925          * packet might match a different one to the previous connection but
2926          * we want the same destination to be used.
2927          */
2928         if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
2929             ((np->in_flags & IPN_STICKY) != 0)) {
2930                 hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst,
2931                                      in, (u_32_t)dport);
2932                 if (hm != NULL) {
2933                         in.s_addr = ntohl(hm->hm_ndstip.s_addr);
2934                         np = hm->hm_ipnat;
2935                         ni->nai_np = np;
2936                         move = 0;
2937                         ipf_nat_hostmapdel(softc, &hm);
2938                 }
2939         }
2940
2941         /*
2942          * Otherwise, it's an inbound packet. Most likely, we don't
2943          * want to rewrite source ports and source addresses. Instead,
2944          * we want to rewrite to a fixed internal address and fixed
2945          * internal port.
2946          */
2947         if (np->in_flags & IPN_SPLIT) {
2948                 in.s_addr = np->in_dnip;
2949                 inb.s_addr = htonl(in.s_addr);
2950
2951                 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
2952                         hm = ipf_nat_hostmap(softn, NULL, fin->fin_src,
2953                                              fin->fin_dst, inb, (u_32_t)dport);
2954                         if (hm != NULL) {
2955                                 in.s_addr = hm->hm_ndstip.s_addr;
2956                                 move = 0;
2957                         }
2958                 }
2959
2960                 if (hm == NULL || hm->hm_ref == 1) {
2961                         if (np->in_ndstaddr == htonl(in.s_addr)) {
2962                                 np->in_dnip = ntohl(np->in_ndstmsk);
2963                                 move = 0;
2964                         } else {
2965                                 np->in_dnip = ntohl(np->in_ndstaddr);
2966                         }
2967                 }
2968                 if (hm != NULL)
2969                         ipf_nat_hostmapdel(softc, &hm);
2970
2971         } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
2972                 i6addr_t in6;
2973
2974                 /*
2975                  * 0/32 - use the interface's IP address.
2976                  */
2977                 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
2978                                &in6, NULL) == -1) {
2979                         NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
2980                         return -1;
2981                 }
2982                 in.s_addr = ntohl(in6.in4.s_addr);
2983
2984         } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) {
2985                 /*
2986                  * 0/0 - use the original destination address/port.
2987                  */
2988                 in.s_addr = ntohl(fin->fin_daddr);
2989
2990         } else if (np->in_redir == NAT_BIMAP &&
2991                    np->in_ndstmsk == np->in_odstmsk) {
2992                 /*
2993                  * map the address block in a 1:1 fashion
2994                  */
2995                 in.s_addr = np->in_ndstaddr;
2996                 in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk;
2997                 in.s_addr = ntohl(in.s_addr);
2998         } else {
2999                 in.s_addr = ntohl(np->in_ndstaddr);
3000         }
3001
3002         if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
3003                 nport = dport;
3004         else {
3005                 /*
3006                  * Whilst not optimized for the case where
3007                  * pmin == pmax, the gain is not significant.
3008                  */
3009                 if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
3010                     (np->in_odport != np->in_dtop)) {
3011                         nport = ntohs(dport) - np->in_odport + np->in_dpmax;
3012                         nport = htons(nport);
3013                 } else {
3014                         nport = htons(np->in_dpnext);
3015                         np->in_dpnext++;
3016                         if (np->in_dpnext > np->in_dpmax)
3017                                 np->in_dpnext = np->in_dpmin;
3018                 }
3019         }
3020
3021         /*
3022          * When the redirect-to address is set to 0.0.0.0, just
3023          * assume a blank `forwarding' of the packet.  We don't
3024          * setup any translation for this either.
3025          */
3026         if (in.s_addr == 0) {
3027                 if (nport == dport) {
3028                         NBUMPSIDED(0, ns_xlate_null);
3029                         return -1;
3030                 }
3031                 in.s_addr = ntohl(fin->fin_daddr);
3032         }
3033
3034         /*
3035          * Check to see if this redirect mapping already exists and if
3036          * it does, return "failure" (allowing it to be created will just
3037          * cause one or both of these "connections" to stop working.)
3038          */
3039         inb.s_addr = htonl(in.s_addr);
3040         sp = fin->fin_data[0];
3041         dp = fin->fin_data[1];
3042         fin->fin_data[1] = fin->fin_data[0];
3043         fin->fin_data[0] = ntohs(nport);
3044         natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
3045                              (u_int)fin->fin_p, inb, fin->fin_src);
3046         fin->fin_data[0] = sp;
3047         fin->fin_data[1] = dp;
3048         if (natl != NULL) {
3049                 DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl);
3050                 NBUMPSIDE(0, ns_xlate_exists);
3051                 return -1;
3052         }
3053
3054         inb.s_addr = htonl(in.s_addr);
3055         nat->nat_ndstaddr = htonl(in.s_addr);
3056         nat->nat_odstip = fin->fin_dst;
3057         nat->nat_nsrcip = fin->fin_src;
3058         nat->nat_osrcip = fin->fin_src;
3059         if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
3060                 nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
3061                                               fin->fin_dst, inb, (u_32_t)dport);
3062
3063         if (flags & IPN_TCPUDP) {
3064                 nat->nat_odport = dport;
3065                 nat->nat_ndport = nport;
3066                 nat->nat_osport = sport;
3067                 nat->nat_nsport = sport;
3068                 ((tcphdr_t *)fin->fin_dp)->th_dport = nport;
3069         } else if (flags & IPN_ICMPQUERY) {
3070                 nat->nat_oicmpid = fin->fin_data[1];
3071                 ((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
3072                 nat->nat_nicmpid = nport;
3073         }
3074
3075         return move;
3076 }
3077
3078 /* ------------------------------------------------------------------------ */
3079 /* Function:    ipf_nat_add                                                 */
3080 /* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
3081 /*                       else pointer to new NAT structure                  */
3082 /* Parameters:  fin(I)       - pointer to packet information                */
3083 /*              np(I)        - pointer to NAT rule                          */
3084 /*              natsave(I)   - pointer to where to store NAT struct pointer */
3085 /*              flags(I)     - flags describing the current packet          */
3086 /*              direction(I) - direction of packet (in/out)                 */
3087 /* Write Lock:  ipf_nat                                                     */
3088 /*                                                                          */
3089 /* Attempts to create a new NAT entry.  Does not actually change the packet */
3090 /* in any way.                                                              */
3091 /*                                                                          */
3092 /* This fucntion is in three main parts: (1) deal with creating a new NAT   */
3093 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
3094 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
3095 /* and (3) building that structure and putting it into the NAT table(s).    */
3096 /*                                                                          */
3097 /* NOTE: natsave should NOT be used top point back to an ipstate_t struct   */
3098 /*       as it can result in memory being corrupted.                        */
3099 /* ------------------------------------------------------------------------ */
3100 nat_t *
3101 ipf_nat_add(fin, np, natsave, flags, direction)
3102         fr_info_t *fin;
3103         ipnat_t *np;
3104         nat_t **natsave;
3105         u_int flags;
3106         int direction;
3107 {
3108         ipf_main_softc_t *softc = fin->fin_main_soft;
3109         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3110         hostmap_t *hm = NULL;
3111         nat_t *nat, *natl;
3112         natstat_t *nsp;
3113         u_int nflags;
3114         natinfo_t ni;
3115         int move;
3116
3117         nsp = &softn->ipf_nat_stats;
3118
3119         if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
3120             softn->ipf_nat_table_wm_high) {
3121                 softn->ipf_nat_doflush = 1;
3122         }
3123
3124         if (nsp->ns_active >= softn->ipf_nat_table_max) {
3125                 NBUMPSIDED(fin->fin_out, ns_table_max);
3126                 return NULL;
3127         }
3128
3129         move = 1;
3130         nflags = np->in_flags & flags;
3131         nflags &= NAT_FROMRULE;
3132
3133         ni.nai_np = np;
3134         ni.nai_dport = 0;
3135         ni.nai_sport = 0;
3136
3137         /* Give me a new nat */
3138         KMALLOC(nat, nat_t *);
3139         if (nat == NULL) {
3140                 NBUMPSIDED(fin->fin_out, ns_memfail);
3141                 /*
3142                  * Try to automatically tune the max # of entries in the
3143                  * table allowed to be less than what will cause kmem_alloc()
3144                  * to fail and try to eliminate panics due to out of memory
3145                  * conditions arising.
3146                  */
3147                 if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
3148                     (nsp->ns_active > 100)) {
3149                         softn->ipf_nat_table_max = nsp->ns_active - 100;
3150                         printf("table_max reduced to %d\n",
3151                                 softn->ipf_nat_table_max);
3152                 }
3153                 return NULL;
3154         }
3155
3156         if (flags & IPN_ICMPQUERY) {
3157                 /*
3158                  * In the ICMP query NAT code, we translate the ICMP id fields
3159                  * to make them unique. This is indepedent of the ICMP type
3160                  * (e.g. in the unlikely event that a host sends an echo and
3161                  * an tstamp request with the same id, both packets will have
3162                  * their ip address/id field changed in the same way).
3163                  */
3164                 /* The icmp_id field is used by the sender to identify the
3165                  * process making the icmp request. (the receiver justs
3166                  * copies it back in its response). So, it closely matches
3167                  * the concept of source port. We overlay sport, so we can
3168                  * maximally reuse the existing code.
3169                  */
3170                 ni.nai_sport = fin->fin_data[1];
3171                 ni.nai_dport = 0;
3172         }
3173
3174         bzero((char *)nat, sizeof(*nat));
3175         nat->nat_flags = flags;
3176         nat->nat_redir = np->in_redir;
3177         nat->nat_dir = direction;
3178         nat->nat_pr[0] = fin->fin_p;
3179         nat->nat_pr[1] = fin->fin_p;
3180
3181         /*
3182          * Search the current table for a match and create a new mapping
3183          * if there is none found.
3184          */
3185         if (np->in_redir & NAT_DIVERTUDP) {
3186                 move = ipf_nat_newdivert(fin, nat, &ni);
3187
3188         } else if (np->in_redir & NAT_REWRITE) {
3189                 move = ipf_nat_newrewrite(fin, nat, &ni);
3190
3191         } else if (direction == NAT_OUTBOUND) {
3192                 /*
3193                  * We can now arrange to call this for the same connection
3194                  * because ipf_nat_new doesn't protect the code path into
3195                  * this function.
3196                  */
3197                 natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
3198                                      fin->fin_src, fin->fin_dst);
3199                 if (natl != NULL) {
3200                         KFREE(nat);
3201                         nat = natl;
3202                         goto done;
3203                 }
3204
3205                 move = ipf_nat_newmap(fin, nat, &ni);
3206         } else {
3207                 /*
3208                  * NAT_INBOUND is used for redirects rules
3209                  */
3210                 natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
3211                                         fin->fin_src, fin->fin_dst);
3212                 if (natl != NULL) {
3213                         KFREE(nat);
3214                         nat = natl;
3215                         goto done;
3216                 }
3217
3218                 move = ipf_nat_newrdr(fin, nat, &ni);
3219         }
3220         if (move == -1)
3221                 goto badnat;
3222
3223         np = ni.nai_np;
3224
3225         nat->nat_mssclamp = np->in_mssclamp;
3226         nat->nat_me = natsave;
3227         nat->nat_fr = fin->fin_fr;
3228         nat->nat_rev = fin->fin_rev;
3229         nat->nat_ptr = np;
3230         nat->nat_dlocal = np->in_dlocal;
3231
3232         if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
3233                 if (ipf_proxy_new(fin, nat) == -1) {
3234                         NBUMPSIDED(fin->fin_out, ns_appr_fail);
3235                         goto badnat;
3236                 }
3237         }
3238
3239         nat->nat_ifps[0] = np->in_ifps[0];
3240         if (np->in_ifps[0] != NULL) {
3241                 COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
3242         }
3243
3244         nat->nat_ifps[1] = np->in_ifps[1];
3245         if (np->in_ifps[1] != NULL) {
3246                 COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
3247         }
3248
3249         if (ipf_nat_finalise(fin, nat) == -1) {
3250                 goto badnat;
3251         }
3252
3253         np->in_use++;
3254
3255         if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
3256                 if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
3257                         ipf_nat_delrdr(softn, np);
3258                         ipf_nat_addrdr(softn, np);
3259                 } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
3260                         ipf_nat_delmap(softn, np);
3261                         ipf_nat_addmap(softn, np);
3262                 }
3263         }
3264
3265         if (flags & SI_WILDP)
3266                 nsp->ns_wilds++;
3267         nsp->ns_proto[nat->nat_pr[0]]++;
3268
3269         goto done;
3270 badnat:
3271         DT2(ns_badnatnew, fr_info_t *, fin, nat_t *, nat);
3272         NBUMPSIDE(fin->fin_out, ns_badnatnew);
3273         if ((hm = nat->nat_hm) != NULL)
3274                 ipf_nat_hostmapdel(softc, &hm);
3275         KFREE(nat);
3276         nat = NULL;
3277 done:
3278         if (nat != NULL && np != NULL)
3279                 np->in_hits++;
3280         if (natsave != NULL)
3281                 *natsave = nat;
3282         return nat;
3283 }
3284
3285
3286 /* ------------------------------------------------------------------------ */
3287 /* Function:    ipf_nat_finalise                                            */
3288 /* Returns:     int - 0 == sucess, -1 == failure                            */
3289 /* Parameters:  fin(I) - pointer to packet information                      */
3290 /*              nat(I) - pointer to NAT entry                               */
3291 /* Write Lock:  ipf_nat                                                     */
3292 /*                                                                          */
3293 /* This is the tail end of constructing a new NAT entry and is the same     */
3294 /* for both IPv4 and IPv6.                                                  */
3295 /* ------------------------------------------------------------------------ */
3296 /*ARGSUSED*/
3297 static int
3298 ipf_nat_finalise(fin, nat)
3299         fr_info_t *fin;
3300         nat_t *nat;
3301 {
3302         ipf_main_softc_t *softc = fin->fin_main_soft;
3303         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3304         u_32_t sum1, sum2, sumd;
3305         frentry_t *fr;
3306         u_32_t flags;
3307 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
3308         qpktinfo_t *qpi = fin->fin_qpi;
3309 #endif
3310
3311         flags = nat->nat_flags;
3312
3313         switch (nat->nat_pr[0])
3314         {
3315         case IPPROTO_ICMP :
3316                 sum1 = LONG_SUM(ntohs(nat->nat_oicmpid));
3317                 sum2 = LONG_SUM(ntohs(nat->nat_nicmpid));
3318                 CALC_SUMD(sum1, sum2, sumd);
3319                 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
3320
3321                 break;
3322
3323         default :
3324                 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \
3325                                 ntohs(nat->nat_osport));
3326                 sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \
3327                                 ntohs(nat->nat_nsport));
3328                 CALC_SUMD(sum1, sum2, sumd);
3329                 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
3330
3331                 sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \
3332                                 ntohs(nat->nat_odport));
3333                 sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \
3334                                 ntohs(nat->nat_ndport));
3335                 CALC_SUMD(sum1, sum2, sumd);
3336                 nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
3337                 break;
3338         }
3339
3340         /*
3341          * Compute the partial checksum, just in case.
3342          * This is only ever placed into outbound packets so care needs
3343          * to be taken over which pair of addresses are used.
3344          */
3345         if (nat->nat_dir == NAT_OUTBOUND) {
3346                 sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
3347                 sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr));
3348         } else {
3349                 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
3350                 sum1 += LONG_SUM(ntohl(nat->nat_odstaddr));
3351         }
3352         sum1 += nat->nat_pr[1];
3353         nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
3354
3355         sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
3356         sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
3357         CALC_SUMD(sum1, sum2, sumd);
3358         nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
3359
3360         sum1 = LONG_SUM(ntohl(nat->nat_odstaddr));
3361         sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
3362         CALC_SUMD(sum1, sum2, sumd);
3363         nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16);
3364
3365         nat->nat_v[0] = 4;
3366         nat->nat_v[1] = 4;
3367
3368         if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
3369                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
3370         }
3371
3372         if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
3373                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
3374         }
3375
3376         if ((nat->nat_flags & SI_CLONE) == 0)
3377                 nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
3378
3379         if (ipf_nat_insert(softc, softn, nat) == 0) {
3380                 if (softn->ipf_nat_logging)
3381                         ipf_nat_log(softc, softn, nat, NL_NEW);
3382                 fr = nat->nat_fr;
3383                 if (fr != NULL) {
3384                         MUTEX_ENTER(&fr->fr_lock);
3385                         fr->fr_ref++;
3386                         MUTEX_EXIT(&fr->fr_lock);
3387                 }
3388                 return 0;
3389         }
3390
3391         NBUMPSIDED(fin->fin_out, ns_unfinalised);
3392         /*
3393          * nat_insert failed, so cleanup time...
3394          */
3395         if (nat->nat_sync != NULL)
3396                 ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
3397         return -1;
3398 }
3399
3400
3401 /* ------------------------------------------------------------------------ */
3402 /* Function:    ipf_nat_insert                                              */
3403 /* Returns:     int - 0 == sucess, -1 == failure                            */
3404 /* Parameters:  softc(I) - pointer to soft context main structure           */
3405 /*              softn(I) - pointer to NAT context structure                 */
3406 /*              nat(I) - pointer to NAT structure                           */
3407 /* Write Lock:  ipf_nat                                                     */
3408 /*                                                                          */
3409 /* Insert a NAT entry into the hash tables for searching and add it to the  */
3410 /* list of active NAT entries.  Adjust global counters when complete.       */
3411 /* ------------------------------------------------------------------------ */
3412 int
3413 ipf_nat_insert(softc, softn, nat)
3414         ipf_main_softc_t *softc;
3415         ipf_nat_softc_t *softn;
3416         nat_t *nat;
3417 {
3418         u_int hv0, hv1;
3419         u_int sp, dp;
3420         ipnat_t *in;
3421
3422         /*
3423          * Try and return an error as early as possible, so calculate the hash
3424          * entry numbers first and then proceed.
3425          */
3426         if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
3427                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3428                         sp = nat->nat_osport;
3429                         dp = nat->nat_odport;
3430                 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3431                         sp = 0;
3432                         dp = nat->nat_oicmpid;
3433                 } else {
3434                         sp = 0;
3435                         dp = 0;
3436                 }
3437                 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff);
3438                 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff);
3439                 /*
3440                  * TRACE nat_osrcaddr, nat_osport, nat_odstaddr,
3441                  * nat_odport, hv0
3442                  */
3443
3444                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3445                         sp = nat->nat_nsport;
3446                         dp = nat->nat_ndport;
3447                 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3448                         sp = 0;
3449                         dp = nat->nat_nicmpid;
3450                 } else {
3451                         sp = 0;
3452                         dp = 0;
3453                 }
3454                 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff);
3455                 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff);
3456                 /*
3457                  * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr,
3458                  * nat_ndport, hv1
3459                  */
3460         } else {
3461                 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff);
3462                 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff);
3463                 /* TRACE nat_osrcaddr, nat_odstaddr, hv0 */
3464
3465                 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff);
3466                 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff);
3467                 /* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */
3468         }
3469
3470         nat->nat_hv[0] = hv0;
3471         nat->nat_hv[1] = hv1;
3472
3473         MUTEX_INIT(&nat->nat_lock, "nat entry lock");
3474
3475         in = nat->nat_ptr;
3476         nat->nat_ref = nat->nat_me ? 2 : 1;
3477
3478         nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
3479         nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4);
3480
3481         if (nat->nat_ifnames[1][0] != '\0') {
3482                 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3483                 nat->nat_ifps[1] = ipf_resolvenic(softc,
3484                                                   nat->nat_ifnames[1], 4);
3485         } else if (in->in_ifnames[1] != -1) {
3486                 char *name;
3487
3488                 name = in->in_names + in->in_ifnames[1];
3489                 if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
3490                         (void) strncpy(nat->nat_ifnames[1],
3491                                        nat->nat_ifnames[0], LIFNAMSIZ);
3492                         nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3493                         nat->nat_ifps[1] = nat->nat_ifps[0];
3494                 }
3495         }
3496         if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
3497                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
3498         }
3499         if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
3500                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
3501         }
3502
3503         return ipf_nat_hashtab_add(softc, softn, nat);
3504 }
3505
3506
3507 /* ------------------------------------------------------------------------ */
3508 /* Function:    ipf_nat_hashtab_add                                         */
3509 /* Parameters:  softc(I) - pointer to soft context main structure           */
3510 /*              softn(I) - pointer to NAT context structure                 */
3511 /*              nat(I) - pointer to NAT structure                           */
3512 /*                                                                          */
3513 /* Handle the insertion of a NAT entry into the table/list.                 */
3514 /* ------------------------------------------------------------------------ */
3515 int
3516 ipf_nat_hashtab_add(softc, softn, nat)
3517         ipf_main_softc_t *softc;
3518         ipf_nat_softc_t *softn;
3519         nat_t *nat;
3520 {
3521         nat_t **natp;
3522         u_int hv0;
3523         u_int hv1;
3524
3525         hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
3526         hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
3527
3528         if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
3529                 u_int swap;
3530
3531                 swap = hv0;
3532                 hv0 = hv1;
3533                 hv1 = swap;
3534         }
3535
3536         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >=
3537             softn->ipf_nat_maxbucket) {
3538                 DT1(ns_bucket_max_0, int,
3539                     softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]);
3540                 NBUMPSIDE(0, ns_bucket_max);
3541                 return -1;
3542         }
3543
3544         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >=
3545             softn->ipf_nat_maxbucket) {
3546                 DT1(ns_bucket_max_1, int,
3547                     softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]);
3548                 NBUMPSIDE(1, ns_bucket_max);
3549                 return -1;
3550         }
3551
3552         /*
3553          * The ordering of operations in the list and hash table insertion
3554          * is very important.  The last operation for each task should be
3555          * to update the top of the list, after all the "nexts" have been
3556          * done so that walking the list while it is being done does not
3557          * find strange pointers.
3558          *
3559          * Global list of NAT instances
3560          */
3561         nat->nat_next = softn->ipf_nat_instances;
3562         nat->nat_pnext = &softn->ipf_nat_instances;
3563         if (softn->ipf_nat_instances)
3564                 softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
3565         softn->ipf_nat_instances = nat;
3566
3567         /*
3568          * Inbound hash table.
3569          */
3570         natp = &softn->ipf_nat_table[0][hv0];
3571         nat->nat_phnext[0] = natp;
3572         nat->nat_hnext[0] = *natp;
3573         if (*natp) {
3574                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
3575         } else {
3576                 NBUMPSIDE(0, ns_inuse);
3577         }
3578         *natp = nat;
3579         NBUMPSIDE(0, ns_bucketlen[hv0]);
3580
3581         /*
3582          * Outbound hash table.
3583          */
3584         natp = &softn->ipf_nat_table[1][hv1];
3585         nat->nat_phnext[1] = natp;
3586         nat->nat_hnext[1] = *natp;
3587         if (*natp)
3588                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
3589         else {
3590                 NBUMPSIDE(1, ns_inuse);
3591         }
3592         *natp = nat;
3593         NBUMPSIDE(1, ns_bucketlen[hv1]);
3594
3595         ipf_nat_setqueue(softc, softn, nat);
3596
3597         if (nat->nat_dir & NAT_OUTBOUND) {
3598                 NBUMPSIDE(1, ns_added);
3599         } else {
3600                 NBUMPSIDE(0, ns_added);
3601         }
3602         softn->ipf_nat_stats.ns_active++;
3603         return 0;
3604 }
3605
3606
3607 /* ------------------------------------------------------------------------ */
3608 /* Function:    ipf_nat_icmperrorlookup                                     */
3609 /* Returns:     nat_t* - point to matching NAT structure                    */
3610 /* Parameters:  fin(I) - pointer to packet information                      */
3611 /*              dir(I) - direction of packet (in/out)                       */
3612 /*                                                                          */
3613 /* Check if the ICMP error message is related to an existing TCP, UDP or    */
3614 /* ICMP query nat entry.  It is assumed that the packet is already of the   */
3615 /* the required length.                                                     */
3616 /* ------------------------------------------------------------------------ */
3617 nat_t *
3618 ipf_nat_icmperrorlookup(fin, dir)
3619         fr_info_t *fin;
3620         int dir;
3621 {
3622         ipf_main_softc_t *softc = fin->fin_main_soft;
3623         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3624         int flags = 0, type, minlen;
3625         icmphdr_t *icmp, *orgicmp;
3626         nat_stat_side_t *nside;
3627         tcphdr_t *tcp = NULL;
3628         u_short data[2];
3629         nat_t *nat;
3630         ip_t *oip;
3631         u_int p;
3632
3633         icmp = fin->fin_dp;
3634         type = icmp->icmp_type;
3635         nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
3636         /*
3637          * Does it at least have the return (basic) IP header ?
3638          * Only a basic IP header (no options) should be with an ICMP error
3639          * header.  Also, if it's not an error type, then return.
3640          */
3641         if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) {
3642                 ATOMIC_INCL(nside->ns_icmp_basic);
3643                 return NULL;
3644         }
3645
3646         /*
3647          * Check packet size
3648          */
3649         oip = (ip_t *)((char *)fin->fin_dp + 8);
3650         minlen = IP_HL(oip) << 2;
3651         if ((minlen < sizeof(ip_t)) ||
3652             (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) {
3653                 ATOMIC_INCL(nside->ns_icmp_size);
3654                 return NULL;
3655         }
3656
3657         /*
3658          * Is the buffer big enough for all of it ?  It's the size of the IP
3659          * header claimed in the encapsulated part which is of concern.  It
3660          * may be too big to be in this buffer but not so big that it's
3661          * outside the ICMP packet, leading to TCP deref's causing problems.
3662          * This is possible because we don't know how big oip_hl is when we
3663          * do the pullup early in ipf_check() and thus can't gaurantee it is
3664          * all here now.
3665          */
3666 #ifdef  ipf_nat_KERNEL
3667         {
3668         mb_t *m;
3669
3670         m = fin->fin_m;
3671 # if defined(MENTAT)
3672         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3673             (char *)m->b_wptr) {
3674                 ATOMIC_INCL(nside->ns_icmp_mbuf);
3675                 return NULL;
3676         }
3677 # else
3678         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3679             (char *)fin->fin_ip + M_LEN(m)) {
3680                 ATOMIC_INCL(nside->ns_icmp_mbuf);
3681                 return NULL;
3682         }
3683 # endif
3684         }
3685 #endif
3686
3687         if (fin->fin_daddr != oip->ip_src.s_addr) {
3688                 ATOMIC_INCL(nside->ns_icmp_address);
3689                 return NULL;
3690         }
3691
3692         p = oip->ip_p;
3693         if (p == IPPROTO_TCP)
3694                 flags = IPN_TCP;
3695         else if (p == IPPROTO_UDP)
3696                 flags = IPN_UDP;
3697         else if (p == IPPROTO_ICMP) {
3698                 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3699
3700                 /* see if this is related to an ICMP query */
3701                 if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) {
3702                         data[0] = fin->fin_data[0];
3703                         data[1] = fin->fin_data[1];
3704                         fin->fin_data[0] = 0;
3705                         fin->fin_data[1] = orgicmp->icmp_id;
3706
3707                         flags = IPN_ICMPERR|IPN_ICMPQUERY;
3708                         /*
3709                          * NOTE : dir refers to the direction of the original
3710                          *        ip packet. By definition the icmp error
3711                          *        message flows in the opposite direction.
3712                          */
3713                         if (dir == NAT_INBOUND)
3714                                 nat = ipf_nat_inlookup(fin, flags, p,
3715                                                        oip->ip_dst,
3716                                                        oip->ip_src);
3717                         else
3718                                 nat = ipf_nat_outlookup(fin, flags, p,
3719                                                         oip->ip_dst,
3720                                                         oip->ip_src);
3721                         fin->fin_data[0] = data[0];
3722                         fin->fin_data[1] = data[1];
3723                         return nat;
3724                 }
3725         }
3726
3727         if (flags & IPN_TCPUDP) {
3728                 minlen += 8;            /* + 64bits of data to get ports */
3729                 /* TRACE (fin,minlen) */
3730                 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
3731                         ATOMIC_INCL(nside->ns_icmp_short);
3732                         return NULL;
3733                 }
3734
3735                 data[0] = fin->fin_data[0];
3736                 data[1] = fin->fin_data[1];
3737                 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3738                 fin->fin_data[0] = ntohs(tcp->th_dport);
3739                 fin->fin_data[1] = ntohs(tcp->th_sport);
3740
3741                 if (dir == NAT_INBOUND) {
3742                         nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst,
3743                                                oip->ip_src);
3744                 } else {
3745                         nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst,
3746                                             oip->ip_src);
3747                 }
3748                 fin->fin_data[0] = data[0];
3749                 fin->fin_data[1] = data[1];
3750                 return nat;
3751         }
3752         if (dir == NAT_INBOUND)
3753                 nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3754         else
3755                 nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3756
3757         return nat;
3758 }
3759
3760
3761 /* ------------------------------------------------------------------------ */
3762 /* Function:    ipf_nat_icmperror                                           */
3763 /* Returns:     nat_t* - point to matching NAT structure                    */
3764 /* Parameters:  fin(I)    - pointer to packet information                   */
3765 /*              nflags(I) - NAT flags for this packet                       */
3766 /*              dir(I)    - direction of packet (in/out)                    */
3767 /*                                                                          */
3768 /* Fix up an ICMP packet which is an error message for an existing NAT      */
3769 /* session.  This will correct both packet header data and checksums.       */
3770 /*                                                                          */
3771 /* This should *ONLY* be used for incoming ICMP error packets to make sure  */
3772 /* a NAT'd ICMP packet gets correctly recognised.                           */
3773 /* ------------------------------------------------------------------------ */
3774 nat_t *
3775 ipf_nat_icmperror(fin, nflags, dir)
3776         fr_info_t *fin;
3777         u_int *nflags;
3778         int dir;
3779 {
3780         ipf_main_softc_t *softc = fin->fin_main_soft;
3781         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3782         u_32_t sum1, sum2, sumd, sumd2;
3783         struct in_addr a1, a2, a3, a4;
3784         int flags, dlen, odst;
3785         icmphdr_t *icmp;
3786         u_short *csump;
3787         tcphdr_t *tcp;
3788         nat_t *nat;
3789         ip_t *oip;
3790         void *dp;
3791
3792         if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
3793                 NBUMPSIDED(fin->fin_out, ns_icmp_short);
3794                 return NULL;
3795         }
3796
3797         /*
3798          * ipf_nat_icmperrorlookup() will return NULL for `defective' packets.
3799          */
3800         if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) {
3801                 NBUMPSIDED(fin->fin_out, ns_icmp_notfound);
3802                 return NULL;
3803         }
3804
3805         tcp = NULL;
3806         csump = NULL;
3807         flags = 0;
3808         sumd2 = 0;
3809         *nflags = IPN_ICMPERR;
3810         icmp = fin->fin_dp;
3811         oip = (ip_t *)&icmp->icmp_ip;
3812         dp = (((char *)oip) + (IP_HL(oip) << 2));
3813         if (oip->ip_p == IPPROTO_TCP) {
3814                 tcp = (tcphdr_t *)dp;
3815                 csump = (u_short *)&tcp->th_sum;
3816                 flags = IPN_TCP;
3817         } else if (oip->ip_p == IPPROTO_UDP) {
3818                 udphdr_t *udp;
3819
3820                 udp = (udphdr_t *)dp;
3821                 tcp = (tcphdr_t *)dp;
3822                 csump = (u_short *)&udp->uh_sum;
3823                 flags = IPN_UDP;
3824         } else if (oip->ip_p == IPPROTO_ICMP)
3825                 flags = IPN_ICMPQUERY;
3826         dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
3827
3828         /*
3829          * Need to adjust ICMP header to include the real IP#'s and
3830          * port #'s.  Only apply a checksum change relative to the
3831          * IP address change as it will be modified again in ipf_nat_checkout
3832          * for both address and port.  Two checksum changes are
3833          * necessary for the two header address changes.  Be careful
3834          * to only modify the checksum once for the port # and twice
3835          * for the IP#.
3836          */
3837
3838         /*
3839          * Step 1
3840          * Fix the IP addresses in the offending IP packet. You also need
3841          * to adjust the IP header checksum of that offending IP packet.
3842          *
3843          * Normally, you would expect that the ICMP checksum of the
3844          * ICMP error message needs to be adjusted as well for the
3845          * IP address change in oip.
3846          * However, this is a NOP, because the ICMP checksum is
3847          * calculated over the complete ICMP packet, which includes the
3848          * changed oip IP addresses and oip->ip_sum. However, these
3849          * two changes cancel each other out (if the delta for
3850          * the IP address is x, then the delta for ip_sum is minus x),
3851          * so no change in the icmp_cksum is necessary.
3852          *
3853          * Inbound ICMP
3854          * ------------
3855          * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3856          * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
3857          * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(b)=nat_newdstip
3858          *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(b)=nat_olddstip
3859          *
3860          * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3861          * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3862          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3863          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3864          *
3865          * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3866          * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
3867          * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(d)=nat_newdstip
3868          *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(d)=nat_olddstip
3869          *
3870          * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3871          * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3872          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3873          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3874          *
3875          * Outbound ICMP
3876          * -------------
3877          * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3878          * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3879          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3880          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3881          *
3882          * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3883          * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
3884          * - OIP_SRC(a)=nat_newsrcip,          OIP_DST(c)=nat_newdstip
3885          *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3886          *
3887          * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3888          * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
3889          * - OIP_SRC(c)=nat_olddstip,          OIP_DST(d)=nat_oldsrcip
3890          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3891          *
3892          * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3893          * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
3894          * - OIP_SRC(b)=nat_newsrcip,          OIP_DST(a)=nat_newdstip
3895          *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3896          */
3897
3898         if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
3899             ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
3900                 a1.s_addr = ntohl(nat->nat_osrcaddr);
3901                 a4.s_addr = ntohl(oip->ip_src.s_addr);
3902                 a3.s_addr = ntohl(nat->nat_odstaddr);
3903                 a2.s_addr = ntohl(oip->ip_dst.s_addr);
3904                 oip->ip_src.s_addr = htonl(a1.s_addr);
3905                 oip->ip_dst.s_addr = htonl(a3.s_addr);
3906                 odst = 1;
3907         } else {
3908                 a1.s_addr = ntohl(nat->nat_ndstaddr);
3909                 a2.s_addr = ntohl(oip->ip_dst.s_addr);
3910                 a3.s_addr = ntohl(nat->nat_nsrcaddr);
3911                 a4.s_addr = ntohl(oip->ip_src.s_addr);
3912                 oip->ip_dst.s_addr = htonl(a3.s_addr);
3913                 oip->ip_src.s_addr = htonl(a1.s_addr);
3914                 odst = 0;
3915         }
3916         sum1 = 0;
3917         sum2 = 0;
3918         sumd = 0;
3919         CALC_SUMD(a2.s_addr, a3.s_addr, sum1);
3920         CALC_SUMD(a4.s_addr, a1.s_addr, sum2);
3921         sumd = sum2 + sum1;
3922         if (sumd != 0)
3923                 ipf_fix_datacksum(&oip->ip_sum, sumd);
3924
3925         sumd2 = sumd;
3926         sum1 = 0;
3927         sum2 = 0;
3928
3929         /*
3930          * Fix UDP pseudo header checksum to compensate for the
3931          * IP address change.
3932          */
3933         if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
3934                 u_32_t sum3, sum4, sumt;
3935
3936                 /*
3937                  * Step 2 :
3938                  * For offending TCP/UDP IP packets, translate the ports as
3939                  * well, based on the NAT specification. Of course such
3940                  * a change may be reflected in the ICMP checksum as well.
3941                  *
3942                  * Since the port fields are part of the TCP/UDP checksum
3943                  * of the offending IP packet, you need to adjust that checksum
3944                  * as well... except that the change in the port numbers should
3945                  * be offset by the checksum change.  However, the TCP/UDP
3946                  * checksum will also need to change if there has been an
3947                  * IP address change.
3948                  */
3949                 if (odst == 1) {
3950                         sum1 = ntohs(nat->nat_osport);
3951                         sum4 = ntohs(tcp->th_sport);
3952                         sum3 = ntohs(nat->nat_odport);
3953                         sum2 = ntohs(tcp->th_dport);
3954
3955                         tcp->th_sport = htons(sum1);
3956                         tcp->th_dport = htons(sum3);
3957                 } else {
3958                         sum1 = ntohs(nat->nat_ndport);
3959                         sum2 = ntohs(tcp->th_dport);
3960                         sum3 = ntohs(nat->nat_nsport);
3961                         sum4 = ntohs(tcp->th_sport);
3962
3963                         tcp->th_dport = htons(sum3);
3964                         tcp->th_sport = htons(sum1);
3965                 }
3966                 CALC_SUMD(sum4, sum1, sumt);
3967                 sumd += sumt;
3968                 CALC_SUMD(sum2, sum3, sumt);
3969                 sumd += sumt;
3970
3971                 if (sumd != 0 || sumd2 != 0) {
3972                         /*
3973                          * At this point, sumd is the delta to apply to the
3974                          * TCP/UDP header, given the changes in both the IP
3975                          * address and the ports and sumd2 is the delta to
3976                          * apply to the ICMP header, given the IP address
3977                          * change delta that may need to be applied to the
3978                          * TCP/UDP checksum instead.
3979                          *
3980                          * If we will both the IP and TCP/UDP checksums
3981                          * then the ICMP checksum changes by the address
3982                          * delta applied to the TCP/UDP checksum.  If we
3983                          * do not change the TCP/UDP checksum them we
3984                          * apply the delta in ports to the ICMP checksum.
3985                          */
3986                         if (oip->ip_p == IPPROTO_UDP) {
3987                                 if ((dlen >= 8) && (*csump != 0)) {
3988                                         ipf_fix_datacksum(csump, sumd);
3989                                 } else {
3990                                         CALC_SUMD(sum1, sum4, sumd2);
3991                                         CALC_SUMD(sum3, sum2, sumt);
3992                                         sumd2 += sumt;
3993                                 }
3994                         } else if (oip->ip_p == IPPROTO_TCP) {
3995                                 if (dlen >= 18) {
3996                                         ipf_fix_datacksum(csump, sumd);
3997                                 } else {
3998                                         CALC_SUMD(sum1, sum4, sumd2);
3999                                         CALC_SUMD(sum3, sum2, sumt);
4000                                         sumd2 += sumt;
4001                                 }
4002                         }
4003                         if (sumd2 != 0) {
4004                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4005                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4006                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4007                                 ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0);
4008                         }
4009                 }
4010         } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
4011                 icmphdr_t *orgicmp;
4012
4013                 /*
4014                  * XXX - what if this is bogus hl and we go off the end ?
4015                  * In this case, ipf_nat_icmperrorlookup() will have
4016                  * returned NULL.
4017                  */
4018                 orgicmp = (icmphdr_t *)dp;
4019
4020                 if (odst == 1) {
4021                         if (orgicmp->icmp_id != nat->nat_osport) {
4022
4023                                 /*
4024                                  * Fix ICMP checksum (of the offening ICMP
4025                                  * query packet) to compensate the change
4026                                  * in the ICMP id of the offending ICMP
4027                                  * packet.
4028                                  *
4029                                  * Since you modify orgicmp->icmp_id with
4030                                  * a delta (say x) and you compensate that
4031                                  * in origicmp->icmp_cksum with a delta
4032                                  * minus x, you don't have to adjust the
4033                                  * overall icmp->icmp_cksum
4034                                  */
4035                                 sum1 = ntohs(orgicmp->icmp_id);
4036                                 sum2 = ntohs(nat->nat_oicmpid);
4037                                 CALC_SUMD(sum1, sum2, sumd);
4038                                 orgicmp->icmp_id = nat->nat_oicmpid;
4039                                 ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd);
4040                         }
4041                 } /* nat_dir == NAT_INBOUND is impossible for icmp queries */
4042         }
4043         return nat;
4044 }
4045
4046
4047 /*
4048  *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
4049  * osrc    X       == src    == src      X
4050  * odst    X       == dst    == dst      X
4051  * nsrc  == dst      X         X      == dst
4052  * ndst  == src      X         X      == src
4053  * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
4054  */
4055 /*
4056  * NB: these lookups don't lock access to the list, it assumed that it has
4057  * already been done!
4058  */
4059 /* ------------------------------------------------------------------------ */
4060 /* Function:    ipf_nat_inlookup                                            */
4061 /* Returns:     nat_t* - NULL == no match,                                  */
4062 /*                       else pointer to matching NAT entry                 */
4063 /* Parameters:  fin(I)    - pointer to packet information                   */
4064 /*              flags(I)  - NAT flags for this packet                       */
4065 /*              p(I)      - protocol for this packet                        */
4066 /*              src(I)    - source IP address                               */
4067 /*              mapdst(I) - destination IP address                          */
4068 /*                                                                          */
4069 /* Lookup a nat entry based on the mapped destination ip address/port and   */
4070 /* real source address/port.  We use this lookup when receiving a packet,   */
4071 /* we're looking for a table entry, based on the destination address.       */
4072 /*                                                                          */
4073 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4074 /*                                                                          */
4075 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4076 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4077 /*                                                                          */
4078 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4079 /*            the packet is of said protocol                                */
4080 /* ------------------------------------------------------------------------ */
4081 nat_t *
4082 ipf_nat_inlookup(fin, flags, p, src, mapdst)
4083         fr_info_t *fin;
4084         u_int flags, p;
4085         struct in_addr src , mapdst;
4086 {
4087         ipf_main_softc_t *softc = fin->fin_main_soft;
4088         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4089         u_short sport, dport;
4090         grehdr_t *gre;
4091         ipnat_t *ipn;
4092         u_int sflags;
4093         nat_t *nat;
4094         int nflags;
4095         u_32_t dst;
4096         void *ifp;
4097         u_int hv, rhv;
4098
4099         ifp = fin->fin_ifp;
4100         gre = NULL;
4101         dst = mapdst.s_addr;
4102         sflags = flags & NAT_TCPUDPICMP;
4103
4104         switch (p)
4105         {
4106         case IPPROTO_TCP :
4107         case IPPROTO_UDP :
4108                 sport = htons(fin->fin_data[0]);
4109                 dport = htons(fin->fin_data[1]);
4110                 break;
4111         case IPPROTO_ICMP :
4112                 if (flags & IPN_ICMPERR) {
4113                         sport = fin->fin_data[1];
4114                         dport = 0;
4115                 } else {
4116                         dport = fin->fin_data[1];
4117                         sport = 0;
4118                 }
4119                 break;
4120         default :
4121                 sport = 0;
4122                 dport = 0;
4123                 break;
4124         }
4125
4126
4127         if ((flags & SI_WILDP) != 0)
4128                 goto find_in_wild_ports;
4129
4130         rhv = NAT_HASH_FN(dst, dport, 0xffffffff);
4131         rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff);
4132         hv = rhv % softn->ipf_nat_table_sz;
4133         nat = softn->ipf_nat_table[1][hv];
4134         /* TRACE dst, dport, src, sport, hv, nat */
4135
4136         for (; nat; nat = nat->nat_hnext[1]) {
4137                 if (nat->nat_ifps[0] != NULL) {
4138                         if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4139                                 continue;
4140                 }
4141
4142                 if (nat->nat_pr[0] != p)
4143                         continue;
4144
4145                 switch (nat->nat_dir)
4146                 {
4147                 case NAT_INBOUND :
4148                 case NAT_DIVERTIN :
4149                         if (nat->nat_v[0] != 4)
4150                                 continue;
4151                         if (nat->nat_osrcaddr != src.s_addr ||
4152                             nat->nat_odstaddr != dst)
4153                                 continue;
4154                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4155                                 if (nat->nat_osport != sport)
4156                                         continue;
4157                                 if (nat->nat_odport != dport)
4158                                         continue;
4159
4160                         } else if (p == IPPROTO_ICMP) {
4161                                 if (nat->nat_osport != dport) {
4162                                         continue;
4163                                 }
4164                         }
4165                         break;
4166                 case NAT_DIVERTOUT :
4167                         if (nat->nat_dlocal)
4168                                 continue;
4169                 case NAT_OUTBOUND :
4170                         if (nat->nat_v[1] != 4)
4171                                 continue;
4172                         if (nat->nat_dlocal)
4173                                 continue;
4174                         if (nat->nat_dlocal)
4175                                 continue;
4176                         if (nat->nat_ndstaddr != src.s_addr ||
4177                             nat->nat_nsrcaddr != dst)
4178                                 continue;
4179                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4180                                 if (nat->nat_ndport != sport)
4181                                         continue;
4182                                 if (nat->nat_nsport != dport)
4183                                         continue;
4184
4185                         } else if (p == IPPROTO_ICMP) {
4186                                 if (nat->nat_osport != dport) {
4187                                         continue;
4188                                 }
4189                         }
4190                         break;
4191                 }
4192
4193
4194                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4195                         ipn = nat->nat_ptr;
4196                         if ((ipn != NULL) && (nat->nat_aps != NULL))
4197                                 if (ipf_proxy_match(fin, nat) != 0)
4198                                         continue;
4199                 }
4200                 if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4201                         nat->nat_ifps[0] = ifp;
4202                         nat->nat_mtu[0] = GETIFMTU_4(ifp);
4203                 }
4204                 return nat;
4205         }
4206
4207         /*
4208          * So if we didn't find it but there are wildcard members in the hash
4209          * table, go back and look for them.  We do this search and update here
4210          * because it is modifying the NAT table and we want to do this only
4211          * for the first packet that matches.  The exception, of course, is
4212          * for "dummy" (FI_IGNORE) lookups.
4213          */
4214 find_in_wild_ports:
4215         if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4216                 NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0);
4217                 return NULL;
4218         }
4219         if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4220                 NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0);
4221                 return NULL;
4222         }
4223
4224         RWLOCK_EXIT(&softc->ipf_nat);
4225
4226         hv = NAT_HASH_FN(dst, 0, 0xffffffff);
4227         hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz);
4228         WRITE_ENTER(&softc->ipf_nat);
4229
4230         nat = softn->ipf_nat_table[1][hv];
4231         /* TRACE dst, src, hv, nat */
4232         for (; nat; nat = nat->nat_hnext[1]) {
4233                 if (nat->nat_ifps[0] != NULL) {
4234                         if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4235                                 continue;
4236                 }
4237
4238                 if (nat->nat_pr[0] != fin->fin_p)
4239                         continue;
4240
4241                 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4242                 {
4243                 case NAT_INBOUND :
4244                         if (nat->nat_v[0] != 4)
4245                                 continue;
4246                         if (nat->nat_osrcaddr != src.s_addr ||
4247                             nat->nat_odstaddr != dst)
4248                                 continue;
4249                         break;
4250                 case NAT_OUTBOUND :
4251                         if (nat->nat_v[1] != 4)
4252                                 continue;
4253                         if (nat->nat_ndstaddr != src.s_addr ||
4254                             nat->nat_nsrcaddr != dst)
4255                                 continue;
4256                         break;
4257                 }
4258
4259                 nflags = nat->nat_flags;
4260                 if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
4261                         continue;
4262
4263                 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
4264                                    NAT_INBOUND) == 1) {
4265                         if ((fin->fin_flx & FI_IGNORE) != 0)
4266                                 break;
4267                         if ((nflags & SI_CLONE) != 0) {
4268                                 nat = ipf_nat_clone(fin, nat);
4269                                 if (nat == NULL)
4270                                         break;
4271                         } else {
4272                                 MUTEX_ENTER(&softn->ipf_nat_new);
4273                                 softn->ipf_nat_stats.ns_wilds--;
4274                                 MUTEX_EXIT(&softn->ipf_nat_new);
4275                         }
4276
4277                         if (nat->nat_dir == NAT_INBOUND) {
4278                                 if (nat->nat_osport == 0) {
4279                                         nat->nat_osport = sport;
4280                                         nat->nat_nsport = sport;
4281                                 }
4282                                 if (nat->nat_odport == 0) {
4283                                         nat->nat_odport = dport;
4284                                         nat->nat_ndport = dport;
4285                                 }
4286                         } else if (nat->nat_dir == NAT_OUTBOUND) {
4287                                 if (nat->nat_osport == 0) {
4288                                         nat->nat_osport = dport;
4289                                         nat->nat_nsport = dport;
4290                                 }
4291                                 if (nat->nat_odport == 0) {
4292                                         nat->nat_odport = sport;
4293                                         nat->nat_ndport = sport;
4294                                 }
4295                         }
4296                         if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4297                                 nat->nat_ifps[0] = ifp;
4298                                 nat->nat_mtu[0] = GETIFMTU_4(ifp);
4299                         }
4300                         nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4301                         ipf_nat_tabmove(softn, nat);
4302                         break;
4303                 }
4304         }
4305
4306         MUTEX_DOWNGRADE(&softc->ipf_nat);
4307
4308         if (nat == NULL) {
4309                 NBUMPSIDE(0, ns_lookup_miss);
4310         }
4311         return nat;
4312 }
4313
4314
4315 /* ------------------------------------------------------------------------ */
4316 /* Function:    ipf_nat_tabmove                                             */
4317 /* Returns:     Nil                                                         */
4318 /* Parameters:  softn(I) - pointer to NAT context structure                 */
4319 /*              nat(I)   - pointer to NAT structure                         */
4320 /* Write Lock:  ipf_nat                                                     */
4321 /*                                                                          */
4322 /* This function is only called for TCP/UDP NAT table entries where the     */
4323 /* original was placed in the table without hashing on the ports and we now */
4324 /* want to include hashing on port numbers.                                 */
4325 /* ------------------------------------------------------------------------ */
4326 static void
4327 ipf_nat_tabmove(softn, nat)
4328         ipf_nat_softc_t *softn;
4329         nat_t *nat;
4330 {
4331         u_int hv0, hv1, rhv0, rhv1;
4332         natstat_t *nsp;
4333         nat_t **natp;
4334
4335         if (nat->nat_flags & SI_CLONE)
4336                 return;
4337
4338         nsp = &softn->ipf_nat_stats;
4339         /*
4340          * Remove the NAT entry from the old location
4341          */
4342         if (nat->nat_hnext[0])
4343                 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
4344         *nat->nat_phnext[0] = nat->nat_hnext[0];
4345         nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] %
4346                                      softn->ipf_nat_table_sz]--;
4347
4348         if (nat->nat_hnext[1])
4349                 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
4350         *nat->nat_phnext[1] = nat->nat_hnext[1];
4351         nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] %
4352                                      softn->ipf_nat_table_sz]--;
4353
4354         /*
4355          * Add into the NAT table in the new position
4356          */
4357         rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff);
4358         rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport,
4359                            0xffffffff);
4360         rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff);
4361         rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport,
4362                            0xffffffff);
4363
4364         hv0 = rhv0 % softn->ipf_nat_table_sz;
4365         hv1 = rhv1 % softn->ipf_nat_table_sz;
4366
4367         if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
4368                 u_int swap;
4369
4370                 swap = hv0;
4371                 hv0 = hv1;
4372                 hv1 = swap;
4373         }
4374
4375         /* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */
4376         /* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */
4377
4378         nat->nat_hv[0] = rhv0;
4379         natp = &softn->ipf_nat_table[0][hv0];
4380         if (*natp)
4381                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
4382         nat->nat_phnext[0] = natp;
4383         nat->nat_hnext[0] = *natp;
4384         *natp = nat;
4385         nsp->ns_side[0].ns_bucketlen[hv0]++;
4386
4387         nat->nat_hv[1] = rhv1;
4388         natp = &softn->ipf_nat_table[1][hv1];
4389         if (*natp)
4390                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
4391         nat->nat_phnext[1] = natp;
4392         nat->nat_hnext[1] = *natp;
4393         *natp = nat;
4394         nsp->ns_side[1].ns_bucketlen[hv1]++;
4395 }
4396
4397
4398 /* ------------------------------------------------------------------------ */
4399 /* Function:    ipf_nat_outlookup                                           */
4400 /* Returns:     nat_t* - NULL == no match,                                  */
4401 /*                       else pointer to matching NAT entry                 */
4402 /* Parameters:  fin(I)   - pointer to packet information                    */
4403 /*              flags(I) - NAT flags for this packet                        */
4404 /*              p(I)     - protocol for this packet                         */
4405 /*              src(I)   - source IP address                                */
4406 /*              dst(I)   - destination IP address                           */
4407 /*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
4408 /*                                                                          */
4409 /* Lookup a nat entry based on the source 'real' ip address/port and        */
4410 /* destination address/port.  We use this lookup when sending a packet out, */
4411 /* we're looking for a table entry, based on the source address.            */
4412 /*                                                                          */
4413 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4414 /*                                                                          */
4415 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4416 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4417 /*                                                                          */
4418 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4419 /*            the packet is of said protocol                                */
4420 /* ------------------------------------------------------------------------ */
4421 nat_t *
4422 ipf_nat_outlookup(fin, flags, p, src, dst)
4423         fr_info_t *fin;
4424         u_int flags, p;
4425         struct in_addr src , dst;
4426 {
4427         ipf_main_softc_t *softc = fin->fin_main_soft;
4428         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4429         u_short sport, dport;
4430         u_int sflags;
4431         ipnat_t *ipn;
4432         nat_t *nat;
4433         void *ifp;
4434         u_int hv;
4435
4436         ifp = fin->fin_ifp;
4437         sflags = flags & IPN_TCPUDPICMP;
4438         sport = 0;
4439         dport = 0;
4440
4441         switch (p)
4442         {
4443         case IPPROTO_TCP :
4444         case IPPROTO_UDP :
4445                 sport = htons(fin->fin_data[0]);
4446                 dport = htons(fin->fin_data[1]);
4447                 break;
4448         case IPPROTO_ICMP :
4449                 if (flags & IPN_ICMPERR)
4450                         sport = fin->fin_data[1];
4451                 else
4452                         dport = fin->fin_data[1];
4453                 break;
4454         default :
4455                 break;
4456         }
4457
4458         if ((flags & SI_WILDP) != 0)
4459                 goto find_out_wild_ports;
4460
4461         hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff);
4462         hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz);
4463         nat = softn->ipf_nat_table[0][hv];
4464
4465         /* TRACE src, sport, dst, dport, hv, nat */
4466
4467         for (; nat; nat = nat->nat_hnext[0]) {
4468                 if (nat->nat_ifps[1] != NULL) {
4469                         if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4470                                 continue;
4471                 }
4472
4473                 if (nat->nat_pr[1] != p)
4474                         continue;
4475
4476                 switch (nat->nat_dir)
4477                 {
4478                 case NAT_INBOUND :
4479                 case NAT_DIVERTIN :
4480                         if (nat->nat_v[1] != 4)
4481                                 continue;
4482                         if (nat->nat_ndstaddr != src.s_addr ||
4483                             nat->nat_nsrcaddr != dst.s_addr)
4484                                 continue;
4485
4486                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4487                                 if (nat->nat_ndport != sport)
4488                                         continue;
4489                                 if (nat->nat_nsport != dport)
4490                                         continue;
4491
4492                         } else if (p == IPPROTO_ICMP) {
4493                                 if (nat->nat_osport != dport) {
4494                                         continue;
4495                                 }
4496                         }
4497                         break;
4498                 case NAT_OUTBOUND :
4499                 case NAT_DIVERTOUT :
4500                         if (nat->nat_v[0] != 4)
4501                                 continue;
4502                         if (nat->nat_osrcaddr != src.s_addr ||
4503                             nat->nat_odstaddr != dst.s_addr)
4504                                 continue;
4505
4506                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4507                                 if (nat->nat_odport != dport)
4508                                         continue;
4509                                 if (nat->nat_osport != sport)
4510                                         continue;
4511
4512                         } else if (p == IPPROTO_ICMP) {
4513                                 if (nat->nat_osport != dport) {
4514                                         continue;
4515                                 }
4516                         }
4517                         break;
4518                 }
4519
4520                 ipn = nat->nat_ptr;
4521                 if ((ipn != NULL) && (nat->nat_aps != NULL))
4522                         if (ipf_proxy_match(fin, nat) != 0)
4523                                 continue;
4524
4525                 if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4526                         nat->nat_ifps[1] = ifp;
4527                         nat->nat_mtu[1] = GETIFMTU_4(ifp);
4528                 }
4529                 return nat;
4530         }
4531
4532         /*
4533          * So if we didn't find it but there are wildcard members in the hash
4534          * table, go back and look for them.  We do this search and update here
4535          * because it is modifying the NAT table and we want to do this only
4536          * for the first packet that matches.  The exception, of course, is
4537          * for "dummy" (FI_IGNORE) lookups.
4538          */
4539 find_out_wild_ports:
4540         if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4541                 NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1);
4542                 return NULL;
4543         }
4544         if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4545                 NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1);
4546                 return NULL;
4547         }
4548
4549         RWLOCK_EXIT(&softc->ipf_nat);
4550
4551         hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff);
4552         hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz);
4553
4554         WRITE_ENTER(&softc->ipf_nat);
4555
4556         nat = softn->ipf_nat_table[0][hv];
4557         for (; nat; nat = nat->nat_hnext[0]) {
4558                 if (nat->nat_ifps[1] != NULL) {
4559                         if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4560                                 continue;
4561                 }
4562
4563                 if (nat->nat_pr[1] != fin->fin_p)
4564                         continue;
4565
4566                 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4567                 {
4568                 case NAT_INBOUND :
4569                         if (nat->nat_v[1] != 4)
4570                                 continue;
4571                         if (nat->nat_ndstaddr != src.s_addr ||
4572                             nat->nat_nsrcaddr != dst.s_addr)
4573                                 continue;
4574                         break;
4575                 case NAT_OUTBOUND :
4576                         if (nat->nat_v[0] != 4)
4577                                 continue;
4578                         if (nat->nat_osrcaddr != src.s_addr ||
4579                             nat->nat_odstaddr != dst.s_addr)
4580                                 continue;
4581                         break;
4582                 }
4583
4584                 if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
4585                         continue;
4586
4587                 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
4588                                    NAT_OUTBOUND) == 1) {
4589                         if ((fin->fin_flx & FI_IGNORE) != 0)
4590                                 break;
4591                         if ((nat->nat_flags & SI_CLONE) != 0) {
4592                                 nat = ipf_nat_clone(fin, nat);
4593                                 if (nat == NULL)
4594                                         break;
4595                         } else {
4596                                 MUTEX_ENTER(&softn->ipf_nat_new);
4597                                 softn->ipf_nat_stats.ns_wilds--;
4598                                 MUTEX_EXIT(&softn->ipf_nat_new);
4599                         }
4600
4601                         if (nat->nat_dir == NAT_OUTBOUND) {
4602                                 if (nat->nat_osport == 0) {
4603                                         nat->nat_osport = sport;
4604                                         nat->nat_nsport = sport;
4605                                 }
4606                                 if (nat->nat_odport == 0) {
4607                                         nat->nat_odport = dport;
4608                                         nat->nat_ndport = dport;
4609                                 }
4610                         } else if (nat->nat_dir == NAT_INBOUND) {
4611                                 if (nat->nat_osport == 0) {
4612                                         nat->nat_osport = dport;
4613                                         nat->nat_nsport = dport;
4614                                 }
4615                                 if (nat->nat_odport == 0) {
4616                                         nat->nat_odport = sport;
4617                                         nat->nat_ndport = sport;
4618                                 }
4619                         }
4620                         if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4621                                 nat->nat_ifps[1] = ifp;
4622                                 nat->nat_mtu[1] = GETIFMTU_4(ifp);
4623                         }
4624                         nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4625                         ipf_nat_tabmove(softn, nat);
4626                         break;
4627                 }
4628         }
4629
4630         MUTEX_DOWNGRADE(&softc->ipf_nat);
4631
4632         if (nat == NULL) {
4633                 NBUMPSIDE(1, ns_lookup_miss);
4634         }
4635         return nat;
4636 }
4637
4638
4639 /* ------------------------------------------------------------------------ */
4640 /* Function:    ipf_nat_lookupredir                                         */
4641 /* Returns:     nat_t* - NULL == no match,                                  */
4642 /*                       else pointer to matching NAT entry                 */
4643 /* Parameters:  np(I) - pointer to description of packet to find NAT table  */
4644 /*                      entry for.                                          */
4645 /*                                                                          */
4646 /* Lookup the NAT tables to search for a matching redirect                  */
4647 /* The contents of natlookup_t should imitate those found in a packet that  */
4648 /* would be translated - ie a packet coming in for RDR or going out for MAP.*/
4649 /* We can do the lookup in one of two ways, imitating an inbound or         */
4650 /* outbound  packet.  By default we assume outbound, unless IPN_IN is set.  */
4651 /* For IN, the fields are set as follows:                                   */
4652 /*     nl_real* = source information                                        */
4653 /*     nl_out* = destination information (translated)                       */
4654 /* For an out packet, the fields are set like this:                         */
4655 /*     nl_in* = source information (untranslated)                           */
4656 /*     nl_out* = destination information (translated)                       */
4657 /* ------------------------------------------------------------------------ */
4658 nat_t *
4659 ipf_nat_lookupredir(np)
4660         natlookup_t *np;
4661 {
4662         fr_info_t fi;
4663         nat_t *nat;
4664
4665         bzero((char *)&fi, sizeof(fi));
4666         if (np->nl_flags & IPN_IN) {
4667                 fi.fin_data[0] = ntohs(np->nl_realport);
4668                 fi.fin_data[1] = ntohs(np->nl_outport);
4669         } else {
4670                 fi.fin_data[0] = ntohs(np->nl_inport);
4671                 fi.fin_data[1] = ntohs(np->nl_outport);
4672         }
4673         if (np->nl_flags & IPN_TCP)
4674                 fi.fin_p = IPPROTO_TCP;
4675         else if (np->nl_flags & IPN_UDP)
4676                 fi.fin_p = IPPROTO_UDP;
4677         else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
4678                 fi.fin_p = IPPROTO_ICMP;
4679
4680         /*
4681          * We can do two sorts of lookups:
4682          * - IPN_IN: we have the `real' and `out' address, look for `in'.
4683          * - default: we have the `in' and `out' address, look for `real'.
4684          */
4685         if (np->nl_flags & IPN_IN) {
4686                 if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p,
4687                                             np->nl_realip, np->nl_outip))) {
4688                         np->nl_inip = nat->nat_odstip;
4689                         np->nl_inport = nat->nat_odport;
4690                 }
4691         } else {
4692                 /*
4693                  * If nl_inip is non null, this is a lookup based on the real
4694                  * ip address. Else, we use the fake.
4695                  */
4696                 if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p,
4697                                          np->nl_inip, np->nl_outip))) {
4698
4699                         if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
4700                                 fr_info_t fin;
4701                                 bzero((char *)&fin, sizeof(fin));
4702                                 fin.fin_p = nat->nat_pr[0];
4703                                 fin.fin_data[0] = ntohs(nat->nat_ndport);
4704                                 fin.fin_data[1] = ntohs(nat->nat_nsport);
4705                                 if (ipf_nat_inlookup(&fin, np->nl_flags,
4706                                                      fin.fin_p, nat->nat_ndstip,
4707                                                      nat->nat_nsrcip) != NULL) {
4708                                         np->nl_flags &= ~IPN_FINDFORWARD;
4709                                 }
4710                         }
4711
4712                         np->nl_realip = nat->nat_ndstip;
4713                         np->nl_realport = nat->nat_ndport;
4714                 }
4715         }
4716
4717         return nat;
4718 }
4719
4720
4721 /* ------------------------------------------------------------------------ */
4722 /* Function:    ipf_nat_match                                               */
4723 /* Returns:     int - 0 == no match, 1 == match                             */
4724 /* Parameters:  fin(I)   - pointer to packet information                    */
4725 /*              np(I)    - pointer to NAT rule                              */
4726 /*                                                                          */
4727 /* Pull the matching of a packet against a NAT rule out of that complex     */
4728 /* loop inside ipf_nat_checkin() and lay it out properly in its own function. */
4729 /* ------------------------------------------------------------------------ */
4730 static int
4731 ipf_nat_match(fin, np)
4732         fr_info_t *fin;
4733         ipnat_t *np;
4734 {
4735         ipf_main_softc_t *softc = fin->fin_main_soft;
4736         frtuc_t *ft;
4737         int match;
4738
4739         match = 0;
4740         switch (np->in_osrcatype)
4741         {
4742         case FRI_NORMAL :
4743                 match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr);
4744                 break;
4745         case FRI_LOOKUP :
4746                 match = (*np->in_osrcfunc)(softc, np->in_osrcptr,
4747                                            4, &fin->fin_saddr, fin->fin_plen);
4748                 break;
4749         }
4750         match ^= ((np->in_flags & IPN_NOTSRC) != 0);
4751         if (match)
4752                 return 0;
4753
4754         match = 0;
4755         switch (np->in_odstatype)
4756         {
4757         case FRI_NORMAL :
4758                 match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr);
4759                 break;
4760         case FRI_LOOKUP :
4761                 match = (*np->in_odstfunc)(softc, np->in_odstptr,
4762                                            4, &fin->fin_daddr, fin->fin_plen);
4763                 break;
4764         }
4765
4766         match ^= ((np->in_flags & IPN_NOTDST) != 0);
4767         if (match)
4768                 return 0;
4769
4770         ft = &np->in_tuc;
4771         if (!(fin->fin_flx & FI_TCPUDP) ||
4772             (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
4773                 if (ft->ftu_scmp || ft->ftu_dcmp)
4774                         return 0;
4775                 return 1;
4776         }
4777
4778         return ipf_tcpudpchk(&fin->fin_fi, ft);
4779 }
4780
4781
4782 /* ------------------------------------------------------------------------ */
4783 /* Function:    ipf_nat_update                                              */
4784 /* Returns:     Nil                                                         */
4785 /* Parameters:  fin(I) - pointer to packet information                      */
4786 /*              nat(I) - pointer to NAT structure                           */
4787 /*                                                                          */
4788 /* Updates the lifetime of a NAT table entry for non-TCP packets.  Must be  */
4789 /* called with fin_rev updated - i.e. after calling ipf_nat_proto().        */
4790 /*                                                                          */
4791 /* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to     */
4792 /* already be set.                                                          */
4793 /* ------------------------------------------------------------------------ */
4794 void
4795 ipf_nat_update(fin, nat)
4796         fr_info_t *fin;
4797         nat_t *nat;
4798 {
4799         ipf_main_softc_t *softc = fin->fin_main_soft;
4800         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4801         ipftq_t *ifq, *ifq2;
4802         ipftqent_t *tqe;
4803         ipnat_t *np = nat->nat_ptr;
4804
4805         tqe = &nat->nat_tqe;
4806         ifq = tqe->tqe_ifq;
4807
4808         /*
4809          * We allow over-riding of NAT timeouts from NAT rules, even for
4810          * TCP, however, if it is TCP and there is no rule timeout set,
4811          * then do not update the timeout here.
4812          */
4813         if (np != NULL) {
4814                 np->in_bytes[fin->fin_rev] += fin->fin_plen;
4815                 ifq2 = np->in_tqehead[fin->fin_rev];
4816         } else {
4817                 ifq2 = NULL;
4818         }
4819
4820         if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) {
4821                 (void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq,
4822                                    0, 2);
4823         } else {
4824                 if (ifq2 == NULL) {
4825                         if (nat->nat_pr[0] == IPPROTO_UDP)
4826                                 ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq :
4827                                                       &softn->ipf_nat_udptq;
4828                         else if (nat->nat_pr[0] == IPPROTO_ICMP ||
4829                                  nat->nat_pr[0] == IPPROTO_ICMPV6)
4830                                 ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq:
4831                                                       &softn->ipf_nat_icmptq;
4832                         else
4833                                 ifq2 = &softn->ipf_nat_iptq;
4834                 }
4835
4836                 ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2);
4837         }
4838 }
4839
4840
4841 /* ------------------------------------------------------------------------ */
4842 /* Function:    ipf_nat_checkout                                            */
4843 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
4844 /*                     0 == no packet translation occurred,                 */
4845 /*                     1 == packet was successfully translated.             */
4846 /* Parameters:  fin(I)   - pointer to packet information                    */
4847 /*              passp(I) - pointer to filtering result flags                */
4848 /*                                                                          */
4849 /* Check to see if an outcoming packet should be changed.  ICMP packets are */
4850 /* first checked to see if they match an existing entry (if an error),      */
4851 /* otherwise a search of the current NAT table is made.  If neither results */
4852 /* in a match then a search for a matching NAT rule is made.  Create a new  */
4853 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
4854 /* packet header(s) as required.                                            */
4855 /* ------------------------------------------------------------------------ */
4856 int
4857 ipf_nat_checkout(fin, passp)
4858         fr_info_t *fin;
4859         u_32_t *passp;
4860 {
4861         ipnat_t *np = NULL, *npnext;
4862         struct ifnet *ifp, *sifp;
4863         ipf_main_softc_t *softc;
4864         ipf_nat_softc_t *softn;
4865         icmphdr_t *icmp = NULL;
4866         tcphdr_t *tcp = NULL;
4867         int rval, natfailed;
4868         u_int nflags = 0;
4869         u_32_t ipa, iph;
4870         int natadd = 1;
4871         frentry_t *fr;
4872         nat_t *nat;
4873
4874         if (fin->fin_v == 6) {
4875 #ifdef USE_INET6
4876                 return ipf_nat6_checkout(fin, passp);
4877 #else
4878                 return 0;
4879 #endif
4880         }
4881
4882         softc = fin->fin_main_soft;
4883         softn = softc->ipf_nat_soft;
4884
4885         if (softn->ipf_nat_lock != 0)
4886                 return 0;
4887         if (softn->ipf_nat_stats.ns_rules == 0 &&
4888             softn->ipf_nat_instances == NULL)
4889                 return 0;
4890
4891         natfailed = 0;
4892         fr = fin->fin_fr;
4893         sifp = fin->fin_ifp;
4894         if (fr != NULL) {
4895                 ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
4896                 if ((ifp != NULL) && (ifp != (void *)-1))
4897                         fin->fin_ifp = ifp;
4898         }
4899         ifp = fin->fin_ifp;
4900
4901         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
4902                 switch (fin->fin_p)
4903                 {
4904                 case IPPROTO_TCP :
4905                         nflags = IPN_TCP;
4906                         break;
4907                 case IPPROTO_UDP :
4908                         nflags = IPN_UDP;
4909                         break;
4910                 case IPPROTO_ICMP :
4911                         icmp = fin->fin_dp;
4912
4913                         /*
4914                          * This is an incoming packet, so the destination is
4915                          * the icmp_id and the source port equals 0
4916                          */
4917                         if ((fin->fin_flx & FI_ICMPQUERY) != 0)
4918                                 nflags = IPN_ICMPQUERY;
4919                         break;
4920                 default :
4921                         break;
4922                 }
4923
4924                 if ((nflags & IPN_TCPUDP))
4925                         tcp = fin->fin_dp;
4926         }
4927
4928         ipa = fin->fin_saddr;
4929
4930         READ_ENTER(&softc->ipf_nat);
4931
4932         if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
4933             (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
4934                 /*EMPTY*/;
4935         else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
4936                 natadd = 0;
4937         else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH,
4938                                       (u_int)fin->fin_p, fin->fin_src,
4939                                       fin->fin_dst))) {
4940                 nflags = nat->nat_flags;
4941         } else if (fin->fin_off == 0) {
4942                 u_32_t hv, msk, nmsk = 0;
4943
4944                 /*
4945                  * If there is no current entry in the nat table for this IP#,
4946                  * create one for it (if there is a matching rule).
4947                  */
4948 maskloop:
4949                 msk = softn->ipf_nat_map_active_masks[nmsk];
4950                 iph = ipa & msk;
4951                 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz);
4952 retry_roundrobin:
4953                 for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) {
4954                         npnext = np->in_mnext;
4955                         if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
4956                                 continue;
4957                         if (np->in_v[0] != 4)
4958                                 continue;
4959                         if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
4960                                 continue;
4961                         if ((np->in_flags & IPN_RF) &&
4962                             !(np->in_flags & nflags))
4963                                 continue;
4964                         if (np->in_flags & IPN_FILTER) {
4965                                 switch (ipf_nat_match(fin, np))
4966                                 {
4967                                 case 0 :
4968                                         continue;
4969                                 case -1 :
4970                                         rval = -1;
4971                                         goto outmatchfail;
4972                                 case 1 :
4973                                 default :
4974                                         break;
4975                                 }
4976                         } else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr)
4977                                 continue;
4978
4979                         if ((fr != NULL) &&
4980                             !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
4981                                 continue;
4982
4983                         if (np->in_plabel != -1) {
4984                                 if (((np->in_flags & IPN_FILTER) == 0) &&
4985                                     (np->in_odport != fin->fin_data[1]))
4986                                         continue;
4987                                 if (ipf_proxy_ok(fin, tcp, np) == 0)
4988                                         continue;
4989                         }
4990
4991                         if (np->in_flags & IPN_NO) {
4992                                 np->in_hits++;
4993                                 break;
4994                         }
4995                         MUTEX_ENTER(&softn->ipf_nat_new);
4996                         /*
4997                          * If we've matched a round-robin rule but it has
4998                          * moved in the list since we got it, start over as
4999                          * this is now no longer correct.
5000                          */
5001                         if (npnext != np->in_mnext) {
5002                                 if ((np->in_flags & IPN_ROUNDR) != 0) {
5003                                         MUTEX_EXIT(&softn->ipf_nat_new);
5004                                         goto retry_roundrobin;
5005                                 }
5006                                 npnext = np->in_mnext;
5007                         }
5008
5009                         nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND);
5010                         MUTEX_EXIT(&softn->ipf_nat_new);
5011                         if (nat != NULL) {
5012                                 natfailed = 0;
5013                                 break;
5014                         }
5015                         natfailed = -1;
5016                 }
5017                 if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) {
5018                         nmsk++;
5019                         goto maskloop;
5020                 }
5021         }
5022
5023         if (nat != NULL) {
5024                 rval = ipf_nat_out(fin, nat, natadd, nflags);
5025                 if (rval == 1) {
5026                         MUTEX_ENTER(&nat->nat_lock);
5027                         ipf_nat_update(fin, nat);
5028                         nat->nat_bytes[1] += fin->fin_plen;
5029                         nat->nat_pkts[1]++;
5030                         fin->fin_pktnum = nat->nat_pkts[1];
5031                         MUTEX_EXIT(&nat->nat_lock);
5032                 }
5033         } else
5034                 rval = natfailed;
5035 outmatchfail:
5036         RWLOCK_EXIT(&softc->ipf_nat);
5037
5038         switch (rval)
5039         {
5040         case -1 :
5041                 if (passp != NULL) {
5042                         DT1(frb_natv4out, fr_info_t *, fin);
5043                         NBUMPSIDED(1, ns_drop);
5044                         *passp = FR_BLOCK;
5045                         fin->fin_reason = FRB_NATV4;
5046                 }
5047                 fin->fin_flx |= FI_BADNAT;
5048                 NBUMPSIDED(1, ns_badnat);
5049                 break;
5050         case 0 :
5051                 NBUMPSIDE(1, ns_ignored);
5052                 break;
5053         case 1 :
5054                 NBUMPSIDE(1, ns_translated);
5055                 break;
5056         }
5057         fin->fin_ifp = sifp;
5058         return rval;
5059 }
5060
5061 /* ------------------------------------------------------------------------ */
5062 /* Function:    ipf_nat_out                                                 */
5063 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5064 /*                     1 == packet was successfully translated.             */
5065 /* Parameters:  fin(I)    - pointer to packet information                   */
5066 /*              nat(I)    - pointer to NAT structure                        */
5067 /*              natadd(I) - flag indicating if it is safe to add frag cache */
5068 /*              nflags(I) - NAT flags set for this packet                   */
5069 /*                                                                          */
5070 /* Translate a packet coming "out" on an interface.                         */
5071 /* ------------------------------------------------------------------------ */
5072 int
5073 ipf_nat_out(fin, nat, natadd, nflags)
5074         fr_info_t *fin;
5075         nat_t *nat;
5076         int natadd;
5077         u_32_t nflags;
5078 {
5079         ipf_main_softc_t *softc = fin->fin_main_soft;
5080         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5081         icmphdr_t *icmp;
5082         tcphdr_t *tcp;
5083         ipnat_t *np;
5084         int skip;
5085         int i;
5086
5087         tcp = NULL;
5088         icmp = NULL;
5089         np = nat->nat_ptr;
5090
5091         if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
5092                 (void) ipf_frag_natnew(softc, fin, 0, nat);
5093
5094         /*
5095          * Fix up checksums, not by recalculating them, but
5096          * simply computing adjustments.
5097          * This is only done for STREAMS based IP implementations where the
5098          * checksum has already been calculated by IP.  In all other cases,
5099          * IPFilter is called before the checksum needs calculating so there
5100          * is no call to modify whatever is in the header now.
5101          */
5102         if (nflags == IPN_ICMPERR) {
5103                 u_32_t s1, s2, sumd, msumd;
5104
5105                 s1 = LONG_SUM(ntohl(fin->fin_saddr));
5106                 if (nat->nat_dir == NAT_OUTBOUND) {
5107                         s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
5108                 } else {
5109                         s2 = LONG_SUM(ntohl(nat->nat_odstaddr));
5110                 }
5111                 CALC_SUMD(s1, s2, sumd);
5112                 msumd = sumd;
5113
5114                 s1 = LONG_SUM(ntohl(fin->fin_daddr));
5115                 if (nat->nat_dir == NAT_OUTBOUND) {
5116                         s2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
5117                 } else {
5118                         s2 = LONG_SUM(ntohl(nat->nat_osrcaddr));
5119                 }
5120                 CALC_SUMD(s1, s2, sumd);
5121                 msumd += sumd;
5122
5123                 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0);
5124         }
5125 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5126     defined(linux) || defined(BRIDGE_IPF)
5127         else {
5128                 /*
5129                  * Strictly speaking, this isn't necessary on BSD
5130                  * kernels because they do checksum calculation after
5131                  * this code has run BUT if ipfilter is being used
5132                  * to do NAT as a bridge, that code doesn't exist.
5133                  */
5134                 switch (nat->nat_dir)
5135                 {
5136                 case NAT_OUTBOUND :
5137                         ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART,
5138                                          &fin->fin_ip->ip_sum,
5139                                          nat->nat_ipsumd, 0);
5140                         break;
5141
5142                 case NAT_INBOUND :
5143                         ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART,
5144                                         &fin->fin_ip->ip_sum,
5145                                         nat->nat_ipsumd, 0);
5146                         break;
5147
5148                 default :
5149                         break;
5150                 }
5151         }
5152 #endif
5153
5154         /*
5155          * Address assignment is after the checksum modification because
5156          * we are using the address in the packet for determining the
5157          * correct checksum offset (the ICMP error could be coming from
5158          * anyone...)
5159          */
5160         switch (nat->nat_dir)
5161         {
5162         case NAT_OUTBOUND :
5163                 fin->fin_ip->ip_src = nat->nat_nsrcip;
5164                 fin->fin_saddr = nat->nat_nsrcaddr;
5165                 fin->fin_ip->ip_dst = nat->nat_ndstip;
5166                 fin->fin_daddr = nat->nat_ndstaddr;
5167                 break;
5168
5169         case NAT_INBOUND :
5170                 fin->fin_ip->ip_src = nat->nat_odstip;
5171                 fin->fin_saddr = nat->nat_ndstaddr;
5172                 fin->fin_ip->ip_dst = nat->nat_osrcip;
5173                 fin->fin_daddr = nat->nat_nsrcaddr;
5174                 break;
5175
5176         case NAT_DIVERTIN :
5177             {
5178                 mb_t *m;
5179
5180                 skip = ipf_nat_decap(fin, nat);
5181                 if (skip <= 0) {
5182                         NBUMPSIDED(1, ns_decap_fail);
5183                         return -1;
5184                 }
5185
5186                 m = fin->fin_m;
5187
5188 #if defined(MENTAT) && defined(_KERNEL)
5189                 m->b_rptr += skip;
5190 #else
5191                 m->m_data += skip;
5192                 m->m_len -= skip;
5193
5194 # ifdef M_PKTHDR
5195                 if (m->m_flags & M_PKTHDR)
5196                         m->m_pkthdr.len -= skip;
5197 # endif
5198 #endif
5199
5200                 MUTEX_ENTER(&nat->nat_lock);
5201                 ipf_nat_update(fin, nat);
5202                 MUTEX_EXIT(&nat->nat_lock);
5203                 fin->fin_flx |= FI_NATED;
5204                 if (np != NULL && np->in_tag.ipt_num[0] != 0)
5205                         fin->fin_nattag = &np->in_tag;
5206                 return 1;
5207                 /* NOTREACHED */
5208             }
5209
5210         case NAT_DIVERTOUT :
5211             {
5212                 u_32_t s1, s2, sumd;
5213                 udphdr_t *uh;
5214                 ip_t *ip;
5215                 mb_t *m;
5216
5217                 m = M_DUP(np->in_divmp);
5218                 if (m == NULL) {
5219                         NBUMPSIDED(1, ns_divert_dup);
5220                         return -1;
5221                 }
5222
5223                 ip = MTOD(m, ip_t *);
5224                 ip->ip_id = htons(ipf_nextipid(fin));
5225                 s2 = ntohs(ip->ip_id);
5226
5227                 s1 = ip->ip_len;
5228                 ip->ip_len = ntohs(ip->ip_len);
5229                 ip->ip_len += fin->fin_plen;
5230                 ip->ip_len = htons(ip->ip_len);
5231                 s2 += ntohs(ip->ip_len);
5232                 CALC_SUMD(s1, s2, sumd);
5233
5234                 uh = (udphdr_t *)(ip + 1);
5235                 uh->uh_ulen += fin->fin_plen;
5236                 uh->uh_ulen = htons(uh->uh_ulen);
5237 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5238     defined(linux) || defined(BRIDGE_IPF)
5239                 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5240 #endif
5241
5242                 PREP_MB_T(fin, m);
5243
5244                 fin->fin_src = ip->ip_src;
5245                 fin->fin_dst = ip->ip_dst;
5246                 fin->fin_ip = ip;
5247                 fin->fin_plen += sizeof(ip_t) + 8;      /* UDP + IPv4 hdr */
5248                 fin->fin_dlen += sizeof(ip_t) + 8;      /* UDP + IPv4 hdr */
5249
5250                 nflags &= ~IPN_TCPUDPICMP;
5251
5252                 break;
5253             }
5254
5255         default :
5256                 break;
5257         }
5258
5259         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5260                 u_short *csump;
5261
5262                 if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
5263                         tcp = fin->fin_dp;
5264
5265                         switch (nat->nat_dir)
5266                         {
5267                         case NAT_OUTBOUND :
5268                                 tcp->th_sport = nat->nat_nsport;
5269                                 fin->fin_data[0] = ntohs(nat->nat_nsport);
5270                                 tcp->th_dport = nat->nat_ndport;
5271                                 fin->fin_data[1] = ntohs(nat->nat_ndport);
5272                                 break;
5273
5274                         case NAT_INBOUND :
5275                                 tcp->th_sport = nat->nat_odport;
5276                                 fin->fin_data[0] = ntohs(nat->nat_odport);
5277                                 tcp->th_dport = nat->nat_osport;
5278                                 fin->fin_data[1] = ntohs(nat->nat_osport);
5279                                 break;
5280                         }
5281                 }
5282
5283                 if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
5284                         icmp = fin->fin_dp;
5285                         icmp->icmp_id = nat->nat_nicmpid;
5286                 }
5287
5288                 csump = ipf_nat_proto(fin, nat, nflags);
5289
5290                 /*
5291                  * The above comments do not hold for layer 4 (or higher)
5292                  * checksums...
5293                  */
5294                 if (csump != NULL) {
5295                         if (nat->nat_dir == NAT_OUTBOUND)
5296                                 ipf_fix_outcksum(fin->fin_cksum, csump,
5297                                                  nat->nat_sumd[0],
5298                                                  nat->nat_sumd[1] +
5299                                                  fin->fin_dlen);
5300                         else
5301                                 ipf_fix_incksum(fin->fin_cksum, csump,
5302                                                 nat->nat_sumd[0],
5303                                                 nat->nat_sumd[1] +
5304                                                 fin->fin_dlen);
5305                 }
5306         }
5307
5308         ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5309         /* ------------------------------------------------------------- */
5310         /* A few quick notes:                                            */
5311         /*      Following are test conditions prior to calling the       */
5312         /*      ipf_proxy_check routine.                                 */
5313         /*                                                               */
5314         /*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5315         /*      with a redirect rule, we attempt to match the packet's   */
5316         /*      source port against in_dport, otherwise we'd compare the */
5317         /*      packet's destination.                                    */
5318         /* ------------------------------------------------------------- */
5319         if ((np != NULL) && (np->in_apr != NULL)) {
5320                 i = ipf_proxy_check(fin, nat);
5321                 if (i == 0) {
5322                         i = 1;
5323                 } else if (i == -1) {
5324                         NBUMPSIDED(1, ns_ipf_proxy_fail);
5325                 }
5326         } else {
5327                 i = 1;
5328         }
5329         fin->fin_flx |= FI_NATED;
5330         return i;
5331 }
5332
5333
5334 /* ------------------------------------------------------------------------ */
5335 /* Function:    ipf_nat_checkin                                             */
5336 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5337 /*                     0 == no packet translation occurred,                 */
5338 /*                     1 == packet was successfully translated.             */
5339 /* Parameters:  fin(I)   - pointer to packet information                    */
5340 /*              passp(I) - pointer to filtering result flags                */
5341 /*                                                                          */
5342 /* Check to see if an incoming packet should be changed.  ICMP packets are  */
5343 /* first checked to see if they match an existing entry (if an error),      */
5344 /* otherwise a search of the current NAT table is made.  If neither results */
5345 /* in a match then a search for a matching NAT rule is made.  Create a new  */
5346 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
5347 /* packet header(s) as required.                                            */
5348 /* ------------------------------------------------------------------------ */
5349 int
5350 ipf_nat_checkin(fin, passp)
5351         fr_info_t *fin;
5352         u_32_t *passp;
5353 {
5354         ipf_main_softc_t *softc;
5355         ipf_nat_softc_t *softn;
5356         u_int nflags, natadd;
5357         ipnat_t *np, *npnext;
5358         int rval, natfailed;
5359         struct ifnet *ifp;
5360         struct in_addr in;
5361         icmphdr_t *icmp;
5362         tcphdr_t *tcp;
5363         u_short dport;
5364         nat_t *nat;
5365         u_32_t iph;
5366
5367         softc = fin->fin_main_soft;
5368         softn = softc->ipf_nat_soft;
5369
5370         if (softn->ipf_nat_lock != 0)
5371                 return 0;
5372         if (softn->ipf_nat_stats.ns_rules == 0 &&
5373             softn->ipf_nat_instances == NULL)
5374                 return 0;
5375
5376         tcp = NULL;
5377         icmp = NULL;
5378         dport = 0;
5379         natadd = 1;
5380         nflags = 0;
5381         natfailed = 0;
5382         ifp = fin->fin_ifp;
5383
5384         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5385                 switch (fin->fin_p)
5386                 {
5387                 case IPPROTO_TCP :
5388                         nflags = IPN_TCP;
5389                         break;
5390                 case IPPROTO_UDP :
5391                         nflags = IPN_UDP;
5392                         break;
5393                 case IPPROTO_ICMP :
5394                         icmp = fin->fin_dp;
5395
5396                         /*
5397                          * This is an incoming packet, so the destination is
5398                          * the icmp_id and the source port equals 0
5399                          */
5400                         if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
5401                                 nflags = IPN_ICMPQUERY;
5402                                 dport = icmp->icmp_id;
5403                         } break;
5404                 default :
5405                         break;
5406                 }
5407
5408                 if ((nflags & IPN_TCPUDP)) {
5409                         tcp = fin->fin_dp;
5410                         dport = fin->fin_data[1];
5411                 }
5412         }
5413
5414         in = fin->fin_dst;
5415
5416         READ_ENTER(&softc->ipf_nat);
5417
5418         if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
5419             (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND)))
5420                 /*EMPTY*/;
5421         else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
5422                 natadd = 0;
5423         else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH,
5424                                          (u_int)fin->fin_p,
5425                                          fin->fin_src, in))) {
5426                 nflags = nat->nat_flags;
5427         } else if (fin->fin_off == 0) {
5428                 u_32_t hv, msk, rmsk = 0;
5429
5430                 /*
5431                  * If there is no current entry in the nat table for this IP#,
5432                  * create one for it (if there is a matching rule).
5433                  */
5434 maskloop:
5435                 msk = softn->ipf_nat_rdr_active_masks[rmsk];
5436                 iph = in.s_addr & msk;
5437                 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz);
5438 retry_roundrobin:
5439                 /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */
5440                 for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) {
5441                         npnext = np->in_rnext;
5442                         if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
5443                                 continue;
5444                         if (np->in_v[0] != 4)
5445                                 continue;
5446                         if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
5447                                 continue;
5448                         if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
5449                                 continue;
5450                         if (np->in_flags & IPN_FILTER) {
5451                                 switch (ipf_nat_match(fin, np))
5452                                 {
5453                                 case 0 :
5454                                         continue;
5455                                 case -1 :
5456                                         rval = -1;
5457                                         goto inmatchfail;
5458                                 case 1 :
5459                                 default :
5460                                         break;
5461                                 }
5462                         } else {
5463                                 if ((in.s_addr & np->in_odstmsk) !=
5464                                     np->in_odstaddr)
5465                                         continue;
5466                                 if (np->in_odport &&
5467                                     ((np->in_dtop < dport) ||
5468                                      (dport < np->in_odport)))
5469                                         continue;
5470                         }
5471
5472                         if (np->in_plabel != -1) {
5473                                 if (!ipf_proxy_ok(fin, tcp, np)) {
5474                                         continue;
5475                                 }
5476                         }
5477
5478                         if (np->in_flags & IPN_NO) {
5479                                 np->in_hits++;
5480                                 break;
5481                         }
5482
5483                         MUTEX_ENTER(&softn->ipf_nat_new);
5484                         /*
5485                          * If we've matched a round-robin rule but it has
5486                          * moved in the list since we got it, start over as
5487                          * this is now no longer correct.
5488                          */
5489                         if (npnext != np->in_rnext) {
5490                                 if ((np->in_flags & IPN_ROUNDR) != 0) {
5491                                         MUTEX_EXIT(&softn->ipf_nat_new);
5492                                         goto retry_roundrobin;
5493                                 }
5494                                 npnext = np->in_rnext;
5495                         }
5496
5497                         nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND);
5498                         MUTEX_EXIT(&softn->ipf_nat_new);
5499                         if (nat != NULL) {
5500                                 natfailed = 0;
5501                                 break;
5502                         }
5503                         natfailed = -1;
5504                 }
5505                 if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) {
5506                         rmsk++;
5507                         goto maskloop;
5508                 }
5509         }
5510
5511         if (nat != NULL) {
5512                 rval = ipf_nat_in(fin, nat, natadd, nflags);
5513                 if (rval == 1) {
5514                         MUTEX_ENTER(&nat->nat_lock);
5515                         ipf_nat_update(fin, nat);
5516                         nat->nat_bytes[0] += fin->fin_plen;
5517                         nat->nat_pkts[0]++;
5518                         fin->fin_pktnum = nat->nat_pkts[0];
5519                         MUTEX_EXIT(&nat->nat_lock);
5520                 }
5521         } else
5522                 rval = natfailed;
5523 inmatchfail:
5524         RWLOCK_EXIT(&softc->ipf_nat);
5525
5526         switch (rval)
5527         {
5528         case -1 :
5529                 if (passp != NULL) {
5530                         DT1(frb_natv4in, fr_info_t *, fin);
5531                         NBUMPSIDED(0, ns_drop);
5532                         *passp = FR_BLOCK;
5533                         fin->fin_reason = FRB_NATV4;
5534                 }
5535                 fin->fin_flx |= FI_BADNAT;
5536                 NBUMPSIDED(0, ns_badnat);
5537                 break;
5538         case 0 :
5539                 NBUMPSIDE(0, ns_ignored);
5540                 break;
5541         case 1 :
5542                 NBUMPSIDE(0, ns_translated);
5543                 break;
5544         }
5545         return rval;
5546 }
5547
5548
5549 /* ------------------------------------------------------------------------ */
5550 /* Function:    ipf_nat_in                                                  */
5551 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5552 /*                     1 == packet was successfully translated.             */
5553 /* Parameters:  fin(I)    - pointer to packet information                   */
5554 /*              nat(I)    - pointer to NAT structure                        */
5555 /*              natadd(I) - flag indicating if it is safe to add frag cache */
5556 /*              nflags(I) - NAT flags set for this packet                   */
5557 /* Locks Held:  ipf_nat(READ)                                               */
5558 /*                                                                          */
5559 /* Translate a packet coming "in" on an interface.                          */
5560 /* ------------------------------------------------------------------------ */
5561 int
5562 ipf_nat_in(fin, nat, natadd, nflags)
5563         fr_info_t *fin;
5564         nat_t *nat;
5565         int natadd;
5566         u_32_t nflags;
5567 {
5568         ipf_main_softc_t *softc = fin->fin_main_soft;
5569         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5570         u_32_t sumd, ipsumd, sum1, sum2;
5571         icmphdr_t *icmp;
5572         tcphdr_t *tcp;
5573         ipnat_t *np;
5574         int skip;
5575         int i;
5576
5577         tcp = NULL;
5578         np = nat->nat_ptr;
5579         fin->fin_fr = nat->nat_fr;
5580
5581         if (np != NULL) {
5582                 if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
5583                         (void) ipf_frag_natnew(softc, fin, 0, nat);
5584
5585         /* ------------------------------------------------------------- */
5586         /* A few quick notes:                                            */
5587         /*      Following are test conditions prior to calling the       */
5588         /*      ipf_proxy_check routine.                                 */
5589         /*                                                               */
5590         /*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5591         /*      with a map rule, we attempt to match the packet's        */
5592         /*      source port against in_dport, otherwise we'd compare the */
5593         /*      packet's destination.                                    */
5594         /* ------------------------------------------------------------- */
5595                 if (np->in_apr != NULL) {
5596                         i = ipf_proxy_check(fin, nat);
5597                         if (i == -1) {
5598                                 NBUMPSIDED(0, ns_ipf_proxy_fail);
5599                                 return -1;
5600                         }
5601                 }
5602         }
5603
5604         ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5605
5606         ipsumd = nat->nat_ipsumd;
5607         /*
5608          * Fix up checksums, not by recalculating them, but
5609          * simply computing adjustments.
5610          * Why only do this for some platforms on inbound packets ?
5611          * Because for those that it is done, IP processing is yet to happen
5612          * and so the IPv4 header checksum has not yet been evaluated.
5613          * Perhaps it should always be done for the benefit of things like
5614          * fast forwarding (so that it doesn't need to be recomputed) but with
5615          * header checksum offloading, perhaps it is a moot point.
5616          */
5617
5618         switch (nat->nat_dir)
5619         {
5620         case NAT_INBOUND :
5621                 if ((fin->fin_flx & FI_ICMPERR) == 0) {
5622                         fin->fin_ip->ip_src = nat->nat_nsrcip;
5623                         fin->fin_saddr = nat->nat_nsrcaddr;
5624                 } else {
5625                         sum1 = nat->nat_osrcaddr;
5626                         sum2 = nat->nat_nsrcaddr;
5627                         CALC_SUMD(sum1, sum2, sumd);
5628                         ipsumd -= sumd;
5629                 }
5630                 fin->fin_ip->ip_dst = nat->nat_ndstip;
5631                 fin->fin_daddr = nat->nat_ndstaddr;
5632 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5633      defined(__osf__) || defined(linux)
5634                 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5635 #endif
5636                 break;
5637
5638         case NAT_OUTBOUND :
5639                 if ((fin->fin_flx & FI_ICMPERR) == 0) {
5640                         fin->fin_ip->ip_src = nat->nat_odstip;
5641                         fin->fin_saddr = nat->nat_odstaddr;
5642                 } else {
5643                         sum1 = nat->nat_odstaddr;
5644                         sum2 = nat->nat_ndstaddr;
5645                         CALC_SUMD(sum1, sum2, sumd);
5646                         ipsumd -= sumd;
5647                 }
5648                 fin->fin_ip->ip_dst = nat->nat_osrcip;
5649                 fin->fin_daddr = nat->nat_osrcaddr;
5650 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5651      defined(__osf__) || defined(linux)
5652                 ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5653 #endif
5654                 break;
5655
5656         case NAT_DIVERTIN :
5657             {
5658                 udphdr_t *uh;
5659                 ip_t *ip;
5660                 mb_t *m;
5661
5662                 m = M_DUP(np->in_divmp);
5663                 if (m == NULL) {
5664                         NBUMPSIDED(0, ns_divert_dup);
5665                         return -1;
5666                 }
5667
5668                 ip = MTOD(m, ip_t *);
5669                 ip->ip_id = htons(ipf_nextipid(fin));
5670                 sum1 = ntohs(ip->ip_len);
5671                 ip->ip_len = ntohs(ip->ip_len);
5672                 ip->ip_len += fin->fin_plen;
5673                 ip->ip_len = htons(ip->ip_len);
5674
5675                 uh = (udphdr_t *)(ip + 1);
5676                 uh->uh_ulen += fin->fin_plen;
5677                 uh->uh_ulen = htons(uh->uh_ulen);
5678
5679                 sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len);
5680                 sum2 += ntohs(ip->ip_off) & IP_DF;
5681                 CALC_SUMD(sum1, sum2, sumd);
5682
5683 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5684      defined(__osf__) || defined(linux)
5685                 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5686 #endif
5687                 PREP_MB_T(fin, m);
5688
5689                 fin->fin_ip = ip;
5690                 fin->fin_plen += sizeof(ip_t) + 8;      /* UDP + new IPv4 hdr */
5691                 fin->fin_dlen += sizeof(ip_t) + 8;      /* UDP + old IPv4 hdr */
5692
5693                 nflags &= ~IPN_TCPUDPICMP;
5694
5695                 break;
5696             }
5697
5698         case NAT_DIVERTOUT :
5699             {
5700                 mb_t *m;
5701
5702                 skip = ipf_nat_decap(fin, nat);
5703                 if (skip <= 0) {
5704                         NBUMPSIDED(0, ns_decap_fail);
5705                         return -1;
5706                 }
5707
5708                 m = fin->fin_m;
5709
5710 #if defined(MENTAT) && defined(_KERNEL)
5711                 m->b_rptr += skip;
5712 #else
5713                 m->m_data += skip;
5714                 m->m_len -= skip;
5715
5716 # ifdef M_PKTHDR
5717                 if (m->m_flags & M_PKTHDR)
5718                         m->m_pkthdr.len -= skip;
5719 # endif
5720 #endif
5721
5722                 ipf_nat_update(fin, nat);
5723                 nflags &= ~IPN_TCPUDPICMP;
5724                 fin->fin_flx |= FI_NATED;
5725                 if (np != NULL && np->in_tag.ipt_num[0] != 0)
5726                         fin->fin_nattag = &np->in_tag;
5727                 return 1;
5728                 /* NOTREACHED */
5729             }
5730         }
5731         if (nflags & IPN_TCPUDP)
5732                 tcp = fin->fin_dp;
5733
5734         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5735                 u_short *csump;
5736
5737                 if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
5738                         switch (nat->nat_dir)
5739                         {
5740                         case NAT_INBOUND :
5741                                 tcp->th_sport = nat->nat_nsport;
5742                                 fin->fin_data[0] = ntohs(nat->nat_nsport);
5743                                 tcp->th_dport = nat->nat_ndport;
5744                                 fin->fin_data[1] = ntohs(nat->nat_ndport);
5745                                 break;
5746
5747                         case NAT_OUTBOUND :
5748                                 tcp->th_sport = nat->nat_odport;
5749                                 fin->fin_data[0] = ntohs(nat->nat_odport);
5750                                 tcp->th_dport = nat->nat_osport;
5751                                 fin->fin_data[1] = ntohs(nat->nat_osport);
5752                                 break;
5753                         }
5754                 }
5755
5756
5757                 if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
5758                         icmp = fin->fin_dp;
5759
5760                         icmp->icmp_id = nat->nat_nicmpid;
5761                 }
5762
5763                 csump = ipf_nat_proto(fin, nat, nflags);
5764
5765                 /*
5766                  * The above comments do not hold for layer 4 (or higher)
5767                  * checksums...
5768                  */
5769                 if (csump != NULL) {
5770                         if (nat->nat_dir == NAT_OUTBOUND)
5771                                 ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
5772                         else
5773                                 ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
5774                 }
5775         }
5776
5777         fin->fin_flx |= FI_NATED;
5778         if (np != NULL && np->in_tag.ipt_num[0] != 0)
5779                 fin->fin_nattag = &np->in_tag;
5780         return 1;
5781 }
5782
5783
5784 /* ------------------------------------------------------------------------ */
5785 /* Function:    ipf_nat_proto                                               */
5786 /* Returns:     u_short* - pointer to transport header checksum to update,  */
5787 /*                         NULL if the transport protocol is not recognised */
5788 /*                         as needing a checksum update.                    */
5789 /* Parameters:  fin(I)    - pointer to packet information                   */
5790 /*              nat(I)    - pointer to NAT structure                        */
5791 /*              nflags(I) - NAT flags set for this packet                   */
5792 /*                                                                          */
5793 /* Return the pointer to the checksum field for each protocol so understood.*/
5794 /* If support for making other changes to a protocol header is required,    */
5795 /* that is not strictly 'address' translation, such as clamping the MSS in  */
5796 /* TCP down to a specific value, then do it from here.                      */
5797 /* ------------------------------------------------------------------------ */
5798 u_short *
5799 ipf_nat_proto(fin, nat, nflags)
5800         fr_info_t *fin;
5801         nat_t *nat;
5802         u_int nflags;
5803 {
5804         icmphdr_t *icmp;
5805         u_short *csump;
5806         tcphdr_t *tcp;
5807         udphdr_t *udp;
5808
5809         csump = NULL;
5810         if (fin->fin_out == 0) {
5811                 fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND);
5812         } else {
5813                 fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0);
5814         }
5815
5816         switch (fin->fin_p)
5817         {
5818         case IPPROTO_TCP :
5819                 tcp = fin->fin_dp;
5820
5821                 if ((nflags & IPN_TCP) != 0)
5822                         csump = &tcp->th_sum;
5823
5824                 /*
5825                  * Do a MSS CLAMPING on a SYN packet,
5826                  * only deal IPv4 for now.
5827                  */
5828                 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
5829                         ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
5830
5831                 break;
5832
5833         case IPPROTO_UDP :
5834                 udp = fin->fin_dp;
5835
5836                 if ((nflags & IPN_UDP) != 0) {
5837                         if (udp->uh_sum != 0)
5838                                 csump = &udp->uh_sum;
5839                 }
5840                 break;
5841
5842         case IPPROTO_ICMP :
5843                 icmp = fin->fin_dp;
5844
5845                 if ((nflags & IPN_ICMPQUERY) != 0) {
5846                         if (icmp->icmp_cksum != 0)
5847                                 csump = &icmp->icmp_cksum;
5848                 }
5849                 break;
5850
5851 #ifdef USE_INET6
5852         case IPPROTO_ICMPV6 :
5853             {
5854                 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp;
5855
5856                 icmp6 = fin->fin_dp;
5857
5858                 if ((nflags & IPN_ICMPQUERY) != 0) {
5859                         if (icmp6->icmp6_cksum != 0)
5860                                 csump = &icmp6->icmp6_cksum;
5861                 }
5862                 break;
5863             }
5864 #endif
5865         }
5866         return csump;
5867 }
5868
5869
5870 /* ------------------------------------------------------------------------ */
5871 /* Function:    ipf_nat_expire                                              */
5872 /* Returns:     Nil                                                         */
5873 /* Parameters:  softc(I) - pointer to soft context main structure           */
5874 /*                                                                          */
5875 /* Check all of the timeout queues for entries at the top which need to be  */
5876 /* expired.                                                                 */
5877 /* ------------------------------------------------------------------------ */
5878 void
5879 ipf_nat_expire(softc)
5880         ipf_main_softc_t *softc;
5881 {
5882         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5883         ipftq_t *ifq, *ifqnext;
5884         ipftqent_t *tqe, *tqn;
5885         int i;
5886         SPL_INT(s);
5887
5888         SPL_NET(s);
5889         WRITE_ENTER(&softc->ipf_nat);
5890         for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL;
5891              ifq = ifq->ifq_next) {
5892                 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5893                         if (tqe->tqe_die > softc->ipf_ticks)
5894                                 break;
5895                         tqn = tqe->tqe_next;
5896                         ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5897                 }
5898         }
5899
5900         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) {
5901                 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5902                         if (tqe->tqe_die > softc->ipf_ticks)
5903                                 break;
5904                         tqn = tqe->tqe_next;
5905                         ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5906                 }
5907         }
5908
5909         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
5910                 ifqnext = ifq->ifq_next;
5911
5912                 if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
5913                     (ifq->ifq_ref == 0)) {
5914                         ipf_freetimeoutqueue(softc, ifq);
5915                 }
5916         }
5917
5918         if (softn->ipf_nat_doflush != 0) {
5919                 ipf_nat_extraflush(softc, softn, 2);
5920                 softn->ipf_nat_doflush = 0;
5921         }
5922
5923         RWLOCK_EXIT(&softc->ipf_nat);
5924         SPL_X(s);
5925 }
5926
5927
5928 /* ------------------------------------------------------------------------ */
5929 /* Function:    ipf_nat_sync                                                */
5930 /* Returns:     Nil                                                         */
5931 /* Parameters:  softc(I) - pointer to soft context main structure           */
5932 /*              ifp(I) - pointer to network interface                       */
5933 /*                                                                          */
5934 /* Walk through all of the currently active NAT sessions, looking for those */
5935 /* which need to have their translated address updated.                     */
5936 /* ------------------------------------------------------------------------ */
5937 void
5938 ipf_nat_sync(softc, ifp)
5939         ipf_main_softc_t *softc;
5940         void *ifp;
5941 {
5942         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5943         u_32_t sum1, sum2, sumd;
5944         i6addr_t in;
5945         ipnat_t *n;
5946         nat_t *nat;
5947         void *ifp2;
5948         int idx;
5949         SPL_INT(s);
5950
5951         if (softc->ipf_running <= 0)
5952                 return;
5953
5954         /*
5955          * Change IP addresses for NAT sessions for any protocol except TCP
5956          * since it will break the TCP connection anyway.  The only rules
5957          * which will get changed are those which are "map ... -> 0/32",
5958          * where the rule specifies the address is taken from the interface.
5959          */
5960         SPL_NET(s);
5961         WRITE_ENTER(&softc->ipf_nat);
5962
5963         if (softc->ipf_running <= 0) {
5964                 RWLOCK_EXIT(&softc->ipf_nat);
5965                 return;
5966         }
5967
5968         for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
5969                 if ((nat->nat_flags & IPN_TCP) != 0)
5970                         continue;
5971
5972                 n = nat->nat_ptr;
5973                 if (n != NULL) {
5974                         if (n->in_v[1] == 4) {
5975                                 if (n->in_redir & NAT_MAP) {
5976                                         if ((n->in_nsrcaddr != 0) ||
5977                                             (n->in_nsrcmsk != 0xffffffff))
5978                                                 continue;
5979                                 } else if (n->in_redir & NAT_REDIRECT) {
5980                                         if ((n->in_ndstaddr != 0) ||
5981                                             (n->in_ndstmsk != 0xffffffff))
5982                                                 continue;
5983                                 }
5984                         }
5985 #ifdef USE_INET6
5986                         if (n->in_v[1] == 4) {
5987                                 if (n->in_redir & NAT_MAP) {
5988                                         if (!IP6_ISZERO(&n->in_nsrcaddr) ||
5989                                             !IP6_ISONES(&n->in_nsrcmsk))
5990                                                 continue;
5991                                 } else if (n->in_redir & NAT_REDIRECT) {
5992                                         if (!IP6_ISZERO(&n->in_ndstaddr) ||
5993                                             !IP6_ISONES(&n->in_ndstmsk))
5994                                                 continue;
5995                                 }
5996                         }
5997 #endif
5998                 }
5999
6000                 if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) ||
6001                      (ifp == nat->nat_ifps[1]))) {
6002                         nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0],
6003                                                   nat->nat_v[0]);
6004                         if ((nat->nat_ifps[0] != NULL) &&
6005                             (nat->nat_ifps[0] != (void *)-1)) {
6006                                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
6007                         }
6008                         if (nat->nat_ifnames[1][0] != '\0') {
6009                                 nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1],
6010                                                           nat->nat_v[1]);
6011                         } else {
6012                                 nat->nat_ifps[1] = nat->nat_ifps[0];
6013                         }
6014                         if ((nat->nat_ifps[1] != NULL) &&
6015                             (nat->nat_ifps[1] != (void *)-1)) {
6016                                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
6017                         }
6018                         ifp2 = nat->nat_ifps[0];
6019                         if (ifp2 == NULL)
6020                                 continue;
6021
6022                         /*
6023                          * Change the map-to address to be the same as the
6024                          * new one.
6025                          */
6026                         sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6027                         if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2,
6028                                        &in, NULL) != -1) {
6029                                 if (nat->nat_v[0] == 4)
6030                                         nat->nat_nsrcip = in.in4;
6031                         }
6032                         sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6033
6034                         if (sum1 == sum2)
6035                                 continue;
6036                         /*
6037                          * Readjust the checksum adjustment to take into
6038                          * account the new IP#.
6039                          */
6040                         CALC_SUMD(sum1, sum2, sumd);
6041                         /* XXX - dont change for TCP when solaris does
6042                          * hardware checksumming.
6043                          */
6044                         sumd += nat->nat_sumd[0];
6045                         nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
6046                         nat->nat_sumd[1] = nat->nat_sumd[0];
6047                 }
6048         }
6049
6050         for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) {
6051                 char *base = n->in_names;
6052
6053                 if ((ifp == NULL) || (n->in_ifps[0] == ifp))
6054                         n->in_ifps[0] = ipf_resolvenic(softc,
6055                                                        base + n->in_ifnames[0],
6056                                                        n->in_v[0]);
6057                 if ((ifp == NULL) || (n->in_ifps[1] == ifp))
6058                         n->in_ifps[1] = ipf_resolvenic(softc,
6059                                                        base + n->in_ifnames[1],
6060                                                        n->in_v[1]);
6061
6062                 if (n->in_redir & NAT_REDIRECT)
6063                         idx = 1;
6064                 else
6065                         idx = 0;
6066
6067                 if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) &&
6068                     (n->in_ifps[idx] != NULL &&
6069                      n->in_ifps[idx] != (void *)-1)) {
6070
6071                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc,
6072                                              0, n->in_ifps[idx]);
6073                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst,
6074                                              0, n->in_ifps[idx]);
6075                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc,
6076                                              0, n->in_ifps[idx]);
6077                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst,
6078                                              0, n->in_ifps[idx]);
6079                 }
6080         }
6081         RWLOCK_EXIT(&softc->ipf_nat);
6082         SPL_X(s);
6083 }
6084
6085
6086 /* ------------------------------------------------------------------------ */
6087 /* Function:    ipf_nat_icmpquerytype                                       */
6088 /* Returns:     int - 1 == success, 0 == failure                            */
6089 /* Parameters:  icmptype(I) - ICMP type number                              */
6090 /*                                                                          */
6091 /* Tests to see if the ICMP type number passed is a query/response type or  */
6092 /* not.                                                                     */
6093 /* ------------------------------------------------------------------------ */
6094 static int
6095 ipf_nat_icmpquerytype(icmptype)
6096         int icmptype;
6097 {
6098
6099         /*
6100          * For the ICMP query NAT code, it is essential that both the query
6101          * and the reply match on the NAT rule. Because the NAT structure
6102          * does not keep track of the icmptype, and a single NAT structure
6103          * is used for all icmp types with the same src, dest and id, we
6104          * simply define the replies as queries as well. The funny thing is,
6105          * altough it seems silly to call a reply a query, this is exactly
6106          * as it is defined in the IPv4 specification
6107          */
6108         switch (icmptype)
6109         {
6110         case ICMP_ECHOREPLY:
6111         case ICMP_ECHO:
6112         /* route aedvertisement/solliciation is currently unsupported: */
6113         /* it would require rewriting the ICMP data section            */
6114         case ICMP_TSTAMP:
6115         case ICMP_TSTAMPREPLY:
6116         case ICMP_IREQ:
6117         case ICMP_IREQREPLY:
6118         case ICMP_MASKREQ:
6119         case ICMP_MASKREPLY:
6120                 return 1;
6121         default:
6122                 return 0;
6123         }
6124 }
6125
6126
6127 /* ------------------------------------------------------------------------ */
6128 /* Function:    nat_log                                                     */
6129 /* Returns:     Nil                                                         */
6130 /* Parameters:  softc(I) - pointer to soft context main structure           */
6131 /*              softn(I) - pointer to NAT context structure                 */
6132 /*              nat(I)    - pointer to NAT structure                        */
6133 /*              action(I) - action related to NAT structure being performed */
6134 /*                                                                          */
6135 /* Creates a NAT log entry.                                                 */
6136 /* ------------------------------------------------------------------------ */
6137 void
6138 ipf_nat_log(softc, softn, nat, action)
6139         ipf_main_softc_t *softc;
6140         ipf_nat_softc_t *softn;
6141         struct nat *nat;
6142         u_int action;
6143 {
6144 #ifdef  IPFILTER_LOG
6145 # ifndef LARGE_NAT
6146         struct ipnat *np;
6147         int rulen;
6148 # endif
6149         struct natlog natl;
6150         void *items[1];
6151         size_t sizes[1];
6152         int types[1];
6153
6154         bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip,
6155               sizeof(natl.nl_osrcip));
6156         bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip,
6157               sizeof(natl.nl_nsrcip));
6158         bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip,
6159               sizeof(natl.nl_odstip));
6160         bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip,
6161               sizeof(natl.nl_ndstip));
6162
6163         natl.nl_bytes[0] = nat->nat_bytes[0];
6164         natl.nl_bytes[1] = nat->nat_bytes[1];
6165         natl.nl_pkts[0] = nat->nat_pkts[0];
6166         natl.nl_pkts[1] = nat->nat_pkts[1];
6167         natl.nl_odstport = nat->nat_odport;
6168         natl.nl_osrcport = nat->nat_osport;
6169         natl.nl_nsrcport = nat->nat_nsport;
6170         natl.nl_ndstport = nat->nat_ndport;
6171         natl.nl_p[0] = nat->nat_pr[0];
6172         natl.nl_p[1] = nat->nat_pr[1];
6173         natl.nl_v[0] = nat->nat_v[0];
6174         natl.nl_v[1] = nat->nat_v[1];
6175         natl.nl_type = nat->nat_redir;
6176         natl.nl_action = action;
6177         natl.nl_rule = -1;
6178
6179         bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0],
6180               sizeof(nat->nat_ifnames[0]));
6181         bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1],
6182               sizeof(nat->nat_ifnames[1]));
6183
6184 # ifndef LARGE_NAT
6185         if (nat->nat_ptr != NULL) {
6186                 for (rulen = 0, np = softn->ipf_nat_list; np != NULL;
6187                      np = np->in_next, rulen++)
6188                         if (np == nat->nat_ptr) {
6189                                 natl.nl_rule = rulen;
6190                                 break;
6191                         }
6192         }
6193 # endif
6194         items[0] = &natl;
6195         sizes[0] = sizeof(natl);
6196         types[0] = 0;
6197
6198         (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1);
6199 #endif
6200 }
6201
6202
6203 #if defined(__OpenBSD__)
6204 /* ------------------------------------------------------------------------ */
6205 /* Function:    ipf_nat_ifdetach                                            */
6206 /* Returns:     Nil                                                         */
6207 /* Parameters:  ifp(I) - pointer to network interface                       */
6208 /*                                                                          */
6209 /* Compatibility interface for OpenBSD to trigger the correct updating of   */
6210 /* interface references within IPFilter.                                    */
6211 /* ------------------------------------------------------------------------ */
6212 void
6213 ipf_nat_ifdetach(ifp)
6214         void *ifp;
6215 {
6216         ipf_main_softc_t *softc;
6217
6218         softc = ipf_get_softc(0);
6219
6220         ipf_sync(ifp);
6221         return;
6222 }
6223 #endif
6224
6225
6226 /* ------------------------------------------------------------------------ */
6227 /* Function:    ipf_nat_rule_deref                                          */
6228 /* Returns:     Nil                                                         */
6229 /* Parameters:  softc(I) - pointer to soft context main structure           */
6230 /*              inp(I)   - pointer to pointer to NAT rule                   */
6231 /* Write Locks: ipf_nat                                                     */
6232 /*                                                                          */
6233 /* Dropping the refernce count for a rule means that whatever held the      */
6234 /* pointer to this rule (*inp) is no longer interested in it and when the   */
6235 /* reference count drops to zero, any resources allocated for the rule can  */
6236 /* be released and the rule itself free'd.                                  */
6237 /* ------------------------------------------------------------------------ */
6238 void
6239 ipf_nat_rule_deref(softc, inp)
6240         ipf_main_softc_t *softc;
6241         ipnat_t **inp;
6242 {
6243         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6244         ipnat_t *n;
6245
6246         n = *inp;
6247         *inp = NULL;
6248         n->in_use--;
6249         if (n->in_use > 0)
6250                 return;
6251
6252         if (n->in_apr != NULL)
6253                 ipf_proxy_deref(n->in_apr);
6254
6255         ipf_nat_rule_fini(softc, n);
6256
6257         if (n->in_redir & NAT_REDIRECT) {
6258                 if ((n->in_flags & IPN_PROXYRULE) == 0) {
6259                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr);
6260                 }
6261         }
6262         if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
6263                 if ((n->in_flags & IPN_PROXYRULE) == 0) {
6264                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map);
6265                 }
6266         }
6267
6268         if (n->in_tqehead[0] != NULL) {
6269                 if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
6270                         ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6271                 }
6272         }
6273
6274         if (n->in_tqehead[1] != NULL) {
6275                 if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
6276                         ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6277                 }
6278         }
6279
6280         if ((n->in_flags & IPN_PROXYRULE) == 0) {
6281                 ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules);
6282         }
6283
6284         MUTEX_DESTROY(&n->in_lock);
6285
6286         KFREES(n, n->in_size);
6287
6288 #if SOLARIS && !defined(INSTANCES)
6289         if (softn->ipf_nat_stats.ns_rules == 0)
6290                 pfil_delayed_copy = 1;
6291 #endif
6292 }
6293
6294
6295 /* ------------------------------------------------------------------------ */
6296 /* Function:    ipf_nat_deref                                               */
6297 /* Returns:     Nil                                                         */
6298 /* Parameters:  softc(I) - pointer to soft context main structure           */
6299 /*              natp(I)  - pointer to pointer to NAT table entry            */
6300 /*                                                                          */
6301 /* Decrement the reference counter for this NAT table entry and free it if  */
6302 /* there are no more things using it.                                       */
6303 /*                                                                          */
6304 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */
6305 /* structure *because* it only gets called on paths _after_ nat_ref has been*/
6306 /* incremented.  If nat_ref == 1 then we shouldn't decrement it here        */
6307 /* because nat_delete() will do that and send nat_ref to -1.                */
6308 /*                                                                          */
6309 /* Holding the lock on nat_lock is required to serialise nat_delete() being */
6310 /* called from a NAT flush ioctl with a deref happening because of a packet.*/
6311 /* ------------------------------------------------------------------------ */
6312 void
6313 ipf_nat_deref(softc, natp)
6314         ipf_main_softc_t *softc;
6315         nat_t **natp;
6316 {
6317         nat_t *nat;
6318
6319         nat = *natp;
6320         *natp = NULL;
6321
6322         MUTEX_ENTER(&nat->nat_lock);
6323         if (nat->nat_ref > 1) {
6324                 nat->nat_ref--;
6325                 ASSERT(nat->nat_ref >= 0);
6326                 MUTEX_EXIT(&nat->nat_lock);
6327                 return;
6328         }
6329         MUTEX_EXIT(&nat->nat_lock);
6330
6331         WRITE_ENTER(&softc->ipf_nat);
6332         ipf_nat_delete(softc, nat, NL_EXPIRE);
6333         RWLOCK_EXIT(&softc->ipf_nat);
6334 }
6335
6336
6337 /* ------------------------------------------------------------------------ */
6338 /* Function:    ipf_nat_clone                                               */
6339 /* Returns:     ipstate_t* - NULL == cloning failed,                        */
6340 /*                           else pointer to new state structure            */
6341 /* Parameters:  fin(I) - pointer to packet information                      */
6342 /*              is(I)  - pointer to master state structure                  */
6343 /* Write Lock:  ipf_nat                                                     */
6344 /*                                                                          */
6345 /* Create a "duplcate" state table entry from the master.                   */
6346 /* ------------------------------------------------------------------------ */
6347 nat_t *
6348 ipf_nat_clone(fin, nat)
6349         fr_info_t *fin;
6350         nat_t *nat;
6351 {
6352         ipf_main_softc_t *softc = fin->fin_main_soft;
6353         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6354         frentry_t *fr;
6355         nat_t *clone;
6356         ipnat_t *np;
6357
6358         KMALLOC(clone, nat_t *);
6359         if (clone == NULL) {
6360                 NBUMPSIDED(fin->fin_out, ns_clone_nomem);
6361                 return NULL;
6362         }
6363         bcopy((char *)nat, (char *)clone, sizeof(*clone));
6364
6365         MUTEX_NUKE(&clone->nat_lock);
6366
6367         clone->nat_rev = fin->fin_rev;
6368         clone->nat_aps = NULL;
6369         /*
6370          * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
6371          */
6372         clone->nat_tqe.tqe_pnext = NULL;
6373         clone->nat_tqe.tqe_next = NULL;
6374         clone->nat_tqe.tqe_ifq = NULL;
6375         clone->nat_tqe.tqe_parent = clone;
6376
6377         clone->nat_flags &= ~SI_CLONE;
6378         clone->nat_flags |= SI_CLONED;
6379
6380         if (clone->nat_hm)
6381                 clone->nat_hm->hm_ref++;
6382
6383         if (ipf_nat_insert(softc, softn, clone) == -1) {
6384                 KFREE(clone);
6385                 NBUMPSIDED(fin->fin_out, ns_insert_fail);
6386                 return NULL;
6387         }
6388
6389         np = clone->nat_ptr;
6390         if (np != NULL) {
6391                 if (softn->ipf_nat_logging)
6392                         ipf_nat_log(softc, softn, clone, NL_CLONE);
6393                 np->in_use++;
6394         }
6395         fr = clone->nat_fr;
6396         if (fr != NULL) {
6397                 MUTEX_ENTER(&fr->fr_lock);
6398                 fr->fr_ref++;
6399                 MUTEX_EXIT(&fr->fr_lock);
6400         }
6401
6402
6403         /*
6404          * Because the clone is created outside the normal loop of things and
6405          * TCP has special needs in terms of state, initialise the timeout
6406          * state of the new NAT from here.
6407          */
6408         if (clone->nat_pr[0] == IPPROTO_TCP) {
6409                 (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq,
6410                                    clone->nat_flags, 2);
6411         }
6412         clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone);
6413         if (softn->ipf_nat_logging)
6414                 ipf_nat_log(softc, softn, clone, NL_CLONE);
6415         return clone;
6416 }
6417
6418
6419 /* ------------------------------------------------------------------------ */
6420 /* Function:   ipf_nat_wildok                                               */
6421 /* Returns:    int - 1 == packet's ports match wildcards                    */
6422 /*                   0 == packet's ports don't match wildcards              */
6423 /* Parameters: nat(I)   - NAT entry                                         */
6424 /*             sport(I) - source port                                       */
6425 /*             dport(I) - destination port                                  */
6426 /*             flags(I) - wildcard flags                                    */
6427 /*             dir(I)   - packet direction                                  */
6428 /*                                                                          */
6429 /* Use NAT entry and packet direction to determine which combination of     */
6430 /* wildcard flags should be used.                                           */
6431 /* ------------------------------------------------------------------------ */
6432 int
6433 ipf_nat_wildok(nat, sport, dport, flags, dir)
6434         nat_t *nat;
6435         int sport, dport, flags, dir;
6436 {
6437         /*
6438          * When called by       dir is set to
6439          * nat_inlookup         NAT_INBOUND (0)
6440          * nat_outlookup        NAT_OUTBOUND (1)
6441          *
6442          * We simply combine the packet's direction in dir with the original
6443          * "intended" direction of that NAT entry in nat->nat_dir to decide
6444          * which combination of wildcard flags to allow.
6445          */
6446         switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)))
6447         {
6448         case 3: /* outbound packet / outbound entry */
6449                 if (((nat->nat_osport == sport) ||
6450                     (flags & SI_W_SPORT)) &&
6451                     ((nat->nat_odport == dport) ||
6452                     (flags & SI_W_DPORT)))
6453                         return 1;
6454                 break;
6455         case 2: /* outbound packet / inbound entry */
6456                 if (((nat->nat_osport == dport) ||
6457                     (flags & SI_W_SPORT)) &&
6458                     ((nat->nat_odport == sport) ||
6459                     (flags & SI_W_DPORT)))
6460                         return 1;
6461                 break;
6462         case 1: /* inbound packet / outbound entry */
6463                 if (((nat->nat_osport == dport) ||
6464                     (flags & SI_W_SPORT)) &&
6465                     ((nat->nat_odport == sport) ||
6466                     (flags & SI_W_DPORT)))
6467                         return 1;
6468                 break;
6469         case 0: /* inbound packet / inbound entry */
6470                 if (((nat->nat_osport == sport) ||
6471                     (flags & SI_W_SPORT)) &&
6472                     ((nat->nat_odport == dport) ||
6473                     (flags & SI_W_DPORT)))
6474                         return 1;
6475                 break;
6476         default:
6477                 break;
6478         }
6479
6480         return(0);
6481 }
6482
6483
6484 /* ------------------------------------------------------------------------ */
6485 /* Function:    nat_mssclamp                                                */
6486 /* Returns:     Nil                                                         */
6487 /* Parameters:  tcp(I)    - pointer to TCP header                           */
6488 /*              maxmss(I) - value to clamp the TCP MSS to                   */
6489 /*              fin(I)    - pointer to packet information                   */
6490 /*              csump(I)  - pointer to TCP checksum                         */
6491 /*                                                                          */
6492 /* Check for MSS option and clamp it if necessary.  If found and changed,   */
6493 /* then the TCP header checksum will be updated to reflect the change in    */
6494 /* the MSS.                                                                 */
6495 /* ------------------------------------------------------------------------ */
6496 static void
6497 ipf_nat_mssclamp(tcp, maxmss, fin, csump)
6498         tcphdr_t *tcp;
6499         u_32_t maxmss;
6500         fr_info_t *fin;
6501         u_short *csump;
6502 {
6503         u_char *cp, *ep, opt;
6504         int hlen, advance;
6505         u_32_t mss, sumd;
6506
6507         hlen = TCP_OFF(tcp) << 2;
6508         if (hlen > sizeof(*tcp)) {
6509                 cp = (u_char *)tcp + sizeof(*tcp);
6510                 ep = (u_char *)tcp + hlen;
6511
6512                 while (cp < ep) {
6513                         opt = cp[0];
6514                         if (opt == TCPOPT_EOL)
6515                                 break;
6516                         else if (opt == TCPOPT_NOP) {
6517                                 cp++;
6518                                 continue;
6519                         }
6520
6521                         if (cp + 1 >= ep)
6522                                 break;
6523                         advance = cp[1];
6524                         if ((cp + advance > ep) || (advance <= 0))
6525                                 break;
6526                         switch (opt)
6527                         {
6528                         case TCPOPT_MAXSEG:
6529                                 if (advance != 4)
6530                                         break;
6531                                 mss = cp[2] * 256 + cp[3];
6532                                 if (mss > maxmss) {
6533                                         cp[2] = maxmss / 256;
6534                                         cp[3] = maxmss & 0xff;
6535                                         CALC_SUMD(mss, maxmss, sumd);
6536                                         ipf_fix_outcksum(0, csump, sumd, 0);
6537                                 }
6538                                 break;
6539                         default:
6540                                 /* ignore unknown options */
6541                                 break;
6542                         }
6543
6544                         cp += advance;
6545                 }
6546         }
6547 }
6548
6549
6550 /* ------------------------------------------------------------------------ */
6551 /* Function:    ipf_nat_setqueue                                            */
6552 /* Returns:     Nil                                                         */
6553 /* Parameters:  softc(I) - pointer to soft context main structure           */
6554 /*              softn(I) - pointer to NAT context structure                 */
6555 /*              nat(I)- pointer to NAT structure                            */
6556 /* Locks:       ipf_nat (read or write)                                     */
6557 /*                                                                          */
6558 /* Put the NAT entry on its default queue entry, using rev as a helped in   */
6559 /* determining which queue it should be placed on.                          */
6560 /* ------------------------------------------------------------------------ */
6561 void
6562 ipf_nat_setqueue(softc, softn, nat)
6563         ipf_main_softc_t *softc;
6564         ipf_nat_softc_t *softn;
6565         nat_t *nat;
6566 {
6567         ipftq_t *oifq, *nifq;
6568         int rev = nat->nat_rev;
6569
6570         if (nat->nat_ptr != NULL)
6571                 nifq = nat->nat_ptr->in_tqehead[rev];
6572         else
6573                 nifq = NULL;
6574
6575         if (nifq == NULL) {
6576                 switch (nat->nat_pr[0])
6577                 {
6578                 case IPPROTO_UDP :
6579                         nifq = &softn->ipf_nat_udptq;
6580                         break;
6581                 case IPPROTO_ICMP :
6582                         nifq = &softn->ipf_nat_icmptq;
6583                         break;
6584                 case IPPROTO_TCP :
6585                         nifq = softn->ipf_nat_tcptq +
6586                                nat->nat_tqe.tqe_state[rev];
6587                         break;
6588                 default :
6589                         nifq = &softn->ipf_nat_iptq;
6590                         break;
6591                 }
6592         }
6593
6594         oifq = nat->nat_tqe.tqe_ifq;
6595         /*
6596          * If it's currently on a timeout queue, move it from one queue to
6597          * another, else put it on the end of the newly determined queue.
6598          */
6599         if (oifq != NULL)
6600                 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq);
6601         else
6602                 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat);
6603         return;
6604 }
6605
6606
6607 /* ------------------------------------------------------------------------ */
6608 /* Function:    nat_getnext                                                 */
6609 /* Returns:     int - 0 == ok, else error                                   */
6610 /* Parameters:  softc(I) - pointer to soft context main structure           */
6611 /*              t(I)   - pointer to ipftoken structure                      */
6612 /*              itp(I) - pointer to ipfgeniter_t structure                  */
6613 /*                                                                          */
6614 /* Fetch the next nat/ipnat structure pointer from the linked list and      */
6615 /* copy it out to the storage space pointed to by itp_data.  The next item  */
6616 /* in the list to look at is put back in the ipftoken struture.             */
6617 /* ------------------------------------------------------------------------ */
6618 static int
6619 ipf_nat_getnext(softc, t, itp, objp)
6620         ipf_main_softc_t *softc;
6621         ipftoken_t *t;
6622         ipfgeniter_t *itp;
6623         ipfobj_t *objp;
6624 {
6625         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6626         hostmap_t *hm, *nexthm = NULL, zerohm;
6627         ipnat_t *ipn, *nextipnat = NULL, zeroipn;
6628         nat_t *nat, *nextnat = NULL, zeronat;
6629         int error = 0;
6630         void *nnext;
6631
6632         if (itp->igi_nitems != 1) {
6633                 IPFERROR(60075);
6634                 return ENOSPC;
6635         }
6636
6637         READ_ENTER(&softc->ipf_nat);
6638
6639         switch (itp->igi_type)
6640         {
6641         case IPFGENITER_HOSTMAP :
6642                 hm = t->ipt_data;
6643                 if (hm == NULL) {
6644                         nexthm = softn->ipf_hm_maplist;
6645                 } else {
6646                         nexthm = hm->hm_next;
6647                 }
6648                 if (nexthm != NULL) {
6649                         ATOMIC_INC32(nexthm->hm_ref);
6650                         t->ipt_data = nexthm;
6651                 } else {
6652                         bzero(&zerohm, sizeof(zerohm));
6653                         nexthm = &zerohm;
6654                         t->ipt_data = NULL;
6655                 }
6656                 nnext = nexthm->hm_next;
6657                 break;
6658
6659         case IPFGENITER_IPNAT :
6660                 ipn = t->ipt_data;
6661                 if (ipn == NULL) {
6662                         nextipnat = softn->ipf_nat_list;
6663                 } else {
6664                         nextipnat = ipn->in_next;
6665                 }
6666                 if (nextipnat != NULL) {
6667                         ATOMIC_INC32(nextipnat->in_use);
6668                         t->ipt_data = nextipnat;
6669                 } else {
6670                         bzero(&zeroipn, sizeof(zeroipn));
6671                         nextipnat = &zeroipn;
6672                         t->ipt_data = NULL;
6673                 }
6674                 nnext = nextipnat->in_next;
6675                 break;
6676
6677         case IPFGENITER_NAT :
6678                 nat = t->ipt_data;
6679                 if (nat == NULL) {
6680                         nextnat = softn->ipf_nat_instances;
6681                 } else {
6682                         nextnat = nat->nat_next;
6683                 }
6684                 if (nextnat != NULL) {
6685                         MUTEX_ENTER(&nextnat->nat_lock);
6686                         nextnat->nat_ref++;
6687                         MUTEX_EXIT(&nextnat->nat_lock);
6688                         t->ipt_data = nextnat;
6689                 } else {
6690                         bzero(&zeronat, sizeof(zeronat));
6691                         nextnat = &zeronat;
6692                         t->ipt_data = NULL;
6693                 }
6694                 nnext = nextnat->nat_next;
6695                 break;
6696
6697         default :
6698                 RWLOCK_EXIT(&softc->ipf_nat);
6699                 IPFERROR(60055);
6700                 return EINVAL;
6701         }
6702
6703         RWLOCK_EXIT(&softc->ipf_nat);
6704
6705         objp->ipfo_ptr = itp->igi_data;
6706
6707         switch (itp->igi_type)
6708         {
6709         case IPFGENITER_HOSTMAP :
6710                 error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm));
6711                 if (error != 0) {
6712                         IPFERROR(60049);
6713                         error = EFAULT;
6714                 }
6715                 if (hm != NULL) {
6716                         WRITE_ENTER(&softc->ipf_nat);
6717                         ipf_nat_hostmapdel(softc, &hm);
6718                         RWLOCK_EXIT(&softc->ipf_nat);
6719                 }
6720                 break;
6721
6722         case IPFGENITER_IPNAT :
6723                 objp->ipfo_size = nextipnat->in_size;
6724                 objp->ipfo_type = IPFOBJ_IPNAT;
6725                 error = ipf_outobjk(softc, objp, nextipnat);
6726                 if (ipn != NULL) {
6727                         WRITE_ENTER(&softc->ipf_nat);
6728                         ipf_nat_rule_deref(softc, &ipn);
6729                         RWLOCK_EXIT(&softc->ipf_nat);
6730                 }
6731                 break;
6732
6733         case IPFGENITER_NAT :
6734                 objp->ipfo_size = sizeof(nat_t);
6735                 objp->ipfo_type = IPFOBJ_NAT;
6736                 error = ipf_outobjk(softc, objp, nextnat);
6737                 if (nat != NULL)
6738                         ipf_nat_deref(softc, &nat);
6739
6740                 break;
6741         }
6742
6743         if (nnext == NULL)
6744                 ipf_token_mark_complete(t);
6745
6746         return error;
6747 }
6748
6749
6750 /* ------------------------------------------------------------------------ */
6751 /* Function:    nat_extraflush                                              */
6752 /* Returns:     int - 0 == success, -1 == failure                           */
6753 /* Parameters:  softc(I) - pointer to soft context main structure           */
6754 /*              softn(I) - pointer to NAT context structure                 */
6755 /*              which(I) - how to flush the active NAT table                */
6756 /* Write Locks: ipf_nat                                                     */
6757 /*                                                                          */
6758 /* Flush nat tables.  Three actions currently defined:                      */
6759 /* which == 0 : flush all nat table entries                                 */
6760 /* which == 1 : flush TCP connections which have started to close but are   */
6761 /*            stuck for some reason.                                        */
6762 /* which == 2 : flush TCP connections which have been idle for a long time, */
6763 /*            starting at > 4 days idle and working back in successive half-*/
6764 /*            days to at most 12 hours old.  If this fails to free enough   */
6765 /*            slots then work backwards in half hour slots to 30 minutes.   */
6766 /*            If that too fails, then work backwards in 30 second intervals */
6767 /*            for the last 30 minutes to at worst 30 seconds idle.          */
6768 /* ------------------------------------------------------------------------ */
6769 static int
6770 ipf_nat_extraflush(softc, softn, which)
6771         ipf_main_softc_t *softc;
6772         ipf_nat_softc_t *softn;
6773         int which;
6774 {
6775         nat_t *nat, **natp;
6776         ipftqent_t *tqn;
6777         ipftq_t *ifq;
6778         int removed;
6779         SPL_INT(s);
6780
6781         removed = 0;
6782
6783         SPL_NET(s);
6784         switch (which)
6785         {
6786         case 0 :
6787                 softn->ipf_nat_stats.ns_flush_all++;
6788                 /*
6789                  * Style 0 flush removes everything...
6790                  */
6791                 for (natp = &softn->ipf_nat_instances;
6792                      ((nat = *natp) != NULL); ) {
6793                         ipf_nat_delete(softc, nat, NL_FLUSH);
6794                         removed++;
6795                 }
6796                 break;
6797
6798         case 1 :
6799                 softn->ipf_nat_stats.ns_flush_closing++;
6800                 /*
6801                  * Since we're only interested in things that are closing,
6802                  * we can start with the appropriate timeout queue.
6803                  */
6804                 for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT;
6805                      ifq != NULL; ifq = ifq->ifq_next) {
6806
6807                         for (tqn = ifq->ifq_head; tqn != NULL; ) {
6808                                 nat = tqn->tqe_parent;
6809                                 tqn = tqn->tqe_next;
6810                                 if (nat->nat_pr[0] != IPPROTO_TCP ||
6811                                     nat->nat_pr[1] != IPPROTO_TCP)
6812                                         break;
6813                                 ipf_nat_delete(softc, nat, NL_EXPIRE);
6814                                 removed++;
6815                         }
6816                 }
6817
6818                 /*
6819                  * Also need to look through the user defined queues.
6820                  */
6821                 for (ifq = softn->ipf_nat_utqe; ifq != NULL;
6822                      ifq = ifq->ifq_next) {
6823                         for (tqn = ifq->ifq_head; tqn != NULL; ) {
6824                                 nat = tqn->tqe_parent;
6825                                 tqn = tqn->tqe_next;
6826                                 if (nat->nat_pr[0] != IPPROTO_TCP ||
6827                                     nat->nat_pr[1] != IPPROTO_TCP)
6828                                         continue;
6829
6830                                 if ((nat->nat_tcpstate[0] >
6831                                      IPF_TCPS_ESTABLISHED) &&
6832                                     (nat->nat_tcpstate[1] >
6833                                      IPF_TCPS_ESTABLISHED)) {
6834                                         ipf_nat_delete(softc, nat, NL_EXPIRE);
6835                                         removed++;
6836                                 }
6837                         }
6838                 }
6839                 break;
6840
6841                 /*
6842                  * Args 5-11 correspond to flushing those particular states
6843                  * for TCP connections.
6844                  */
6845         case IPF_TCPS_CLOSE_WAIT :
6846         case IPF_TCPS_FIN_WAIT_1 :
6847         case IPF_TCPS_CLOSING :
6848         case IPF_TCPS_LAST_ACK :
6849         case IPF_TCPS_FIN_WAIT_2 :
6850         case IPF_TCPS_TIME_WAIT :
6851         case IPF_TCPS_CLOSED :
6852                 softn->ipf_nat_stats.ns_flush_state++;
6853                 tqn = softn->ipf_nat_tcptq[which].ifq_head;
6854                 while (tqn != NULL) {
6855                         nat = tqn->tqe_parent;
6856                         tqn = tqn->tqe_next;
6857                         ipf_nat_delete(softc, nat, NL_FLUSH);
6858                         removed++;
6859                 }
6860                 break;
6861
6862         default :
6863                 if (which < 30)
6864                         break;
6865
6866                 softn->ipf_nat_stats.ns_flush_timeout++;
6867                 /*
6868                  * Take a large arbitrary number to mean the number of seconds
6869                  * for which which consider to be the maximum value we'll allow
6870                  * the expiration to be.
6871                  */
6872                 which = IPF_TTLVAL(which);
6873                 for (natp = &softn->ipf_nat_instances;
6874                      ((nat = *natp) != NULL); ) {
6875                         if (softc->ipf_ticks - nat->nat_touched > which) {
6876                                 ipf_nat_delete(softc, nat, NL_FLUSH);
6877                                 removed++;
6878                         } else
6879                                 natp = &nat->nat_next;
6880                 }
6881                 break;
6882         }
6883
6884         if (which != 2) {
6885                 SPL_X(s);
6886                 return removed;
6887         }
6888
6889         softn->ipf_nat_stats.ns_flush_queue++;
6890
6891         /*
6892          * Asked to remove inactive entries because the table is full, try
6893          * again, 3 times, if first attempt failed with a different criteria
6894          * each time.  The order tried in must be in decreasing age.
6895          * Another alternative is to implement random drop and drop N entries
6896          * at random until N have been freed up.
6897          */
6898         if (softc->ipf_ticks - softn->ipf_nat_last_force_flush >
6899             IPF_TTLVAL(5)) {
6900                 softn->ipf_nat_last_force_flush = softc->ipf_ticks;
6901
6902                 removed = ipf_queueflush(softc, ipf_nat_flush_entry,
6903                                          softn->ipf_nat_tcptq,
6904                                          softn->ipf_nat_utqe,
6905                                          &softn->ipf_nat_stats.ns_active,
6906                                          softn->ipf_nat_table_sz,
6907                                          softn->ipf_nat_table_wm_low);
6908         }
6909
6910         SPL_X(s);
6911         return removed;
6912 }
6913
6914
6915 /* ------------------------------------------------------------------------ */
6916 /* Function:    ipf_nat_flush_entry                                         */
6917 /* Returns:     0 - always succeeds                                         */
6918 /* Parameters:  softc(I) - pointer to soft context main structure           */
6919 /*              entry(I) - pointer to NAT entry                             */
6920 /* Write Locks: ipf_nat                                                     */
6921 /*                                                                          */
6922 /* This function is a stepping stone between ipf_queueflush() and           */
6923 /* nat_dlete().  It is used so we can provide a uniform interface via the   */
6924 /* ipf_queueflush() function.  Since the nat_delete() function returns void */
6925 /* we translate that to mean it always succeeds in deleting something.      */
6926 /* ------------------------------------------------------------------------ */
6927 static int
6928 ipf_nat_flush_entry(softc, entry)
6929         ipf_main_softc_t *softc;
6930         void *entry;
6931 {
6932         ipf_nat_delete(softc, entry, NL_FLUSH);
6933         return 0;
6934 }
6935
6936
6937 /* ------------------------------------------------------------------------ */
6938 /* Function:    ipf_nat_iterator                                            */
6939 /* Returns:     int - 0 == ok, else error                                   */
6940 /* Parameters:  softc(I) - pointer to soft context main structure           */
6941 /*              token(I) - pointer to ipftoken structure                    */
6942 /*              itp(I)   - pointer to ipfgeniter_t structure                */
6943 /*              obj(I)   - pointer to data description structure            */
6944 /*                                                                          */
6945 /* This function acts as a handler for the SIOCGENITER ioctls that use a    */
6946 /* generic structure to iterate through a list.  There are three different  */
6947 /* linked lists of NAT related information to go through: NAT rules, active */
6948 /* NAT mappings and the NAT fragment cache.                                 */
6949 /* ------------------------------------------------------------------------ */
6950 static int
6951 ipf_nat_iterator(softc, token, itp, obj)
6952         ipf_main_softc_t *softc;
6953         ipftoken_t *token;
6954         ipfgeniter_t *itp;
6955         ipfobj_t *obj;
6956 {
6957         int error;
6958
6959         if (itp->igi_data == NULL) {
6960                 IPFERROR(60052);
6961                 return EFAULT;
6962         }
6963
6964         switch (itp->igi_type)
6965         {
6966         case IPFGENITER_HOSTMAP :
6967         case IPFGENITER_IPNAT :
6968         case IPFGENITER_NAT :
6969                 error = ipf_nat_getnext(softc, token, itp, obj);
6970                 break;
6971
6972         case IPFGENITER_NATFRAG :
6973                 error = ipf_frag_nat_next(softc, token, itp);
6974                 break;
6975         default :
6976                 IPFERROR(60053);
6977                 error = EINVAL;
6978                 break;
6979         }
6980
6981         return error;
6982 }
6983
6984
6985 /* ------------------------------------------------------------------------ */
6986 /* Function:    ipf_nat_setpending                                          */
6987 /* Returns:     Nil                                                         */
6988 /* Parameters:  softc(I) - pointer to soft context main structure           */
6989 /*              nat(I)   - pointer to NAT structure                         */
6990 /* Locks:       ipf_nat (read or write)                                     */
6991 /*                                                                          */
6992 /* Put the NAT entry on to the pending queue - this queue has a very short  */
6993 /* lifetime where items are put that can't be deleted straight away because */
6994 /* of locking issues but we want to delete them ASAP, anyway.  In calling   */
6995 /* this function, it is assumed that the owner (if there is one, as shown   */
6996 /* by nat_me) is no longer interested in it.                                */
6997 /* ------------------------------------------------------------------------ */
6998 void
6999 ipf_nat_setpending(softc, nat)
7000         ipf_main_softc_t *softc;
7001         nat_t *nat;
7002 {
7003         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7004         ipftq_t *oifq;
7005
7006         oifq = nat->nat_tqe.tqe_ifq;
7007         if (oifq != NULL)
7008                 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq,
7009                               &softn->ipf_nat_pending);
7010         else
7011                 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe,
7012                                 &softn->ipf_nat_pending, nat);
7013
7014         if (nat->nat_me != NULL) {
7015                 *nat->nat_me = NULL;
7016                 nat->nat_me = NULL;
7017                 nat->nat_ref--;
7018                 ASSERT(nat->nat_ref >= 0);
7019         }
7020 }
7021
7022
7023 /* ------------------------------------------------------------------------ */
7024 /* Function:    nat_newrewrite                                              */
7025 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
7026 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
7027 /* Parameters:  fin(I) - pointer to packet information                      */
7028 /*              nat(I) - pointer to NAT entry                               */
7029 /*              ni(I)  - pointer to structure with misc. information needed */
7030 /*                       to create new NAT entry.                           */
7031 /* Write Lock:  ipf_nat                                                     */
7032 /*                                                                          */
7033 /* This function is responsible for setting up an active NAT session where  */
7034 /* we are changing both the source and destination parameters at the same   */
7035 /* time.  The loop in here works differently to elsewhere - each iteration  */
7036 /* is responsible for changing a single parameter that can be incremented.  */
7037 /* So one pass may increase the source IP#, next source port, next dest. IP#*/
7038 /* and the last destination port for a total of 4 iterations to try each.   */
7039 /* This is done to try and exhaustively use the translation space available.*/
7040 /* ------------------------------------------------------------------------ */
7041 static int
7042 ipf_nat_newrewrite(fin, nat, nai)
7043         fr_info_t *fin;
7044         nat_t *nat;
7045         natinfo_t *nai;
7046 {
7047         int src_search = 1;
7048         int dst_search = 1;
7049         fr_info_t frnat;
7050         u_32_t flags;
7051         u_short swap;
7052         ipnat_t *np;
7053         nat_t *natl;
7054         int l = 0;
7055         int changed;
7056
7057         natl = NULL;
7058         changed = -1;
7059         np = nai->nai_np;
7060         flags = nat->nat_flags;
7061         bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7062
7063         nat->nat_hm = NULL;
7064
7065         do {
7066                 changed = -1;
7067                 /* TRACE (l, src_search, dst_search, np) */
7068
7069                 if ((src_search == 0) && (np->in_spnext == 0) &&
7070                     (dst_search == 0) && (np->in_dpnext == 0)) {
7071                         if (l > 0)
7072                                 return -1;
7073                 }
7074
7075                 /*
7076                  * Find a new source address
7077                  */
7078                 if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr,
7079                                      &frnat.fin_saddr) == -1) {
7080                         return -1;
7081                 }
7082
7083                 if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) {
7084                         src_search = 0;
7085                         if (np->in_stepnext == 0)
7086                                 np->in_stepnext = 1;
7087
7088                 } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
7089                         src_search = 0;
7090                         if (np->in_stepnext == 0)
7091                                 np->in_stepnext = 1;
7092
7093                 } else if (np->in_nsrcmsk == 0xffffffff) {
7094                         src_search = 0;
7095                         if (np->in_stepnext == 0)
7096                                 np->in_stepnext = 1;
7097
7098                 } else if (np->in_nsrcmsk != 0xffffffff) {
7099                         if (np->in_stepnext == 0 && changed == -1) {
7100                                 np->in_snip++;
7101                                 np->in_stepnext++;
7102                                 changed = 0;
7103                         }
7104                 }
7105
7106                 if ((flags & IPN_TCPUDPICMP) != 0) {
7107                         if (np->in_spnext != 0)
7108                                 frnat.fin_data[0] = np->in_spnext;
7109
7110                         /*
7111                          * Standard port translation.  Select next port.
7112                          */
7113                         if ((flags & IPN_FIXEDSPORT) != 0) {
7114                                 np->in_stepnext = 2;
7115                         } else if ((np->in_stepnext == 1) &&
7116                                    (changed == -1) && (natl != NULL)) {
7117                                 np->in_spnext++;
7118                                 np->in_stepnext++;
7119                                 changed = 1;
7120                                 if (np->in_spnext > np->in_spmax)
7121                                         np->in_spnext = np->in_spmin;
7122                         }
7123                 } else {
7124                         np->in_stepnext = 2;
7125                 }
7126                 np->in_stepnext &= 0x3;
7127
7128                 /*
7129                  * Find a new destination address
7130                  */
7131                 /* TRACE (fin, np, l, frnat) */
7132
7133                 if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr,
7134                                      &frnat.fin_daddr) == -1)
7135                         return -1;
7136                 if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
7137                         dst_search = 0;
7138                         if (np->in_stepnext == 2)
7139                                 np->in_stepnext = 3;
7140
7141                 } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) {
7142                         dst_search = 0;
7143                         if (np->in_stepnext == 2)
7144                                 np->in_stepnext = 3;
7145
7146                 } else if (np->in_ndstmsk == 0xffffffff) {
7147                         dst_search = 0;
7148                         if (np->in_stepnext == 2)
7149                                 np->in_stepnext = 3;
7150
7151                 } else if (np->in_ndstmsk != 0xffffffff) {
7152                         if ((np->in_stepnext == 2) && (changed == -1) &&
7153                             (natl != NULL)) {
7154                                 changed = 2;
7155                                 np->in_stepnext++;
7156                                 np->in_dnip++;
7157                         }
7158                 }
7159
7160                 if ((flags & IPN_TCPUDPICMP) != 0) {
7161                         if (np->in_dpnext != 0)
7162                                 frnat.fin_data[1] = np->in_dpnext;
7163
7164                         /*
7165                          * Standard port translation.  Select next port.
7166                          */
7167                         if ((flags & IPN_FIXEDDPORT) != 0) {
7168                                 np->in_stepnext = 0;
7169                         } else if (np->in_stepnext == 3 && changed == -1) {
7170                                 np->in_dpnext++;
7171                                 np->in_stepnext++;
7172                                 changed = 3;
7173                                 if (np->in_dpnext > np->in_dpmax)
7174                                         np->in_dpnext = np->in_dpmin;
7175                         }
7176                 } else {
7177                         if (np->in_stepnext == 3)
7178                                 np->in_stepnext = 0;
7179                 }
7180
7181                 /* TRACE (frnat) */
7182
7183                 /*
7184                  * Here we do a lookup of the connection as seen from
7185                  * the outside.  If an IP# pair already exists, try
7186                  * again.  So if you have A->B becomes C->B, you can
7187                  * also have D->E become C->E but not D->B causing
7188                  * another C->B.  Also take protocol and ports into
7189                  * account when determining whether a pre-existing
7190                  * NAT setup will cause an external conflict where
7191                  * this is appropriate.
7192                  *
7193                  * fin_data[] is swapped around because we are doing a
7194                  * lookup of the packet is if it were moving in the opposite
7195                  * direction of the one we are working with now.
7196                  */
7197                 if (flags & IPN_TCPUDP) {
7198                         swap = frnat.fin_data[0];
7199                         frnat.fin_data[0] = frnat.fin_data[1];
7200                         frnat.fin_data[1] = swap;
7201                 }
7202                 if (fin->fin_out == 1) {
7203                         natl = ipf_nat_inlookup(&frnat,
7204                                                 flags & ~(SI_WILDP|NAT_SEARCH),
7205                                                 (u_int)frnat.fin_p,
7206                                                 frnat.fin_dst, frnat.fin_src);
7207
7208                 } else {
7209                         natl = ipf_nat_outlookup(&frnat,
7210                                                  flags & ~(SI_WILDP|NAT_SEARCH),
7211                                                  (u_int)frnat.fin_p,
7212                                                  frnat.fin_dst, frnat.fin_src);
7213                 }
7214                 if (flags & IPN_TCPUDP) {
7215                         swap = frnat.fin_data[0];
7216                         frnat.fin_data[0] = frnat.fin_data[1];
7217                         frnat.fin_data[1] = swap;
7218                 }
7219
7220                 /* TRACE natl, in_stepnext, l */
7221
7222                 if ((natl != NULL) && (l > 8))  /* XXX 8 is arbitrary */
7223                         return -1;
7224
7225                 np->in_stepnext &= 0x3;
7226
7227                 l++;
7228                 changed = -1;
7229         } while (natl != NULL);
7230
7231         nat->nat_osrcip = fin->fin_src;
7232         nat->nat_odstip = fin->fin_dst;
7233         nat->nat_nsrcip = frnat.fin_src;
7234         nat->nat_ndstip = frnat.fin_dst;
7235
7236         if ((flags & IPN_TCPUDP) != 0) {
7237                 nat->nat_osport = htons(fin->fin_data[0]);
7238                 nat->nat_odport = htons(fin->fin_data[1]);
7239                 nat->nat_nsport = htons(frnat.fin_data[0]);
7240                 nat->nat_ndport = htons(frnat.fin_data[1]);
7241         } else if ((flags & IPN_ICMPQUERY) != 0) {
7242                 nat->nat_oicmpid = fin->fin_data[1];
7243                 nat->nat_nicmpid = frnat.fin_data[1];
7244         }
7245
7246         return 0;
7247 }
7248
7249
7250 /* ------------------------------------------------------------------------ */
7251 /* Function:    nat_newdivert                                               */
7252 /* Returns:     int - -1 == error, 0 == success                             */
7253 /* Parameters:  fin(I) - pointer to packet information                      */
7254 /*              nat(I) - pointer to NAT entry                               */
7255 /*              ni(I)  - pointer to structure with misc. information needed */
7256 /*                       to create new NAT entry.                           */
7257 /* Write Lock:  ipf_nat                                                     */
7258 /*                                                                          */
7259 /* Create a new NAT  divert session as defined by the NAT rule.  This is    */
7260 /* somewhat different to other NAT session creation routines because we     */
7261 /* do not iterate through either port numbers or IP addresses, searching    */
7262 /* for a unique mapping, however, a complimentary duplicate check is made.  */
7263 /* ------------------------------------------------------------------------ */
7264 static int
7265 ipf_nat_newdivert(fin, nat, nai)
7266         fr_info_t *fin;
7267         nat_t *nat;
7268         natinfo_t *nai;
7269 {
7270         ipf_main_softc_t *softc = fin->fin_main_soft;
7271         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7272         fr_info_t frnat;
7273         ipnat_t *np;
7274         nat_t *natl;
7275         int p;
7276
7277         np = nai->nai_np;
7278         bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7279
7280         nat->nat_pr[0] = 0;
7281         nat->nat_osrcaddr = fin->fin_saddr;
7282         nat->nat_odstaddr = fin->fin_daddr;
7283         frnat.fin_saddr = htonl(np->in_snip);
7284         frnat.fin_daddr = htonl(np->in_dnip);
7285         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7286                 nat->nat_osport = htons(fin->fin_data[0]);
7287                 nat->nat_odport = htons(fin->fin_data[1]);
7288         } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7289                 nat->nat_oicmpid = fin->fin_data[1];
7290         }
7291
7292         if (np->in_redir & NAT_DIVERTUDP) {
7293                 frnat.fin_data[0] = np->in_spnext;
7294                 frnat.fin_data[1] = np->in_dpnext;
7295                 frnat.fin_flx |= FI_TCPUDP;
7296                 p = IPPROTO_UDP;
7297         } else {
7298                 frnat.fin_flx &= ~FI_TCPUDP;
7299                 p = IPPROTO_IPIP;
7300         }
7301
7302         if (fin->fin_out == 1) {
7303                 natl = ipf_nat_inlookup(&frnat, 0, p,
7304                                         frnat.fin_dst, frnat.fin_src);
7305
7306         } else {
7307                 natl = ipf_nat_outlookup(&frnat, 0, p,
7308                                          frnat.fin_dst, frnat.fin_src);
7309         }
7310
7311         if (natl != NULL) {
7312                 NBUMPSIDED(fin->fin_out, ns_divert_exist);
7313                 return -1;
7314         }
7315
7316         nat->nat_nsrcaddr = frnat.fin_saddr;
7317         nat->nat_ndstaddr = frnat.fin_daddr;
7318         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7319                 nat->nat_nsport = htons(frnat.fin_data[0]);
7320                 nat->nat_ndport = htons(frnat.fin_data[1]);
7321         } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7322                 nat->nat_nicmpid = frnat.fin_data[1];
7323         }
7324
7325         nat->nat_pr[fin->fin_out] = fin->fin_p;
7326         nat->nat_pr[1 - fin->fin_out] = p;
7327
7328         if (np->in_redir & NAT_REDIRECT)
7329                 nat->nat_dir = NAT_DIVERTIN;
7330         else
7331                 nat->nat_dir = NAT_DIVERTOUT;
7332
7333         return 0;
7334 }
7335
7336
7337 /* ------------------------------------------------------------------------ */
7338 /* Function:    nat_builddivertmp                                           */
7339 /* Returns:     int - -1 == error, 0 == success                             */
7340 /* Parameters:  softn(I) - pointer to NAT context structure                 */
7341 /*              np(I)    - pointer to a NAT rule                            */
7342 /*                                                                          */
7343 /* For divert rules, a skeleton packet representing what will be prepended  */
7344 /* to the real packet is created.  Even though we don't have the full       */
7345 /* packet here, a checksum is calculated that we update later when we       */
7346 /* fill in the final details.  At present a 0 checksum for UDP is being set */
7347 /* here because it is expected that divert will be used for localhost.      */
7348 /* ------------------------------------------------------------------------ */
7349 static int
7350 ipf_nat_builddivertmp(softn, np)
7351         ipf_nat_softc_t *softn;
7352         ipnat_t *np;
7353 {
7354         udphdr_t *uh;
7355         size_t len;
7356         ip_t *ip;
7357
7358         if ((np->in_redir & NAT_DIVERTUDP) != 0)
7359                 len = sizeof(ip_t) + sizeof(udphdr_t);
7360         else
7361                 len = sizeof(ip_t);
7362
7363         ALLOC_MB_T(np->in_divmp, len);
7364         if (np->in_divmp == NULL) {
7365                 NBUMPD(ipf_nat_stats, ns_divert_build);
7366                 return -1;
7367         }
7368
7369         /*
7370          * First, the header to get the packet diverted to the new destination
7371          */
7372         ip = MTOD(np->in_divmp, ip_t *);
7373         IP_V_A(ip, 4);
7374         IP_HL_A(ip, 5);
7375         ip->ip_tos = 0;
7376         if ((np->in_redir & NAT_DIVERTUDP) != 0)
7377                 ip->ip_p = IPPROTO_UDP;
7378         else
7379                 ip->ip_p = IPPROTO_IPIP;
7380         ip->ip_ttl = 255;
7381         ip->ip_off = 0;
7382         ip->ip_sum = 0;
7383         ip->ip_len = htons(len);
7384         ip->ip_id = 0;
7385         ip->ip_src.s_addr = htonl(np->in_snip);
7386         ip->ip_dst.s_addr = htonl(np->in_dnip);
7387         ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
7388
7389         if (np->in_redir & NAT_DIVERTUDP) {
7390                 uh = (udphdr_t *)(ip + 1);
7391                 uh->uh_sum = 0;
7392                 uh->uh_ulen = 8;
7393                 uh->uh_sport = htons(np->in_spnext);
7394                 uh->uh_dport = htons(np->in_dpnext);
7395         }
7396
7397         return 0;
7398 }
7399
7400
7401 #define MINDECAP        (sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t))
7402
7403 /* ------------------------------------------------------------------------ */
7404 /* Function:    nat_decap                                                   */
7405 /* Returns:     int - -1 == error, 0 == success                             */
7406 /* Parameters:  fin(I) - pointer to packet information                      */
7407 /*              nat(I) - pointer to current NAT session                     */
7408 /*                                                                          */
7409 /* This function is responsible for undoing a packet's encapsulation in the */
7410 /* reverse of an encap/divert rule.  After removing the outer encapsulation */
7411 /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
7412 /* match the "new" packet as it may still be used by IPFilter elsewhere.    */
7413 /* We use "dir" here as the basis for some of the expectations about the    */
7414 /* outer header.  If we return an error, the goal is to leave the original  */
7415 /* packet information undisturbed - this falls short at the end where we'd  */
7416 /* need to back a backup copy of "fin" - expensive.                         */
7417 /* ------------------------------------------------------------------------ */
7418 static int
7419 ipf_nat_decap(fin, nat)
7420         fr_info_t *fin;
7421         nat_t *nat;
7422 {
7423         ipf_main_softc_t *softc = fin->fin_main_soft;
7424         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7425         char *hdr;
7426         int hlen;
7427         int skip;
7428         mb_t *m;
7429
7430         if ((fin->fin_flx & FI_ICMPERR) != 0) {
7431                 /*
7432                  * ICMP packets don't get decapsulated, instead what we need
7433                  * to do is change the ICMP reply from including (in the data
7434                  * portion for errors) the encapsulated packet that we sent
7435                  * out to something that resembles the original packet prior
7436                  * to encapsulation.  This isn't done here - all we're doing
7437                  * here is changing the outer address to ensure that it gets
7438                  * targetted back to the correct system.
7439                  */
7440
7441                 if (nat->nat_dir & NAT_OUTBOUND) {
7442                         u_32_t sum1, sum2, sumd;
7443
7444                         sum1 = ntohl(fin->fin_daddr);
7445                         sum2 = ntohl(nat->nat_osrcaddr);
7446                         CALC_SUMD(sum1, sum2, sumd);
7447                         fin->fin_ip->ip_dst = nat->nat_osrcip;
7448                         fin->fin_daddr = nat->nat_osrcaddr;
7449 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
7450      defined(__osf__) || defined(linux)
7451                         ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0);
7452 #endif
7453                 }
7454                 return 0;
7455         }
7456
7457         m = fin->fin_m;
7458         skip = fin->fin_hlen;
7459
7460         switch (nat->nat_dir)
7461         {
7462         case NAT_DIVERTIN :
7463         case NAT_DIVERTOUT :
7464                 if (fin->fin_plen < MINDECAP)
7465                         return -1;
7466                 skip += sizeof(udphdr_t);
7467                 break;
7468
7469         case NAT_ENCAPIN :
7470         case NAT_ENCAPOUT :
7471                 if (fin->fin_plen < (skip + sizeof(ip_t)))
7472                         return -1;
7473                 break;
7474         default :
7475                 return -1;
7476                 /* NOTREACHED */
7477         }
7478
7479         /*
7480          * The aim here is to keep the original packet details in "fin" for
7481          * as long as possible so that returning with an error is for the
7482          * original packet and there is little undoing work to do.
7483          */
7484         if (M_LEN(m) < skip + sizeof(ip_t)) {
7485                 if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1)
7486                         return -1;
7487         }
7488
7489         hdr = MTOD(fin->fin_m, char *);
7490         fin->fin_ip = (ip_t *)(hdr + skip);
7491         hlen = IP_HL(fin->fin_ip) << 2;
7492
7493         if (ipf_pr_pullup(fin, skip + hlen) == -1) {
7494                 NBUMPSIDED(fin->fin_out, ns_decap_pullup);
7495                 return -1;
7496         }
7497
7498         fin->fin_hlen = hlen;
7499         fin->fin_dlen -= skip;
7500         fin->fin_plen -= skip;
7501         fin->fin_ipoff += skip;
7502
7503         if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) {
7504                 NBUMPSIDED(fin->fin_out, ns_decap_bad);
7505                 return -1;
7506         }
7507
7508         return skip;
7509 }
7510
7511
7512 /* ------------------------------------------------------------------------ */
7513 /* Function:    nat_nextaddr                                                */
7514 /* Returns:     int - -1 == bad input (no new address),                     */
7515 /*                     0 == success and dst has new address                 */
7516 /* Parameters:  fin(I) - pointer to packet information                      */
7517 /*              na(I)  - how to generate new address                        */
7518 /*              old(I) - original address being replaced                    */
7519 /*              dst(O) - where to put the new address                       */
7520 /* Write Lock:  ipf_nat                                                     */
7521 /*                                                                          */
7522 /* This function uses the contents of the "na" structure, in combination    */
7523 /* with "old" to produce a new address to store in "dst".  Not all of the   */
7524 /* possible uses of "na" will result in a new address.                      */
7525 /* ------------------------------------------------------------------------ */
7526 static int
7527 ipf_nat_nextaddr(fin, na, old, dst)
7528         fr_info_t *fin;
7529         nat_addr_t *na;
7530         u_32_t *old, *dst;
7531 {
7532         ipf_main_softc_t *softc = fin->fin_main_soft;
7533         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7534         u_32_t amin, amax, new;
7535         i6addr_t newip;
7536         int error;
7537
7538         new = 0;
7539         amin = na->na_addr[0].in4.s_addr;
7540
7541         switch (na->na_atype)
7542         {
7543         case FRI_RANGE :
7544                 amax = na->na_addr[1].in4.s_addr;
7545                 break;
7546
7547         case FRI_NETMASKED :
7548         case FRI_DYNAMIC :
7549         case FRI_NORMAL :
7550                 /*
7551                  * Compute the maximum address by adding the inverse of the
7552                  * netmask to the minimum address.
7553                  */
7554                 amax = ~na->na_addr[1].in4.s_addr;
7555                 amax |= amin;
7556                 break;
7557
7558         case FRI_LOOKUP :
7559                 break;
7560
7561         case FRI_BROADCAST :
7562         case FRI_PEERADDR :
7563         case FRI_NETWORK :
7564         default :
7565                 return -1;
7566         }
7567
7568         error = -1;
7569
7570         if (na->na_atype == FRI_LOOKUP) {
7571                 if (na->na_type == IPLT_DSTLIST) {
7572                         error = ipf_dstlist_select_node(fin, na->na_ptr, dst,
7573                                                         NULL);
7574                 } else {
7575                         NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7576                 }
7577
7578         } else if (na->na_atype == IPLT_NONE) {
7579                 /*
7580                  * 0/0 as the new address means leave it alone.
7581                  */
7582                 if (na->na_addr[0].in4.s_addr == 0 &&
7583                     na->na_addr[1].in4.s_addr == 0) {
7584                         new = *old;
7585
7586                 /*
7587                  * 0/32 means get the interface's address
7588                  */
7589                 } else if (na->na_addr[0].in4.s_addr == 0 &&
7590                            na->na_addr[1].in4.s_addr == 0xffffffff) {
7591                         if (ipf_ifpaddr(softc, 4, na->na_atype,
7592                                         fin->fin_ifp, &newip, NULL) == -1) {
7593                                 NBUMPSIDED(fin->fin_out, ns_ifpaddrfail);
7594                                 return -1;
7595                         }
7596                         new = newip.in4.s_addr;
7597                 } else {
7598                         new = htonl(na->na_nextip);
7599                 }
7600                 *dst = new;
7601                 error = 0;
7602
7603         } else {
7604                 NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7605         }
7606
7607         return error;
7608 }
7609
7610
7611 /* ------------------------------------------------------------------------ */
7612 /* Function:    nat_nextaddrinit                                            */
7613 /* Returns:     int - 0 == success, else error number                       */
7614 /* Parameters:  softc(I) - pointer to soft context main structure           */
7615 /*              na(I)      - NAT address information for generating new addr*/
7616 /*              initial(I) - flag indicating if it is the first call for    */
7617 /*                           this "na" structure.                           */
7618 /*              ifp(I)     - network interface to derive address            */
7619 /*                           information from.                              */
7620 /*                                                                          */
7621 /* This function is expected to be called in two scenarious: when a new NAT */
7622 /* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
7623 /* up with the valid network interfaces (possibly due to them changing.)    */
7624 /* To distinguish between these, the "initial" parameter is used.  If it is */
7625 /* 1 then this indicates the rule has just been reloaded and 0 for when we  */
7626 /* are updating information.  This difference is important because in       */
7627 /* instances where we are not updating address information associated with  */
7628 /* a network interface, we don't want to disturb what the "next" address to */
7629 /* come out of ipf_nat_nextaddr() will be.                                  */
7630 /* ------------------------------------------------------------------------ */
7631 static int
7632 ipf_nat_nextaddrinit(softc, base, na, initial, ifp)
7633         ipf_main_softc_t *softc;
7634         char *base;
7635         nat_addr_t *na;
7636         int initial;
7637         void *ifp;
7638 {
7639
7640         switch (na->na_atype)
7641         {
7642         case FRI_LOOKUP :
7643                 if (na->na_subtype == 0) {
7644                         na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
7645                                                         na->na_type,
7646                                                         na->na_num,
7647                                                         &na->na_func);
7648                 } else if (na->na_subtype == 1) {
7649                         na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
7650                                                          na->na_type,
7651                                                          base + na->na_num,
7652                                                          &na->na_func);
7653                 }
7654                 if (na->na_func == NULL) {
7655                         IPFERROR(60060);
7656                         return ESRCH;
7657                 }
7658                 if (na->na_ptr == NULL) {
7659                         IPFERROR(60056);
7660                         return ESRCH;
7661                 }
7662                 break;
7663
7664         case FRI_DYNAMIC :
7665         case FRI_BROADCAST :
7666         case FRI_NETWORK :
7667         case FRI_NETMASKED :
7668         case FRI_PEERADDR :
7669                 if (ifp != NULL)
7670                         (void )ipf_ifpaddr(softc, 4, na->na_atype, ifp,
7671                                            &na->na_addr[0], &na->na_addr[1]);
7672                 break;
7673
7674         case FRI_SPLIT :
7675         case FRI_RANGE :
7676                 if (initial)
7677                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7678                 break;
7679
7680         case FRI_NONE :
7681                 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7682                 return 0;
7683
7684         case FRI_NORMAL :
7685                 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7686                 break;
7687
7688         default :
7689                 IPFERROR(60054);
7690                 return EINVAL;
7691         }
7692
7693         if (initial && (na->na_atype == FRI_NORMAL)) {
7694                 if (na->na_addr[0].in4.s_addr == 0) {
7695                         if ((na->na_addr[1].in4.s_addr == 0xffffffff) ||
7696                             (na->na_addr[1].in4.s_addr == 0)) {
7697                                 return 0;
7698                         }
7699                 }
7700
7701                 if (na->na_addr[1].in4.s_addr == 0xffffffff) {
7702                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7703                 } else {
7704                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1;
7705                 }
7706         }
7707
7708         return 0;
7709 }
7710
7711
7712 /* ------------------------------------------------------------------------ */
7713 /* Function:    ipf_nat_matchflush                                          */
7714 /* Returns:     int - -1 == error, 0 == success                             */
7715 /* Parameters:  softc(I) - pointer to soft context main structure           */
7716 /*              softn(I) - pointer to NAT context structure                 */
7717 /*              nat(I)   - pointer to current NAT session                   */
7718 /*                                                                          */
7719 /* ------------------------------------------------------------------------ */
7720 static int
7721 ipf_nat_matchflush(softc, softn, data)
7722         ipf_main_softc_t *softc;
7723         ipf_nat_softc_t *softn;
7724         caddr_t data;
7725 {
7726         int *array, flushed, error;
7727         nat_t *nat, *natnext;
7728         ipfobj_t obj;
7729
7730         error = ipf_matcharray_load(softc, data, &obj, &array);
7731         if (error != 0)
7732                 return error;
7733
7734         flushed = 0;
7735
7736         for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) {
7737                 natnext = nat->nat_next;
7738                 if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) {
7739                         ipf_nat_delete(softc, nat, NL_FLUSH);
7740                         flushed++;
7741                 }
7742         }
7743
7744         obj.ipfo_retval = flushed;
7745         error = BCOPYOUT(&obj, data, sizeof(obj));
7746
7747         KFREES(array, array[0] * sizeof(*array));
7748
7749         return error;
7750 }
7751
7752
7753 /* ------------------------------------------------------------------------ */
7754 /* Function:    ipf_nat_matcharray                                          */
7755 /* Returns:     int - -1 == error, 0 == success                             */
7756 /* Parameters:  fin(I) - pointer to packet information                      */
7757 /*              nat(I) - pointer to current NAT session                     */
7758 /*                                                                          */
7759 /* ------------------------------------------------------------------------ */
7760 static int
7761 ipf_nat_matcharray(nat, array, ticks)
7762         nat_t *nat;
7763         int *array;
7764         u_long ticks;
7765 {
7766         int i, n, *x, e, p;
7767
7768         e = 0;
7769         n = array[0];
7770         x = array + 1;
7771
7772         for (; n > 0; x += 3 + x[2]) {
7773                 if (x[0] == IPF_EXP_END)
7774                         break;
7775                 e = 0;
7776
7777                 n -= x[2] + 3;
7778                 if (n < 0)
7779                         break;
7780
7781                 p = x[0] >> 16;
7782                 if (p != 0 && p != nat->nat_pr[1])
7783                         break;
7784
7785                 switch (x[0])
7786                 {
7787                 case IPF_EXP_IP_PR :
7788                         for (i = 0; !e && i < x[2]; i++) {
7789                                 e |= (nat->nat_pr[1] == x[i + 3]);
7790                         }
7791                         break;
7792
7793                 case IPF_EXP_IP_SRCADDR :
7794                         if (nat->nat_v[0] == 4) {
7795                                 for (i = 0; !e && i < x[2]; i++) {
7796                                         e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7797                                               x[i + 3]);
7798                                 }
7799                         }
7800                         if (nat->nat_v[1] == 4) {
7801                                 for (i = 0; !e && i < x[2]; i++) {
7802                                         e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7803                                               x[i + 3]);
7804                                 }
7805                         }
7806                         break;
7807
7808                 case IPF_EXP_IP_DSTADDR :
7809                         if (nat->nat_v[0] == 4) {
7810                                 for (i = 0; !e && i < x[2]; i++) {
7811                                         e |= ((nat->nat_odstaddr & x[i + 4]) ==
7812                                               x[i + 3]);
7813                                 }
7814                         }
7815                         if (nat->nat_v[1] == 4) {
7816                                 for (i = 0; !e && i < x[2]; i++) {
7817                                         e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7818                                               x[i + 3]);
7819                                 }
7820                         }
7821                         break;
7822
7823                 case IPF_EXP_IP_ADDR :
7824                         for (i = 0; !e && i < x[2]; i++) {
7825                                 if (nat->nat_v[0] == 4) {
7826                                         e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7827                                               x[i + 3]);
7828                                 }
7829                                 if (nat->nat_v[1] == 4) {
7830                                         e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7831                                               x[i + 3]);
7832                                 }
7833                                 if (nat->nat_v[0] == 4) {
7834                                         e |= ((nat->nat_odstaddr & x[i + 4]) ==
7835                                               x[i + 3]);
7836                                 }
7837                                 if (nat->nat_v[1] == 4) {
7838                                         e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7839                                               x[i + 3]);
7840                                 }
7841                         }
7842                         break;
7843
7844 #ifdef USE_INET6
7845                 case IPF_EXP_IP6_SRCADDR :
7846                         if (nat->nat_v[0] == 6) {
7847                                 for (i = 0; !e && i < x[3]; i++) {
7848                                         e |= IP6_MASKEQ(&nat->nat_osrc6,
7849                                                         x + i + 7, x + i + 3);
7850                                 }
7851                         }
7852                         if (nat->nat_v[1] == 6) {
7853                                 for (i = 0; !e && i < x[3]; i++) {
7854                                         e |= IP6_MASKEQ(&nat->nat_nsrc6,
7855                                                         x + i + 7, x + i + 3);
7856                                 }
7857                         }
7858                         break;
7859
7860                 case IPF_EXP_IP6_DSTADDR :
7861                         if (nat->nat_v[0] == 6) {
7862                                 for (i = 0; !e && i < x[3]; i++) {
7863                                         e |= IP6_MASKEQ(&nat->nat_odst6,
7864                                                         x + i + 7,
7865                                                         x + i + 3);
7866                                 }
7867                         }
7868                         if (nat->nat_v[1] == 6) {
7869                                 for (i = 0; !e && i < x[3]; i++) {
7870                                         e |= IP6_MASKEQ(&nat->nat_ndst6,
7871                                                         x + i + 7,
7872                                                         x + i + 3);
7873                                 }
7874                         }
7875                         break;
7876
7877                 case IPF_EXP_IP6_ADDR :
7878                         for (i = 0; !e && i < x[3]; i++) {
7879                                 if (nat->nat_v[0] == 6) {
7880                                         e |= IP6_MASKEQ(&nat->nat_osrc6,
7881                                                         x + i + 7,
7882                                                         x + i + 3);
7883                                 }
7884                                 if (nat->nat_v[0] == 6) {
7885                                         e |= IP6_MASKEQ(&nat->nat_odst6,
7886                                                         x + i + 7,
7887                                                         x + i + 3);
7888                                 }
7889                                 if (nat->nat_v[1] == 6) {
7890                                         e |= IP6_MASKEQ(&nat->nat_nsrc6,
7891                                                         x + i + 7,
7892                                                         x + i + 3);
7893                                 }
7894                                 if (nat->nat_v[1] == 6) {
7895                                         e |= IP6_MASKEQ(&nat->nat_ndst6,
7896                                                         x + i + 7,
7897                                                         x + i + 3);
7898                                 }
7899                         }
7900                         break;
7901 #endif
7902
7903                 case IPF_EXP_UDP_PORT :
7904                 case IPF_EXP_TCP_PORT :
7905                         for (i = 0; !e && i < x[2]; i++) {
7906                                 e |= (nat->nat_nsport == x[i + 3]) ||
7907                                      (nat->nat_ndport == x[i + 3]);
7908                         }
7909                         break;
7910
7911                 case IPF_EXP_UDP_SPORT :
7912                 case IPF_EXP_TCP_SPORT :
7913                         for (i = 0; !e && i < x[2]; i++) {
7914                                 e |= (nat->nat_nsport == x[i + 3]);
7915                         }
7916                         break;
7917
7918                 case IPF_EXP_UDP_DPORT :
7919                 case IPF_EXP_TCP_DPORT :
7920                         for (i = 0; !e && i < x[2]; i++) {
7921                                 e |= (nat->nat_ndport == x[i + 3]);
7922                         }
7923                         break;
7924
7925                 case IPF_EXP_TCP_STATE :
7926                         for (i = 0; !e && i < x[2]; i++) {
7927                                 e |= (nat->nat_tcpstate[0] == x[i + 3]) ||
7928                                      (nat->nat_tcpstate[1] == x[i + 3]);
7929                         }
7930                         break;
7931
7932                 case IPF_EXP_IDLE_GT :
7933                         e |= (ticks - nat->nat_touched > x[3]);
7934                         break;
7935                 }
7936                 e ^= x[1];
7937
7938                 if (!e)
7939                         break;
7940         }
7941
7942         return e;
7943 }
7944
7945
7946 /* ------------------------------------------------------------------------ */
7947 /* Function:    ipf_nat_gettable                                            */
7948 /* Returns:     int     - 0 = success, else error                           */
7949 /* Parameters:  softc(I) - pointer to soft context main structure           */
7950 /*              softn(I) - pointer to NAT context structure                 */
7951 /*              data(I)  - pointer to ioctl data                            */
7952 /*                                                                          */
7953 /* This function handles ioctl requests for tables of nat information.      */
7954 /* At present the only table it deals with is the hash bucket statistics.   */
7955 /* ------------------------------------------------------------------------ */
7956 static int
7957 ipf_nat_gettable(softc, softn, data)
7958         ipf_main_softc_t *softc;
7959         ipf_nat_softc_t *softn;
7960         char *data;
7961 {
7962         ipftable_t table;
7963         int error;
7964
7965         error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
7966         if (error != 0)
7967                 return error;
7968
7969         switch (table.ita_type)
7970         {
7971         case IPFTABLE_BUCKETS_NATIN :
7972                 error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
7973                                 table.ita_table,
7974                                 softn->ipf_nat_table_sz * sizeof(u_int));
7975                 break;
7976
7977         case IPFTABLE_BUCKETS_NATOUT :
7978                 error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
7979                                 table.ita_table,
7980                                 softn->ipf_nat_table_sz * sizeof(u_int));
7981                 break;
7982
7983         default :
7984                 IPFERROR(60058);
7985                 return EINVAL;
7986         }
7987
7988         if (error != 0) {
7989                 IPFERROR(60059);
7990                 error = EFAULT;
7991         }
7992         return error;
7993 }
7994
7995
7996 /* ------------------------------------------------------------------------ */
7997 /* Function:    ipf_nat_settimeout                                          */
7998 /* Returns:     int  - 0 = success, else failure                            */
7999 /* Parameters:  softc(I) - pointer to soft context main structure           */
8000 /*              t(I) - pointer to tunable                                   */
8001 /*              p(I) - pointer to new tuning data                           */
8002 /*                                                                          */
8003 /* Apply the timeout change to the NAT timeout queues.                      */
8004 /* ------------------------------------------------------------------------ */
8005 int
8006 ipf_nat_settimeout(softc, t, p)
8007         struct ipf_main_softc_s *softc;
8008         ipftuneable_t *t;
8009         ipftuneval_t *p;
8010 {
8011         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8012
8013         if (!strncmp(t->ipft_name, "tcp_", 4))
8014                 return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq);
8015
8016         if (!strcmp(t->ipft_name, "udp_timeout")) {
8017                 ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int);
8018         } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
8019                 ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int);
8020         } else if (!strcmp(t->ipft_name, "icmp_timeout")) {
8021                 ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int);
8022         } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
8023                 ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int);
8024         } else if (!strcmp(t->ipft_name, "ip_timeout")) {
8025                 ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int);
8026         } else {
8027                 IPFERROR(60062);
8028                 return ESRCH;
8029         }
8030         return 0;
8031 }
8032
8033
8034 /* ------------------------------------------------------------------------ */
8035 /* Function:    ipf_nat_rehash                                              */
8036 /* Returns:     int  - 0 = success, else failure                            */
8037 /* Parameters:  softc(I) - pointer to soft context main structure           */
8038 /*              t(I) - pointer to tunable                                   */
8039 /*              p(I) - pointer to new tuning data                           */
8040 /*                                                                          */
8041 /* To change the size of the basic NAT table, we need to first allocate the */
8042 /* new tables (lest it fails and we've got nowhere to store all of the NAT  */
8043 /* sessions currently active) and then walk through the entire list and     */
8044 /* insert them into the table.  There are two tables here: an inbound one   */
8045 /* and an outbound one.  Each NAT entry goes into each table once.          */
8046 /* ------------------------------------------------------------------------ */
8047 int
8048 ipf_nat_rehash(softc, t, p)
8049         ipf_main_softc_t *softc;
8050         ipftuneable_t *t;
8051         ipftuneval_t *p;
8052 {
8053         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8054         nat_t **newtab[2], *nat, **natp;
8055         u_int *bucketlens[2];
8056         u_int maxbucket;
8057         u_int newsize;
8058         int error;
8059         u_int hv;
8060         int i;
8061
8062         newsize = p->ipftu_int;
8063         /*
8064          * In case there is nothing to do...
8065          */
8066         if (newsize == softn->ipf_nat_table_sz)
8067                 return 0;
8068
8069         newtab[0] = NULL;
8070         newtab[1] = NULL;
8071         bucketlens[0] = NULL;
8072         bucketlens[1] = NULL;
8073         /*
8074          * 4 tables depend on the NAT table size: the inbound looking table,
8075          * the outbound lookup table and the hash chain length for each.
8076          */
8077         KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *));
8078         if (newtab == NULL) {
8079                 error = 60063;
8080                 goto badrehash;
8081         }
8082
8083         KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *));
8084         if (newtab == NULL) {
8085                 error = 60064;
8086                 goto badrehash;
8087         }
8088
8089         KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int));
8090         if (bucketlens[0] == NULL) {
8091                 error = 60065;
8092                 goto badrehash;
8093         }
8094
8095         KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int));
8096         if (bucketlens[1] == NULL) {
8097                 error = 60066;
8098                 goto badrehash;
8099         }
8100
8101         /*
8102          * Recalculate the maximum length based on the new size.
8103          */
8104         for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
8105                 maxbucket++;
8106         maxbucket *= 2;
8107
8108         bzero((char *)newtab[0], newsize * sizeof(nat_t *));
8109         bzero((char *)newtab[1], newsize * sizeof(nat_t *));
8110         bzero((char *)bucketlens[0], newsize * sizeof(u_int));
8111         bzero((char *)bucketlens[1], newsize * sizeof(u_int));
8112
8113         WRITE_ENTER(&softc->ipf_nat);
8114
8115         if (softn->ipf_nat_table[0] != NULL) {
8116                 KFREES(softn->ipf_nat_table[0],
8117                        softn->ipf_nat_table_sz *
8118                        sizeof(*softn->ipf_nat_table[0]));
8119         }
8120         softn->ipf_nat_table[0] = newtab[0];
8121
8122         if (softn->ipf_nat_table[1] != NULL) {
8123                 KFREES(softn->ipf_nat_table[1],
8124                        softn->ipf_nat_table_sz *
8125                        sizeof(*softn->ipf_nat_table[1]));
8126         }
8127         softn->ipf_nat_table[1] = newtab[1];
8128
8129         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
8130                 KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
8131                        softn->ipf_nat_table_sz * sizeof(u_int));
8132         }
8133         softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0];
8134
8135         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
8136                 KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
8137                        softn->ipf_nat_table_sz * sizeof(u_int));
8138         }
8139         softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1];
8140
8141 #ifdef USE_INET6
8142         if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) {
8143                 KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen,
8144                        softn->ipf_nat_table_sz * sizeof(u_int));
8145         }
8146         softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0];
8147
8148         if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) {
8149                 KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen,
8150                        softn->ipf_nat_table_sz * sizeof(u_int));
8151         }
8152         softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1];
8153 #endif
8154
8155         softn->ipf_nat_maxbucket = maxbucket;
8156         softn->ipf_nat_table_sz = newsize;
8157         /*
8158          * Walk through the entire list of NAT table entries and put them
8159          * in the new NAT table, somewhere.  Because we have a new table,
8160          * we need to restart the counter of how many chains are in use.
8161          */
8162         softn->ipf_nat_stats.ns_side[0].ns_inuse = 0;
8163         softn->ipf_nat_stats.ns_side[1].ns_inuse = 0;
8164 #ifdef USE_INET6
8165         softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0;
8166         softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0;
8167 #endif
8168
8169         for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) {
8170                 nat->nat_hnext[0] = NULL;
8171                 nat->nat_phnext[0] = NULL;
8172                 hv = nat->nat_hv[0] % softn->ipf_nat_table_sz;
8173
8174                 natp = &softn->ipf_nat_table[0][hv];
8175                 if (*natp) {
8176                         (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
8177                 } else {
8178                         NBUMPSIDE(0, ns_inuse);
8179                 }
8180                 nat->nat_phnext[0] = natp;
8181                 nat->nat_hnext[0] = *natp;
8182                 *natp = nat;
8183                 NBUMPSIDE(0, ns_bucketlen[hv]);
8184
8185                 nat->nat_hnext[1] = NULL;
8186                 nat->nat_phnext[1] = NULL;
8187                 hv = nat->nat_hv[1] % softn->ipf_nat_table_sz;
8188
8189                 natp = &softn->ipf_nat_table[1][hv];
8190                 if (*natp) {
8191                         (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
8192                 } else {
8193                         NBUMPSIDE(1, ns_inuse);
8194                 }
8195                 nat->nat_phnext[1] = natp;
8196                 nat->nat_hnext[1] = *natp;
8197                 *natp = nat;
8198                 NBUMPSIDE(1, ns_bucketlen[hv]);
8199         }
8200         RWLOCK_EXIT(&softc->ipf_nat);
8201
8202         return 0;
8203
8204 badrehash:
8205         if (bucketlens[1] != NULL) {
8206                 KFREES(bucketlens[0], newsize * sizeof(u_int));
8207         }
8208         if (bucketlens[0] != NULL) {
8209                 KFREES(bucketlens[0], newsize * sizeof(u_int));
8210         }
8211         if (newtab[0] != NULL) {
8212                 KFREES(newtab[0], newsize * sizeof(nat_t *));
8213         }
8214         if (newtab[1] != NULL) {
8215                 KFREES(newtab[1], newsize * sizeof(nat_t *));
8216         }
8217         IPFERROR(error);
8218         return ENOMEM;
8219 }
8220
8221
8222 /* ------------------------------------------------------------------------ */
8223 /* Function:    ipf_nat_rehash_rules                                        */
8224 /* Returns:     int  - 0 = success, else failure                            */
8225 /* Parameters:  softc(I) - pointer to soft context main structure           */
8226 /*              t(I) - pointer to tunable                                   */
8227 /*              p(I) - pointer to new tuning data                           */
8228 /*                                                                          */
8229 /* All of the NAT rules hang off of a hash table that is searched with a    */
8230 /* hash on address after the netmask is applied.  There is a different table*/
8231 /* for both inbound rules (rdr) and outbound (map.)  The resizing will only */
8232 /* affect one of these two tables.                                          */
8233 /* ------------------------------------------------------------------------ */
8234 int
8235 ipf_nat_rehash_rules(softc, t, p)
8236         ipf_main_softc_t *softc;
8237         ipftuneable_t *t;
8238         ipftuneval_t *p;
8239 {
8240         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8241         ipnat_t **newtab, *np, ***old, **npp;
8242         u_int newsize;
8243         u_int mask;
8244         u_int hv;
8245
8246         newsize = p->ipftu_int;
8247         /*
8248          * In case there is nothing to do...
8249          */
8250         if (newsize == *t->ipft_pint)
8251                 return 0;
8252
8253         /*
8254          * All inbound rules have the NAT_REDIRECT bit set in in_redir and
8255          * all outbound rules have either NAT_MAP or MAT_MAPBLK set.
8256          * This if statement allows for some more generic code to be below,
8257          * rather than two huge gobs of code that almost do the same thing.
8258          */
8259         if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) {
8260                 old = &softn->ipf_nat_rdr_rules;
8261                 mask = NAT_REDIRECT;
8262         } else {
8263                 old = &softn->ipf_nat_map_rules;
8264                 mask = NAT_MAP|NAT_MAPBLK;
8265         }
8266
8267         KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *));
8268         if (newtab == NULL) {
8269                 IPFERROR(60067);
8270                 return ENOMEM;
8271         }
8272
8273         bzero((char *)newtab, newsize * sizeof(ipnat_t *));
8274
8275         WRITE_ENTER(&softc->ipf_nat);
8276
8277         if (*old != NULL) {
8278                 KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **));
8279         }
8280         *old = newtab;
8281         *t->ipft_pint = newsize;
8282
8283         for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) {
8284                 if ((np->in_redir & mask) == 0)
8285                         continue;
8286
8287                 if (np->in_redir & NAT_REDIRECT) {
8288                         np->in_rnext = NULL;
8289                         hv = np->in_hv[0] % newsize;
8290                         for (npp = newtab + hv; *npp != NULL; )
8291                                 npp = &(*npp)->in_rnext;
8292                         np->in_prnext = npp;
8293                         *npp = np;
8294                 }
8295                 if (np->in_redir & NAT_MAP) {
8296                         np->in_mnext = NULL;
8297                         hv = np->in_hv[1] % newsize;
8298                         for (npp = newtab + hv; *npp != NULL; )
8299                                 npp = &(*npp)->in_mnext;
8300                         np->in_pmnext = npp;
8301                         *npp = np;
8302                 }
8303
8304         }
8305         RWLOCK_EXIT(&softc->ipf_nat);
8306
8307         return 0;
8308 }
8309
8310
8311 /* ------------------------------------------------------------------------ */
8312 /* Function:    ipf_nat_hostmap_rehash                                      */
8313 /* Returns:     int  - 0 = success, else failure                            */
8314 /* Parameters:  softc(I) - pointer to soft context main structure           */
8315 /*              t(I) - pointer to tunable                                   */
8316 /*              p(I) - pointer to new tuning data                           */
8317 /*                                                                          */
8318 /* Allocate and populate a new hash table that will contain a reference to  */
8319 /* all of the active IP# translations currently in place.                   */
8320 /* ------------------------------------------------------------------------ */
8321 int
8322 ipf_nat_hostmap_rehash(softc, t, p)
8323         ipf_main_softc_t *softc;
8324         ipftuneable_t *t;
8325         ipftuneval_t *p;
8326 {
8327         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8328         hostmap_t *hm, **newtab;
8329         u_int newsize;
8330         u_int hv;
8331
8332         newsize = p->ipftu_int;
8333         /*
8334          * In case there is nothing to do...
8335          */
8336         if (newsize == *t->ipft_pint)
8337                 return 0;
8338
8339         KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *));
8340         if (newtab == NULL) {
8341                 IPFERROR(60068);
8342                 return ENOMEM;
8343         }
8344
8345         bzero((char *)newtab, newsize * sizeof(hostmap_t *));
8346
8347         WRITE_ENTER(&softc->ipf_nat);
8348         if (softn->ipf_hm_maptable != NULL) {
8349                 KFREES(softn->ipf_hm_maptable,
8350                        softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *));
8351         }
8352         softn->ipf_hm_maptable = newtab;
8353         softn->ipf_nat_hostmap_sz = newsize;
8354
8355         for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) {
8356                 hv = hm->hm_hv % softn->ipf_nat_hostmap_sz;
8357                 hm->hm_hnext = softn->ipf_hm_maptable[hv];
8358                 hm->hm_phnext = softn->ipf_hm_maptable + hv;
8359                 if (softn->ipf_hm_maptable[hv] != NULL)
8360                         softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
8361                 softn->ipf_hm_maptable[hv] = hm;
8362         }
8363         RWLOCK_EXIT(&softc->ipf_nat);
8364
8365         return 0;
8366 }
8367
8368
8369 /* ------------------------------------------------------------------------ */
8370 /* Function:    ipf_nat_add_tq                                              */
8371 /* Parameters:  softc(I) - pointer to soft context main structure           */
8372 /*                                                                          */
8373 /* ------------------------------------------------------------------------ */
8374 ipftq_t *
8375 ipf_nat_add_tq(softc, ttl)
8376         ipf_main_softc_t *softc;
8377         int ttl;
8378 {
8379         ipf_nat_softc_t *softs = softc->ipf_nat_soft;
8380
8381         return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl);
8382 }
8383
8384 /* ------------------------------------------------------------------------ */
8385 /* Function:    ipf_nat_uncreate                                            */
8386 /* Returns:     Nil                                                         */
8387 /* Parameters:  fin(I) - pointer to packet information                      */
8388 /*                                                                          */
8389 /* This function is used to remove a NAT entry from the NAT table when we   */
8390 /* decide that the create was actually in error. It is thus assumed that    */
8391 /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
8392 /* with the translated packet (not the original), we have to reverse the    */
8393 /* lookup. Although doing the lookup is expensive (relatively speaking), it */
8394 /* is not anticipated that this will be a frequent occurance for normal     */
8395 /* traffic patterns.                                                        */
8396 /* ------------------------------------------------------------------------ */
8397 void
8398 ipf_nat_uncreate(fin)
8399         fr_info_t *fin;
8400 {
8401         ipf_main_softc_t *softc = fin->fin_main_soft;
8402         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8403         int nflags;
8404         nat_t *nat;
8405
8406         switch (fin->fin_p)
8407         {
8408         case IPPROTO_TCP :
8409                 nflags = IPN_TCP;
8410                 break;
8411         case IPPROTO_UDP :
8412                 nflags = IPN_UDP;
8413                 break;
8414         default :
8415                 nflags = 0;
8416                 break;
8417         }
8418
8419         WRITE_ENTER(&softc->ipf_nat);
8420
8421         if (fin->fin_out == 0) {
8422                 nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
8423                                         fin->fin_dst, fin->fin_src);
8424         } else {
8425                 nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
8426                                        fin->fin_src, fin->fin_dst);
8427         }
8428
8429         if (nat != NULL) {
8430                 NBUMPSIDE(fin->fin_out, ns_uncreate[0]);
8431                 ipf_nat_delete(softc, nat, NL_DESTROY);
8432         } else {
8433                 NBUMPSIDE(fin->fin_out, ns_uncreate[1]);
8434         }
8435
8436         RWLOCK_EXIT(&softc->ipf_nat);
8437 }
8438
8439
8440 /* ------------------------------------------------------------------------ */
8441 /* Function:    ipf_nat_cmp_rules                                           */
8442 /* Returns:     int   - 0 == success, else rules do not match.              */
8443 /* Parameters:  n1(I) - first rule to compare                               */
8444 /*              n2(I) - first rule to compare                               */
8445 /*                                                                          */
8446 /* Compare two rules using pointers to each rule. A straight bcmp will not  */
8447 /* work as some fields (such as in_dst, in_pkts) actually do change once    */
8448 /* the rule has been loaded into the kernel. Whilst this function returns   */
8449 /* various non-zero returns, they're strictly to aid in debugging. Use of   */
8450 /* this function should simply care if the result is zero or not.           */
8451 /* ------------------------------------------------------------------------ */
8452 static int
8453 ipf_nat_cmp_rules(n1, n2)
8454         ipnat_t *n1, *n2;
8455 {
8456         if (n1->in_size != n2->in_size)
8457                 return 1;
8458
8459         if (bcmp((char *)&n1->in_v, (char *)&n2->in_v,
8460                  offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0)
8461                 return 2;
8462
8463         if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc,
8464                  n1->in_size - offsetof(ipnat_t, in_tuc)) != 0)
8465                 return 3;
8466         if (n1->in_ndst.na_atype != n2->in_ndst.na_atype)
8467                 return 5;
8468         if (n1->in_ndst.na_function != n2->in_ndst.na_function)
8469                 return 6;
8470         if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr,
8471                  sizeof(n1->in_ndst.na_addr)))
8472                 return 7;
8473         if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype)
8474                 return 8;
8475         if (n1->in_nsrc.na_function != n2->in_nsrc.na_function)
8476                 return 9;
8477         if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr,
8478                  sizeof(n1->in_nsrc.na_addr)))
8479                 return 10;
8480         if (n1->in_odst.na_atype != n2->in_odst.na_atype)
8481                 return 11;
8482         if (n1->in_odst.na_function != n2->in_odst.na_function)
8483                 return 12;
8484         if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr,
8485                  sizeof(n1->in_odst.na_addr)))
8486                 return 13;
8487         if (n1->in_osrc.na_atype != n2->in_osrc.na_atype)
8488                 return 14;
8489         if (n1->in_osrc.na_function != n2->in_osrc.na_function)
8490                 return 15;
8491         if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr,
8492                  sizeof(n1->in_osrc.na_addr)))
8493                 return 16;
8494         return 0;
8495 }
8496
8497
8498 /* ------------------------------------------------------------------------ */
8499 /* Function:    ipf_nat_rule_init                                           */
8500 /* Returns:     int   - 0 == success, else rules do not match.              */
8501 /* Parameters:  softc(I) - pointer to soft context main structure           */
8502 /*              softn(I) - pointer to NAT context structure                 */
8503 /*              n(I)     - first rule to compare                            */
8504 /*                                                                          */
8505 /* ------------------------------------------------------------------------ */
8506 static int
8507 ipf_nat_rule_init(softc, softn, n)
8508         ipf_main_softc_t *softc;
8509         ipf_nat_softc_t *softn;
8510         ipnat_t *n;
8511 {
8512         int error = 0;
8513
8514         if ((n->in_flags & IPN_SIPRANGE) != 0)
8515                 n->in_nsrcatype = FRI_RANGE;
8516
8517         if ((n->in_flags & IPN_DIPRANGE) != 0)
8518                 n->in_ndstatype = FRI_RANGE;
8519
8520         if ((n->in_flags & IPN_SPLIT) != 0)
8521                 n->in_ndstatype = FRI_SPLIT;
8522
8523         if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0)
8524                 n->in_spnext = n->in_spmin;
8525
8526         if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) {
8527                 n->in_dpnext = n->in_dpmin;
8528         } else if (n->in_redir == NAT_REDIRECT) {
8529                 n->in_dpnext = n->in_dpmin;
8530         }
8531
8532         n->in_stepnext = 0;
8533
8534         switch (n->in_v[0])
8535         {
8536         case 4 :
8537                 error = ipf_nat_ruleaddrinit(softc, softn, n);
8538                 if (error != 0)
8539                         return error;
8540                 break;
8541 #ifdef USE_INET6
8542         case 6 :
8543                 error = ipf_nat6_ruleaddrinit(softc, softn, n);
8544                 if (error != 0)
8545                         return error;
8546                 break;
8547 #endif
8548         default :
8549                 break;
8550         }
8551
8552         if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
8553                 /*
8554                  * Prerecord whether or not the destination of the divert
8555                  * is local or not to the interface the packet is going
8556                  * to be sent out.
8557                  */
8558                 n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
8559                                                 n->in_ifps[1], &n->in_ndstip6);
8560         }
8561
8562         return error;
8563 }
8564
8565
8566 /* ------------------------------------------------------------------------ */
8567 /* Function:    ipf_nat_rule_fini                                           */
8568 /* Returns:     int   - 0 == success, else rules do not match.              */
8569 /* Parameters:  softc(I) - pointer to soft context main structure           */
8570 /*              n(I)     - rule to work on                                  */
8571 /*                                                                          */
8572 /* This function is used to release any objects that were referenced during */
8573 /* the rule initialisation. This is useful both when free'ing the rule and  */
8574 /* when handling ioctls that need to initialise these fields but not        */
8575 /* actually use them after the ioctl processing has finished.               */
8576 /* ------------------------------------------------------------------------ */
8577 static void
8578 ipf_nat_rule_fini(softc, n)
8579         ipf_main_softc_t *softc;
8580         ipnat_t *n;
8581 {
8582         if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL)
8583                 ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr);
8584
8585         if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL)
8586                 ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr);
8587
8588         if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL)
8589                 ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr);
8590
8591         if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL)
8592                 ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr);
8593
8594         if (n->in_divmp != NULL)
8595                 FREE_MB_T(n->in_divmp);
8596 }