]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/contrib/ipfilter/netinet/ip_nat.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.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
2950                 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
2951                         hm = ipf_nat_hostmap(softn, NULL, fin->fin_src,
2952                                              fin->fin_dst, in, (u_32_t)dport);
2953                         if (hm != NULL) {
2954                                 in.s_addr = hm->hm_ndstip.s_addr;
2955                                 move = 0;
2956                         }
2957                 }
2958
2959                 if (hm == NULL || hm->hm_ref == 1) {
2960                         if (np->in_ndstaddr == htonl(in.s_addr)) {
2961                                 np->in_dnip = ntohl(np->in_ndstmsk);
2962                                 move = 0;
2963                         } else {
2964                                 np->in_dnip = ntohl(np->in_ndstaddr);
2965                         }
2966                 }
2967                 if (hm != NULL)
2968                         ipf_nat_hostmapdel(softc, &hm);
2969
2970         } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
2971                 i6addr_t in6;
2972
2973                 /*
2974                  * 0/32 - use the interface's IP address.
2975                  */
2976                 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
2977                                &in6, NULL) == -1) {
2978                         NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
2979                         return -1;
2980                 }
2981                 in.s_addr = ntohl(in6.in4.s_addr);
2982
2983         } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) {
2984                 /*
2985                  * 0/0 - use the original destination address/port.
2986                  */
2987                 in.s_addr = ntohl(fin->fin_daddr);
2988
2989         } else if (np->in_redir == NAT_BIMAP &&
2990                    np->in_ndstmsk == np->in_odstmsk) {
2991                 /*
2992                  * map the address block in a 1:1 fashion
2993                  */
2994                 in.s_addr = np->in_ndstaddr;
2995                 in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk;
2996                 in.s_addr = ntohl(in.s_addr);
2997         } else {
2998                 in.s_addr = ntohl(np->in_ndstaddr);
2999         }
3000
3001         if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
3002                 nport = dport;
3003         else {
3004                 /*
3005                  * Whilst not optimized for the case where
3006                  * pmin == pmax, the gain is not significant.
3007                  */
3008                 if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
3009                     (np->in_odport != np->in_dtop)) {
3010                         nport = ntohs(dport) - np->in_odport + np->in_dpmax;
3011                         nport = htons(nport);
3012                 } else {
3013                         nport = htons(np->in_dpnext);
3014                         np->in_dpnext++;
3015                         if (np->in_dpnext > np->in_dpmax)
3016                                 np->in_dpnext = np->in_dpmin;
3017                 }
3018         }
3019
3020         /*
3021          * When the redirect-to address is set to 0.0.0.0, just
3022          * assume a blank `forwarding' of the packet.  We don't
3023          * setup any translation for this either.
3024          */
3025         if (in.s_addr == 0) {
3026                 if (nport == dport) {
3027                         NBUMPSIDED(0, ns_xlate_null);
3028                         return -1;
3029                 }
3030                 in.s_addr = ntohl(fin->fin_daddr);
3031         }
3032
3033         /*
3034          * Check to see if this redirect mapping already exists and if
3035          * it does, return "failure" (allowing it to be created will just
3036          * cause one or both of these "connections" to stop working.)
3037          */
3038         inb.s_addr = htonl(in.s_addr);
3039         sp = fin->fin_data[0];
3040         dp = fin->fin_data[1];
3041         fin->fin_data[1] = fin->fin_data[0];
3042         fin->fin_data[0] = ntohs(nport);
3043         natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
3044                              (u_int)fin->fin_p, inb, fin->fin_src);
3045         fin->fin_data[0] = sp;
3046         fin->fin_data[1] = dp;
3047         if (natl != NULL) {
3048                 DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl);
3049                 NBUMPSIDE(0, ns_xlate_exists);
3050                 return -1;
3051         }
3052
3053         nat->nat_ndstaddr = htonl(in.s_addr);
3054         nat->nat_odstip = fin->fin_dst;
3055         nat->nat_nsrcip = fin->fin_src;
3056         nat->nat_osrcip = fin->fin_src;
3057         if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
3058                 nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
3059                                               fin->fin_dst, in, (u_32_t)dport);
3060
3061         if (flags & IPN_TCPUDP) {
3062                 nat->nat_odport = dport;
3063                 nat->nat_ndport = nport;
3064                 nat->nat_osport = sport;
3065                 nat->nat_nsport = sport;
3066                 ((tcphdr_t *)fin->fin_dp)->th_dport = nport;
3067         } else if (flags & IPN_ICMPQUERY) {
3068                 nat->nat_oicmpid = fin->fin_data[1];
3069                 ((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
3070                 nat->nat_nicmpid = nport;
3071         }
3072
3073         return move;
3074 }
3075
3076 /* ------------------------------------------------------------------------ */
3077 /* Function:    ipf_nat_add                                                 */
3078 /* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
3079 /*                       else pointer to new NAT structure                  */
3080 /* Parameters:  fin(I)       - pointer to packet information                */
3081 /*              np(I)        - pointer to NAT rule                          */
3082 /*              natsave(I)   - pointer to where to store NAT struct pointer */
3083 /*              flags(I)     - flags describing the current packet          */
3084 /*              direction(I) - direction of packet (in/out)                 */
3085 /* Write Lock:  ipf_nat                                                     */
3086 /*                                                                          */
3087 /* Attempts to create a new NAT entry.  Does not actually change the packet */
3088 /* in any way.                                                              */
3089 /*                                                                          */
3090 /* This fucntion is in three main parts: (1) deal with creating a new NAT   */
3091 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
3092 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
3093 /* and (3) building that structure and putting it into the NAT table(s).    */
3094 /*                                                                          */
3095 /* NOTE: natsave should NOT be used top point back to an ipstate_t struct   */
3096 /*       as it can result in memory being corrupted.                        */
3097 /* ------------------------------------------------------------------------ */
3098 nat_t *
3099 ipf_nat_add(fin, np, natsave, flags, direction)
3100         fr_info_t *fin;
3101         ipnat_t *np;
3102         nat_t **natsave;
3103         u_int flags;
3104         int direction;
3105 {
3106         ipf_main_softc_t *softc = fin->fin_main_soft;
3107         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3108         hostmap_t *hm = NULL;
3109         nat_t *nat, *natl;
3110         natstat_t *nsp;
3111         u_int nflags;
3112         natinfo_t ni;
3113         int move;
3114
3115         nsp = &softn->ipf_nat_stats;
3116
3117         if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
3118             softn->ipf_nat_table_wm_high) {
3119                 softn->ipf_nat_doflush = 1;
3120         }
3121
3122         if (nsp->ns_active >= softn->ipf_nat_table_max) {
3123                 NBUMPSIDED(fin->fin_out, ns_table_max);
3124                 return NULL;
3125         }
3126
3127         move = 1;
3128         nflags = np->in_flags & flags;
3129         nflags &= NAT_FROMRULE;
3130
3131         ni.nai_np = np;
3132         ni.nai_dport = 0;
3133         ni.nai_sport = 0;
3134
3135         /* Give me a new nat */
3136         KMALLOC(nat, nat_t *);
3137         if (nat == NULL) {
3138                 NBUMPSIDED(fin->fin_out, ns_memfail);
3139                 /*
3140                  * Try to automatically tune the max # of entries in the
3141                  * table allowed to be less than what will cause kmem_alloc()
3142                  * to fail and try to eliminate panics due to out of memory
3143                  * conditions arising.
3144                  */
3145                 if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
3146                     (nsp->ns_active > 100)) {
3147                         softn->ipf_nat_table_max = nsp->ns_active - 100;
3148                         printf("table_max reduced to %d\n",
3149                                 softn->ipf_nat_table_max);
3150                 }
3151                 return NULL;
3152         }
3153
3154         if (flags & IPN_ICMPQUERY) {
3155                 /*
3156                  * In the ICMP query NAT code, we translate the ICMP id fields
3157                  * to make them unique. This is indepedent of the ICMP type
3158                  * (e.g. in the unlikely event that a host sends an echo and
3159                  * an tstamp request with the same id, both packets will have
3160                  * their ip address/id field changed in the same way).
3161                  */
3162                 /* The icmp_id field is used by the sender to identify the
3163                  * process making the icmp request. (the receiver justs
3164                  * copies it back in its response). So, it closely matches
3165                  * the concept of source port. We overlay sport, so we can
3166                  * maximally reuse the existing code.
3167                  */
3168                 ni.nai_sport = fin->fin_data[1];
3169                 ni.nai_dport = 0;
3170         }
3171
3172         bzero((char *)nat, sizeof(*nat));
3173         nat->nat_flags = flags;
3174         nat->nat_redir = np->in_redir;
3175         nat->nat_dir = direction;
3176         nat->nat_pr[0] = fin->fin_p;
3177         nat->nat_pr[1] = fin->fin_p;
3178
3179         /*
3180          * Search the current table for a match and create a new mapping
3181          * if there is none found.
3182          */
3183         if (np->in_redir & NAT_DIVERTUDP) {
3184                 move = ipf_nat_newdivert(fin, nat, &ni);
3185
3186         } else if (np->in_redir & NAT_REWRITE) {
3187                 move = ipf_nat_newrewrite(fin, nat, &ni);
3188
3189         } else if (direction == NAT_OUTBOUND) {
3190                 /*
3191                  * We can now arrange to call this for the same connection
3192                  * because ipf_nat_new doesn't protect the code path into
3193                  * this function.
3194                  */
3195                 natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
3196                                      fin->fin_src, fin->fin_dst);
3197                 if (natl != NULL) {
3198                         KFREE(nat);
3199                         nat = natl;
3200                         goto done;
3201                 }
3202
3203                 move = ipf_nat_newmap(fin, nat, &ni);
3204         } else {
3205                 /*
3206                  * NAT_INBOUND is used for redirects rules
3207                  */
3208                 natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
3209                                         fin->fin_src, fin->fin_dst);
3210                 if (natl != NULL) {
3211                         KFREE(nat);
3212                         nat = natl;
3213                         goto done;
3214                 }
3215
3216                 move = ipf_nat_newrdr(fin, nat, &ni);
3217         }
3218         if (move == -1)
3219                 goto badnat;
3220
3221         np = ni.nai_np;
3222
3223         nat->nat_mssclamp = np->in_mssclamp;
3224         nat->nat_me = natsave;
3225         nat->nat_fr = fin->fin_fr;
3226         nat->nat_rev = fin->fin_rev;
3227         nat->nat_ptr = np;
3228         nat->nat_dlocal = np->in_dlocal;
3229
3230         if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
3231                 if (ipf_proxy_new(fin, nat) == -1) {
3232                         NBUMPSIDED(fin->fin_out, ns_appr_fail);
3233                         goto badnat;
3234                 }
3235         }
3236
3237         nat->nat_ifps[0] = np->in_ifps[0];
3238         if (np->in_ifps[0] != NULL) {
3239                 COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
3240         }
3241
3242         nat->nat_ifps[1] = np->in_ifps[1];
3243         if (np->in_ifps[1] != NULL) {
3244                 COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
3245         }
3246
3247         if (ipf_nat_finalise(fin, nat) == -1) {
3248                 goto badnat;
3249         }
3250
3251         np->in_use++;
3252
3253         if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
3254                 if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
3255                         ipf_nat_delrdr(softn, np);
3256                         ipf_nat_addrdr(softn, np);
3257                 } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
3258                         ipf_nat_delmap(softn, np);
3259                         ipf_nat_addmap(softn, np);
3260                 }
3261         }
3262
3263         if (flags & SI_WILDP)
3264                 nsp->ns_wilds++;
3265         nsp->ns_proto[nat->nat_pr[0]]++;
3266
3267         goto done;
3268 badnat:
3269         DT2(ns_badnatnew, fr_info_t *, fin, nat_t *, nat);
3270         NBUMPSIDE(fin->fin_out, ns_badnatnew);
3271         if ((hm = nat->nat_hm) != NULL)
3272                 ipf_nat_hostmapdel(softc, &hm);
3273         KFREE(nat);
3274         nat = NULL;
3275 done:
3276         if (nat != NULL && np != NULL)
3277                 np->in_hits++;
3278         if (natsave != NULL)
3279                 *natsave = nat;
3280         return nat;
3281 }
3282
3283
3284 /* ------------------------------------------------------------------------ */
3285 /* Function:    ipf_nat_finalise                                            */
3286 /* Returns:     int - 0 == sucess, -1 == failure                            */
3287 /* Parameters:  fin(I) - pointer to packet information                      */
3288 /*              nat(I) - pointer to NAT entry                               */
3289 /* Write Lock:  ipf_nat                                                     */
3290 /*                                                                          */
3291 /* This is the tail end of constructing a new NAT entry and is the same     */
3292 /* for both IPv4 and IPv6.                                                  */
3293 /* ------------------------------------------------------------------------ */
3294 /*ARGSUSED*/
3295 static int
3296 ipf_nat_finalise(fin, nat)
3297         fr_info_t *fin;
3298         nat_t *nat;
3299 {
3300         ipf_main_softc_t *softc = fin->fin_main_soft;
3301         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3302         u_32_t sum1, sum2, sumd;
3303         frentry_t *fr;
3304         u_32_t flags;
3305 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
3306         qpktinfo_t *qpi = fin->fin_qpi;
3307 #endif
3308
3309         flags = nat->nat_flags;
3310
3311         switch (nat->nat_pr[0])
3312         {
3313         case IPPROTO_ICMP :
3314                 sum1 = LONG_SUM(ntohs(nat->nat_oicmpid));
3315                 sum2 = LONG_SUM(ntohs(nat->nat_nicmpid));
3316                 CALC_SUMD(sum1, sum2, sumd);
3317                 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
3318
3319                 break;
3320
3321         default :
3322                 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \
3323                                 ntohs(nat->nat_osport));
3324                 sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \
3325                                 ntohs(nat->nat_nsport));
3326                 CALC_SUMD(sum1, sum2, sumd);
3327                 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
3328
3329                 sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \
3330                                 ntohs(nat->nat_odport));
3331                 sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \
3332                                 ntohs(nat->nat_ndport));
3333                 CALC_SUMD(sum1, sum2, sumd);
3334                 nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
3335                 break;
3336         }
3337
3338         /*
3339          * Compute the partial checksum, just in case.
3340          * This is only ever placed into outbound packets so care needs
3341          * to be taken over which pair of addresses are used.
3342          */
3343         if (nat->nat_dir == NAT_OUTBOUND) {
3344                 sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
3345                 sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr));
3346         } else {
3347                 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
3348                 sum1 += LONG_SUM(ntohl(nat->nat_odstaddr));
3349         }
3350         sum1 += nat->nat_pr[1];
3351         nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
3352
3353         sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
3354         sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
3355         CALC_SUMD(sum1, sum2, sumd);
3356         nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
3357
3358         sum1 = LONG_SUM(ntohl(nat->nat_odstaddr));
3359         sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
3360         CALC_SUMD(sum1, sum2, sumd);
3361         nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16);
3362
3363         nat->nat_v[0] = 4;
3364         nat->nat_v[1] = 4;
3365
3366         if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
3367                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
3368         }
3369
3370         if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
3371                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
3372         }
3373
3374         if ((nat->nat_flags & SI_CLONE) == 0)
3375                 nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
3376
3377         if (ipf_nat_insert(softc, softn, nat) == 0) {
3378                 if (softn->ipf_nat_logging)
3379                         ipf_nat_log(softc, softn, nat, NL_NEW);
3380                 fr = nat->nat_fr;
3381                 if (fr != NULL) {
3382                         MUTEX_ENTER(&fr->fr_lock);
3383                         fr->fr_ref++;
3384                         MUTEX_EXIT(&fr->fr_lock);
3385                 }
3386                 return 0;
3387         }
3388
3389         NBUMPSIDED(fin->fin_out, ns_unfinalised);
3390         /*
3391          * nat_insert failed, so cleanup time...
3392          */
3393         if (nat->nat_sync != NULL)
3394                 ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
3395         return -1;
3396 }
3397
3398
3399 /* ------------------------------------------------------------------------ */
3400 /* Function:    ipf_nat_insert                                              */
3401 /* Returns:     int - 0 == sucess, -1 == failure                            */
3402 /* Parameters:  softc(I) - pointer to soft context main structure           */
3403 /*              softn(I) - pointer to NAT context structure                 */
3404 /*              nat(I) - pointer to NAT structure                           */
3405 /* Write Lock:  ipf_nat                                                     */
3406 /*                                                                          */
3407 /* Insert a NAT entry into the hash tables for searching and add it to the  */
3408 /* list of active NAT entries.  Adjust global counters when complete.       */
3409 /* ------------------------------------------------------------------------ */
3410 int
3411 ipf_nat_insert(softc, softn, nat)
3412         ipf_main_softc_t *softc;
3413         ipf_nat_softc_t *softn;
3414         nat_t *nat;
3415 {
3416         u_int hv0, hv1;
3417         u_int sp, dp;
3418         ipnat_t *in;
3419
3420         /*
3421          * Try and return an error as early as possible, so calculate the hash
3422          * entry numbers first and then proceed.
3423          */
3424         if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
3425                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3426                         sp = nat->nat_osport;
3427                         dp = nat->nat_odport;
3428                 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3429                         sp = 0;
3430                         dp = nat->nat_oicmpid;
3431                 } else {
3432                         sp = 0;
3433                         dp = 0;
3434                 }
3435                 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff);
3436                 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff);
3437                 /*
3438                  * TRACE nat_osrcaddr, nat_osport, nat_odstaddr,
3439                  * nat_odport, hv0
3440                  */
3441
3442                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3443                         sp = nat->nat_nsport;
3444                         dp = nat->nat_ndport;
3445                 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3446                         sp = 0;
3447                         dp = nat->nat_nicmpid;
3448                 } else {
3449                         sp = 0;
3450                         dp = 0;
3451                 }
3452                 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff);
3453                 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff);
3454                 /*
3455                  * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr,
3456                  * nat_ndport, hv1
3457                  */
3458         } else {
3459                 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff);
3460                 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff);
3461                 /* TRACE nat_osrcaddr, nat_odstaddr, hv0 */
3462
3463                 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff);
3464                 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff);
3465                 /* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */
3466         }
3467
3468         nat->nat_hv[0] = hv0;
3469         nat->nat_hv[1] = hv1;
3470
3471         MUTEX_INIT(&nat->nat_lock, "nat entry lock");
3472
3473         in = nat->nat_ptr;
3474         nat->nat_ref = nat->nat_me ? 2 : 1;
3475
3476         nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
3477         nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4);
3478
3479         if (nat->nat_ifnames[1][0] != '\0') {
3480                 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3481                 nat->nat_ifps[1] = ipf_resolvenic(softc,
3482                                                   nat->nat_ifnames[1], 4);
3483         } else if (in->in_ifnames[1] != -1) {
3484                 char *name;
3485
3486                 name = in->in_names + in->in_ifnames[1];
3487                 if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
3488                         (void) strncpy(nat->nat_ifnames[1],
3489                                        nat->nat_ifnames[0], LIFNAMSIZ);
3490                         nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3491                         nat->nat_ifps[1] = nat->nat_ifps[0];
3492                 }
3493         }
3494         if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
3495                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
3496         }
3497         if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
3498                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
3499         }
3500
3501         return ipf_nat_hashtab_add(softc, softn, nat);
3502 }
3503
3504
3505 /* ------------------------------------------------------------------------ */
3506 /* Function:    ipf_nat_hashtab_add                                         */
3507 /* Parameters:  softc(I) - pointer to soft context main structure           */
3508 /*              softn(I) - pointer to NAT context structure                 */
3509 /*              nat(I) - pointer to NAT structure                           */
3510 /*                                                                          */
3511 /* Handle the insertion of a NAT entry into the table/list.                 */
3512 /* ------------------------------------------------------------------------ */
3513 int
3514 ipf_nat_hashtab_add(softc, softn, nat)
3515         ipf_main_softc_t *softc;
3516         ipf_nat_softc_t *softn;
3517         nat_t *nat;
3518 {
3519         nat_t **natp;
3520         u_int hv0;
3521         u_int hv1;
3522
3523         hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
3524         hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
3525
3526         if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
3527                 u_int swap;
3528
3529                 swap = hv0;
3530                 hv0 = hv1;
3531                 hv1 = swap;
3532         }
3533
3534         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >=
3535             softn->ipf_nat_maxbucket) {
3536                 DT1(ns_bucket_max_0, int,
3537                     softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]);
3538                 NBUMPSIDE(0, ns_bucket_max);
3539                 return -1;
3540         }
3541
3542         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >=
3543             softn->ipf_nat_maxbucket) {
3544                 DT1(ns_bucket_max_1, int,
3545                     softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]);
3546                 NBUMPSIDE(1, ns_bucket_max);
3547                 return -1;
3548         }
3549
3550         /*
3551          * The ordering of operations in the list and hash table insertion
3552          * is very important.  The last operation for each task should be
3553          * to update the top of the list, after all the "nexts" have been
3554          * done so that walking the list while it is being done does not
3555          * find strange pointers.
3556          *
3557          * Global list of NAT instances
3558          */
3559         nat->nat_next = softn->ipf_nat_instances;
3560         nat->nat_pnext = &softn->ipf_nat_instances;
3561         if (softn->ipf_nat_instances)
3562                 softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
3563         softn->ipf_nat_instances = nat;
3564
3565         /*
3566          * Inbound hash table.
3567          */
3568         natp = &softn->ipf_nat_table[0][hv0];
3569         nat->nat_phnext[0] = natp;
3570         nat->nat_hnext[0] = *natp;
3571         if (*natp) {
3572                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
3573         } else {
3574                 NBUMPSIDE(0, ns_inuse);
3575         }
3576         *natp = nat;
3577         NBUMPSIDE(0, ns_bucketlen[hv0]);
3578
3579         /*
3580          * Outbound hash table.
3581          */
3582         natp = &softn->ipf_nat_table[1][hv1];
3583         nat->nat_phnext[1] = natp;
3584         nat->nat_hnext[1] = *natp;
3585         if (*natp)
3586                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
3587         else {
3588                 NBUMPSIDE(1, ns_inuse);
3589         }
3590         *natp = nat;
3591         NBUMPSIDE(1, ns_bucketlen[hv1]);
3592
3593         ipf_nat_setqueue(softc, softn, nat);
3594
3595         if (nat->nat_dir & NAT_OUTBOUND) {
3596                 NBUMPSIDE(1, ns_added);
3597         } else {
3598                 NBUMPSIDE(0, ns_added);
3599         }
3600         softn->ipf_nat_stats.ns_active++;
3601         return 0;
3602 }
3603
3604
3605 /* ------------------------------------------------------------------------ */
3606 /* Function:    ipf_nat_icmperrorlookup                                     */
3607 /* Returns:     nat_t* - point to matching NAT structure                    */
3608 /* Parameters:  fin(I) - pointer to packet information                      */
3609 /*              dir(I) - direction of packet (in/out)                       */
3610 /*                                                                          */
3611 /* Check if the ICMP error message is related to an existing TCP, UDP or    */
3612 /* ICMP query nat entry.  It is assumed that the packet is already of the   */
3613 /* the required length.                                                     */
3614 /* ------------------------------------------------------------------------ */
3615 nat_t *
3616 ipf_nat_icmperrorlookup(fin, dir)
3617         fr_info_t *fin;
3618         int dir;
3619 {
3620         ipf_main_softc_t *softc = fin->fin_main_soft;
3621         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3622         int flags = 0, type, minlen;
3623         icmphdr_t *icmp, *orgicmp;
3624         nat_stat_side_t *nside;
3625         tcphdr_t *tcp = NULL;
3626         u_short data[2];
3627         nat_t *nat;
3628         ip_t *oip;
3629         u_int p;
3630
3631         icmp = fin->fin_dp;
3632         type = icmp->icmp_type;
3633         nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
3634         /*
3635          * Does it at least have the return (basic) IP header ?
3636          * Only a basic IP header (no options) should be with an ICMP error
3637          * header.  Also, if it's not an error type, then return.
3638          */
3639         if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) {
3640                 ATOMIC_INCL(nside->ns_icmp_basic);
3641                 return NULL;
3642         }
3643
3644         /*
3645          * Check packet size
3646          */
3647         oip = (ip_t *)((char *)fin->fin_dp + 8);
3648         minlen = IP_HL(oip) << 2;
3649         if ((minlen < sizeof(ip_t)) ||
3650             (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) {
3651                 ATOMIC_INCL(nside->ns_icmp_size);
3652                 return NULL;
3653         }
3654
3655         /*
3656          * Is the buffer big enough for all of it ?  It's the size of the IP
3657          * header claimed in the encapsulated part which is of concern.  It
3658          * may be too big to be in this buffer but not so big that it's
3659          * outside the ICMP packet, leading to TCP deref's causing problems.
3660          * This is possible because we don't know how big oip_hl is when we
3661          * do the pullup early in ipf_check() and thus can't gaurantee it is
3662          * all here now.
3663          */
3664 #ifdef  ipf_nat_KERNEL
3665         {
3666         mb_t *m;
3667
3668         m = fin->fin_m;
3669 # if defined(MENTAT)
3670         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3671             (char *)m->b_wptr) {
3672                 ATOMIC_INCL(nside->ns_icmp_mbuf);
3673                 return NULL;
3674         }
3675 # else
3676         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3677             (char *)fin->fin_ip + M_LEN(m)) {
3678                 ATOMIC_INCL(nside->ns_icmp_mbuf);
3679                 return NULL;
3680         }
3681 # endif
3682         }
3683 #endif
3684
3685         if (fin->fin_daddr != oip->ip_src.s_addr) {
3686                 ATOMIC_INCL(nside->ns_icmp_address);
3687                 return NULL;
3688         }
3689
3690         p = oip->ip_p;
3691         if (p == IPPROTO_TCP)
3692                 flags = IPN_TCP;
3693         else if (p == IPPROTO_UDP)
3694                 flags = IPN_UDP;
3695         else if (p == IPPROTO_ICMP) {
3696                 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3697
3698                 /* see if this is related to an ICMP query */
3699                 if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) {
3700                         data[0] = fin->fin_data[0];
3701                         data[1] = fin->fin_data[1];
3702                         fin->fin_data[0] = 0;
3703                         fin->fin_data[1] = orgicmp->icmp_id;
3704
3705                         flags = IPN_ICMPERR|IPN_ICMPQUERY;
3706                         /*
3707                          * NOTE : dir refers to the direction of the original
3708                          *        ip packet. By definition the icmp error
3709                          *        message flows in the opposite direction.
3710                          */
3711                         if (dir == NAT_INBOUND)
3712                                 nat = ipf_nat_inlookup(fin, flags, p,
3713                                                        oip->ip_dst,
3714                                                        oip->ip_src);
3715                         else
3716                                 nat = ipf_nat_outlookup(fin, flags, p,
3717                                                         oip->ip_dst,
3718                                                         oip->ip_src);
3719                         fin->fin_data[0] = data[0];
3720                         fin->fin_data[1] = data[1];
3721                         return nat;
3722                 }
3723         }
3724
3725         if (flags & IPN_TCPUDP) {
3726                 minlen += 8;            /* + 64bits of data to get ports */
3727                 /* TRACE (fin,minlen) */
3728                 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
3729                         ATOMIC_INCL(nside->ns_icmp_short);
3730                         return NULL;
3731                 }
3732
3733                 data[0] = fin->fin_data[0];
3734                 data[1] = fin->fin_data[1];
3735                 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3736                 fin->fin_data[0] = ntohs(tcp->th_dport);
3737                 fin->fin_data[1] = ntohs(tcp->th_sport);
3738
3739                 if (dir == NAT_INBOUND) {
3740                         nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst,
3741                                                oip->ip_src);
3742                 } else {
3743                         nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst,
3744                                             oip->ip_src);
3745                 }
3746                 fin->fin_data[0] = data[0];
3747                 fin->fin_data[1] = data[1];
3748                 return nat;
3749         }
3750         if (dir == NAT_INBOUND)
3751                 nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3752         else
3753                 nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3754
3755         return nat;
3756 }
3757
3758
3759 /* ------------------------------------------------------------------------ */
3760 /* Function:    ipf_nat_icmperror                                           */
3761 /* Returns:     nat_t* - point to matching NAT structure                    */
3762 /* Parameters:  fin(I)    - pointer to packet information                   */
3763 /*              nflags(I) - NAT flags for this packet                       */
3764 /*              dir(I)    - direction of packet (in/out)                    */
3765 /*                                                                          */
3766 /* Fix up an ICMP packet which is an error message for an existing NAT      */
3767 /* session.  This will correct both packet header data and checksums.       */
3768 /*                                                                          */
3769 /* This should *ONLY* be used for incoming ICMP error packets to make sure  */
3770 /* a NAT'd ICMP packet gets correctly recognised.                           */
3771 /* ------------------------------------------------------------------------ */
3772 nat_t *
3773 ipf_nat_icmperror(fin, nflags, dir)
3774         fr_info_t *fin;
3775         u_int *nflags;
3776         int dir;
3777 {
3778         ipf_main_softc_t *softc = fin->fin_main_soft;
3779         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3780         u_32_t sum1, sum2, sumd, sumd2;
3781         struct in_addr a1, a2, a3, a4;
3782         int flags, dlen, odst;
3783         icmphdr_t *icmp;
3784         u_short *csump;
3785         tcphdr_t *tcp;
3786         nat_t *nat;
3787         ip_t *oip;
3788         void *dp;
3789
3790         if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
3791                 NBUMPSIDED(fin->fin_out, ns_icmp_short);
3792                 return NULL;
3793         }
3794
3795         /*
3796          * ipf_nat_icmperrorlookup() will return NULL for `defective' packets.
3797          */
3798         if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) {
3799                 NBUMPSIDED(fin->fin_out, ns_icmp_notfound);
3800                 return NULL;
3801         }
3802
3803         tcp = NULL;
3804         csump = NULL;
3805         flags = 0;
3806         sumd2 = 0;
3807         *nflags = IPN_ICMPERR;
3808         icmp = fin->fin_dp;
3809         oip = (ip_t *)&icmp->icmp_ip;
3810         dp = (((char *)oip) + (IP_HL(oip) << 2));
3811         if (oip->ip_p == IPPROTO_TCP) {
3812                 tcp = (tcphdr_t *)dp;
3813                 csump = (u_short *)&tcp->th_sum;
3814                 flags = IPN_TCP;
3815         } else if (oip->ip_p == IPPROTO_UDP) {
3816                 udphdr_t *udp;
3817
3818                 udp = (udphdr_t *)dp;
3819                 tcp = (tcphdr_t *)dp;
3820                 csump = (u_short *)&udp->uh_sum;
3821                 flags = IPN_UDP;
3822         } else if (oip->ip_p == IPPROTO_ICMP)
3823                 flags = IPN_ICMPQUERY;
3824         dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
3825
3826         /*
3827          * Need to adjust ICMP header to include the real IP#'s and
3828          * port #'s.  Only apply a checksum change relative to the
3829          * IP address change as it will be modified again in ipf_nat_checkout
3830          * for both address and port.  Two checksum changes are
3831          * necessary for the two header address changes.  Be careful
3832          * to only modify the checksum once for the port # and twice
3833          * for the IP#.
3834          */
3835
3836         /*
3837          * Step 1
3838          * Fix the IP addresses in the offending IP packet. You also need
3839          * to adjust the IP header checksum of that offending IP packet.
3840          *
3841          * Normally, you would expect that the ICMP checksum of the
3842          * ICMP error message needs to be adjusted as well for the
3843          * IP address change in oip.
3844          * However, this is a NOP, because the ICMP checksum is
3845          * calculated over the complete ICMP packet, which includes the
3846          * changed oip IP addresses and oip->ip_sum. However, these
3847          * two changes cancel each other out (if the delta for
3848          * the IP address is x, then the delta for ip_sum is minus x),
3849          * so no change in the icmp_cksum is necessary.
3850          *
3851          * Inbound ICMP
3852          * ------------
3853          * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3854          * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
3855          * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(b)=nat_newdstip
3856          *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(b)=nat_olddstip
3857          *
3858          * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3859          * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3860          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3861          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3862          *
3863          * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3864          * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
3865          * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(d)=nat_newdstip
3866          *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(d)=nat_olddstip
3867          *
3868          * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3869          * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3870          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3871          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3872          *
3873          * Outbound ICMP
3874          * -------------
3875          * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3876          * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3877          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3878          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3879          *
3880          * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3881          * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
3882          * - OIP_SRC(a)=nat_newsrcip,          OIP_DST(c)=nat_newdstip
3883          *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3884          *
3885          * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3886          * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
3887          * - OIP_SRC(c)=nat_olddstip,          OIP_DST(d)=nat_oldsrcip
3888          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3889          *
3890          * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3891          * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
3892          * - OIP_SRC(b)=nat_newsrcip,          OIP_DST(a)=nat_newdstip
3893          *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3894          */
3895
3896         if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
3897             ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
3898                 a1.s_addr = ntohl(nat->nat_osrcaddr);
3899                 a4.s_addr = ntohl(oip->ip_src.s_addr);
3900                 a3.s_addr = ntohl(nat->nat_odstaddr);
3901                 a2.s_addr = ntohl(oip->ip_dst.s_addr);
3902                 oip->ip_src.s_addr = htonl(a1.s_addr);
3903                 oip->ip_dst.s_addr = htonl(a3.s_addr);
3904                 odst = 1;
3905         } else {
3906                 a1.s_addr = ntohl(nat->nat_ndstaddr);
3907                 a2.s_addr = ntohl(oip->ip_dst.s_addr);
3908                 a3.s_addr = ntohl(nat->nat_nsrcaddr);
3909                 a4.s_addr = ntohl(oip->ip_src.s_addr);
3910                 oip->ip_dst.s_addr = htonl(a3.s_addr);
3911                 oip->ip_src.s_addr = htonl(a1.s_addr);
3912                 odst = 0;
3913         }
3914         sum1 = 0;
3915         sum2 = 0;
3916         sumd = 0;
3917         CALC_SUMD(a2.s_addr, a3.s_addr, sum1);
3918         CALC_SUMD(a4.s_addr, a1.s_addr, sum2);
3919         sumd = sum2 + sum1;
3920         if (sumd != 0)
3921                 ipf_fix_datacksum(&oip->ip_sum, sumd);
3922
3923         sumd2 = sumd;
3924         sum1 = 0;
3925         sum2 = 0;
3926
3927         /*
3928          * Fix UDP pseudo header checksum to compensate for the
3929          * IP address change.
3930          */
3931         if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
3932                 u_32_t sum3, sum4, sumt;
3933
3934                 /*
3935                  * Step 2 :
3936                  * For offending TCP/UDP IP packets, translate the ports as
3937                  * well, based on the NAT specification. Of course such
3938                  * a change may be reflected in the ICMP checksum as well.
3939                  *
3940                  * Since the port fields are part of the TCP/UDP checksum
3941                  * of the offending IP packet, you need to adjust that checksum
3942                  * as well... except that the change in the port numbers should
3943                  * be offset by the checksum change.  However, the TCP/UDP
3944                  * checksum will also need to change if there has been an
3945                  * IP address change.
3946                  */
3947                 if (odst == 1) {
3948                         sum1 = ntohs(nat->nat_osport);
3949                         sum4 = ntohs(tcp->th_sport);
3950                         sum3 = ntohs(nat->nat_odport);
3951                         sum2 = ntohs(tcp->th_dport);
3952
3953                         tcp->th_sport = htons(sum1);
3954                         tcp->th_dport = htons(sum3);
3955                 } else {
3956                         sum1 = ntohs(nat->nat_ndport);
3957                         sum2 = ntohs(tcp->th_dport);
3958                         sum3 = ntohs(nat->nat_nsport);
3959                         sum4 = ntohs(tcp->th_sport);
3960
3961                         tcp->th_dport = htons(sum3);
3962                         tcp->th_sport = htons(sum1);
3963                 }
3964                 CALC_SUMD(sum4, sum1, sumt);
3965                 sumd += sumt;
3966                 CALC_SUMD(sum2, sum3, sumt);
3967                 sumd += sumt;
3968
3969                 if (sumd != 0 || sumd2 != 0) {
3970                         /*
3971                          * At this point, sumd is the delta to apply to the
3972                          * TCP/UDP header, given the changes in both the IP
3973                          * address and the ports and sumd2 is the delta to
3974                          * apply to the ICMP header, given the IP address
3975                          * change delta that may need to be applied to the
3976                          * TCP/UDP checksum instead.
3977                          *
3978                          * If we will both the IP and TCP/UDP checksums
3979                          * then the ICMP checksum changes by the address
3980                          * delta applied to the TCP/UDP checksum.  If we
3981                          * do not change the TCP/UDP checksum them we
3982                          * apply the delta in ports to the ICMP checksum.
3983                          */
3984                         if (oip->ip_p == IPPROTO_UDP) {
3985                                 if ((dlen >= 8) && (*csump != 0)) {
3986                                         ipf_fix_datacksum(csump, sumd);
3987                                 } else {
3988                                         CALC_SUMD(sum1, sum4, sumd2);
3989                                         CALC_SUMD(sum3, sum2, sumt);
3990                                         sumd2 += sumt;
3991                                 }
3992                         } else if (oip->ip_p == IPPROTO_TCP) {
3993                                 if (dlen >= 18) {
3994                                         ipf_fix_datacksum(csump, sumd);
3995                                 } else {
3996                                         CALC_SUMD(sum1, sum4, sumd2);
3997                                         CALC_SUMD(sum3, sum2, sumt);
3998                                         sumd2 += sumt;
3999                                 }
4000                         }
4001                         if (sumd2 != 0) {
4002                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4003                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4004                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4005                                 ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0);
4006                         }
4007                 }
4008         } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
4009                 icmphdr_t *orgicmp;
4010
4011                 /*
4012                  * XXX - what if this is bogus hl and we go off the end ?
4013                  * In this case, ipf_nat_icmperrorlookup() will have
4014                  * returned NULL.
4015                  */
4016                 orgicmp = (icmphdr_t *)dp;
4017
4018                 if (odst == 1) {
4019                         if (orgicmp->icmp_id != nat->nat_osport) {
4020
4021                                 /*
4022                                  * Fix ICMP checksum (of the offening ICMP
4023                                  * query packet) to compensate the change
4024                                  * in the ICMP id of the offending ICMP
4025                                  * packet.
4026                                  *
4027                                  * Since you modify orgicmp->icmp_id with
4028                                  * a delta (say x) and you compensate that
4029                                  * in origicmp->icmp_cksum with a delta
4030                                  * minus x, you don't have to adjust the
4031                                  * overall icmp->icmp_cksum
4032                                  */
4033                                 sum1 = ntohs(orgicmp->icmp_id);
4034                                 sum2 = ntohs(nat->nat_oicmpid);
4035                                 CALC_SUMD(sum1, sum2, sumd);
4036                                 orgicmp->icmp_id = nat->nat_oicmpid;
4037                                 ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd);
4038                         }
4039                 } /* nat_dir == NAT_INBOUND is impossible for icmp queries */
4040         }
4041         return nat;
4042 }
4043
4044
4045 /*
4046  *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
4047  * osrc    X       == src    == src      X
4048  * odst    X       == dst    == dst      X
4049  * nsrc  == dst      X         X      == dst
4050  * ndst  == src      X         X      == src
4051  * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
4052  */
4053 /*
4054  * NB: these lookups don't lock access to the list, it assumed that it has
4055  * already been done!
4056  */
4057 /* ------------------------------------------------------------------------ */
4058 /* Function:    ipf_nat_inlookup                                            */
4059 /* Returns:     nat_t* - NULL == no match,                                  */
4060 /*                       else pointer to matching NAT entry                 */
4061 /* Parameters:  fin(I)    - pointer to packet information                   */
4062 /*              flags(I)  - NAT flags for this packet                       */
4063 /*              p(I)      - protocol for this packet                        */
4064 /*              src(I)    - source IP address                               */
4065 /*              mapdst(I) - destination IP address                          */
4066 /*                                                                          */
4067 /* Lookup a nat entry based on the mapped destination ip address/port and   */
4068 /* real source address/port.  We use this lookup when receiving a packet,   */
4069 /* we're looking for a table entry, based on the destination address.       */
4070 /*                                                                          */
4071 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4072 /*                                                                          */
4073 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4074 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4075 /*                                                                          */
4076 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4077 /*            the packet is of said protocol                                */
4078 /* ------------------------------------------------------------------------ */
4079 nat_t *
4080 ipf_nat_inlookup(fin, flags, p, src, mapdst)
4081         fr_info_t *fin;
4082         u_int flags, p;
4083         struct in_addr src , mapdst;
4084 {
4085         ipf_main_softc_t *softc = fin->fin_main_soft;
4086         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4087         u_short sport, dport;
4088         grehdr_t *gre;
4089         ipnat_t *ipn;
4090         u_int sflags;
4091         nat_t *nat;
4092         int nflags;
4093         u_32_t dst;
4094         void *ifp;
4095         u_int hv, rhv;
4096
4097         ifp = fin->fin_ifp;
4098         gre = NULL;
4099         dst = mapdst.s_addr;
4100         sflags = flags & NAT_TCPUDPICMP;
4101
4102         switch (p)
4103         {
4104         case IPPROTO_TCP :
4105         case IPPROTO_UDP :
4106                 sport = htons(fin->fin_data[0]);
4107                 dport = htons(fin->fin_data[1]);
4108                 break;
4109         case IPPROTO_ICMP :
4110                 if (flags & IPN_ICMPERR) {
4111                         sport = fin->fin_data[1];
4112                         dport = 0;
4113                 } else {
4114                         dport = fin->fin_data[1];
4115                         sport = 0;
4116                 }
4117                 break;
4118         default :
4119                 sport = 0;
4120                 dport = 0;
4121                 break;
4122         }
4123
4124
4125         if ((flags & SI_WILDP) != 0)
4126                 goto find_in_wild_ports;
4127
4128         rhv = NAT_HASH_FN(dst, dport, 0xffffffff);
4129         rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff);
4130         hv = rhv % softn->ipf_nat_table_sz;
4131         nat = softn->ipf_nat_table[1][hv];
4132         /* TRACE dst, dport, src, sport, hv, nat */
4133
4134         for (; nat; nat = nat->nat_hnext[1]) {
4135                 if (nat->nat_ifps[0] != NULL) {
4136                         if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4137                                 continue;
4138                 }
4139
4140                 if (nat->nat_pr[0] != p)
4141                         continue;
4142
4143                 switch (nat->nat_dir)
4144                 {
4145                 case NAT_INBOUND :
4146                 case NAT_DIVERTIN :
4147                         if (nat->nat_v[0] != 4)
4148                                 continue;
4149                         if (nat->nat_osrcaddr != src.s_addr ||
4150                             nat->nat_odstaddr != dst)
4151                                 continue;
4152                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4153                                 if (nat->nat_osport != sport)
4154                                         continue;
4155                                 if (nat->nat_odport != dport)
4156                                         continue;
4157
4158                         } else if (p == IPPROTO_ICMP) {
4159                                 if (nat->nat_osport != dport) {
4160                                         continue;
4161                                 }
4162                         }
4163                         break;
4164                 case NAT_DIVERTOUT :
4165                         if (nat->nat_dlocal)
4166                                 continue;
4167                 case NAT_OUTBOUND :
4168                         if (nat->nat_v[1] != 4)
4169                                 continue;
4170                         if (nat->nat_dlocal)
4171                                 continue;
4172                         if (nat->nat_dlocal)
4173                                 continue;
4174                         if (nat->nat_ndstaddr != src.s_addr ||
4175                             nat->nat_nsrcaddr != dst)
4176                                 continue;
4177                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4178                                 if (nat->nat_ndport != sport)
4179                                         continue;
4180                                 if (nat->nat_nsport != dport)
4181                                         continue;
4182
4183                         } else if (p == IPPROTO_ICMP) {
4184                                 if (nat->nat_osport != dport) {
4185                                         continue;
4186                                 }
4187                         }
4188                         break;
4189                 }
4190
4191
4192                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4193                         ipn = nat->nat_ptr;
4194                         if ((ipn != NULL) && (nat->nat_aps != NULL))
4195                                 if (ipf_proxy_match(fin, nat) != 0)
4196                                         continue;
4197                 }
4198                 if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4199                         nat->nat_ifps[0] = ifp;
4200                         nat->nat_mtu[0] = GETIFMTU_4(ifp);
4201                 }
4202                 return nat;
4203         }
4204
4205         /*
4206          * So if we didn't find it but there are wildcard members in the hash
4207          * table, go back and look for them.  We do this search and update here
4208          * because it is modifying the NAT table and we want to do this only
4209          * for the first packet that matches.  The exception, of course, is
4210          * for "dummy" (FI_IGNORE) lookups.
4211          */
4212 find_in_wild_ports:
4213         if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4214                 NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0);
4215                 return NULL;
4216         }
4217         if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4218                 NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0);
4219                 return NULL;
4220         }
4221
4222         RWLOCK_EXIT(&softc->ipf_nat);
4223
4224         hv = NAT_HASH_FN(dst, 0, 0xffffffff);
4225         hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz);
4226         WRITE_ENTER(&softc->ipf_nat);
4227
4228         nat = softn->ipf_nat_table[1][hv];
4229         /* TRACE dst, src, hv, nat */
4230         for (; nat; nat = nat->nat_hnext[1]) {
4231                 if (nat->nat_ifps[0] != NULL) {
4232                         if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4233                                 continue;
4234                 }
4235
4236                 if (nat->nat_pr[0] != fin->fin_p)
4237                         continue;
4238
4239                 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4240                 {
4241                 case NAT_INBOUND :
4242                         if (nat->nat_v[0] != 4)
4243                                 continue;
4244                         if (nat->nat_osrcaddr != src.s_addr ||
4245                             nat->nat_odstaddr != dst)
4246                                 continue;
4247                         break;
4248                 case NAT_OUTBOUND :
4249                         if (nat->nat_v[1] != 4)
4250                                 continue;
4251                         if (nat->nat_ndstaddr != src.s_addr ||
4252                             nat->nat_nsrcaddr != dst)
4253                                 continue;
4254                         break;
4255                 }
4256
4257                 nflags = nat->nat_flags;
4258                 if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
4259                         continue;
4260
4261                 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
4262                                    NAT_INBOUND) == 1) {
4263                         if ((fin->fin_flx & FI_IGNORE) != 0)
4264                                 break;
4265                         if ((nflags & SI_CLONE) != 0) {
4266                                 nat = ipf_nat_clone(fin, nat);
4267                                 if (nat == NULL)
4268                                         break;
4269                         } else {
4270                                 MUTEX_ENTER(&softn->ipf_nat_new);
4271                                 softn->ipf_nat_stats.ns_wilds--;
4272                                 MUTEX_EXIT(&softn->ipf_nat_new);
4273                         }
4274
4275                         if (nat->nat_dir == NAT_INBOUND) {
4276                                 if (nat->nat_osport == 0) {
4277                                         nat->nat_osport = sport;
4278                                         nat->nat_nsport = sport;
4279                                 }
4280                                 if (nat->nat_odport == 0) {
4281                                         nat->nat_odport = dport;
4282                                         nat->nat_ndport = dport;
4283                                 }
4284                         } else if (nat->nat_dir == NAT_OUTBOUND) {
4285                                 if (nat->nat_osport == 0) {
4286                                         nat->nat_osport = dport;
4287                                         nat->nat_nsport = dport;
4288                                 }
4289                                 if (nat->nat_odport == 0) {
4290                                         nat->nat_odport = sport;
4291                                         nat->nat_ndport = sport;
4292                                 }
4293                         }
4294                         if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4295                                 nat->nat_ifps[0] = ifp;
4296                                 nat->nat_mtu[0] = GETIFMTU_4(ifp);
4297                         }
4298                         nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4299                         ipf_nat_tabmove(softn, nat);
4300                         break;
4301                 }
4302         }
4303
4304         MUTEX_DOWNGRADE(&softc->ipf_nat);
4305
4306         if (nat == NULL) {
4307                 NBUMPSIDE(0, ns_lookup_miss);
4308         }
4309         return nat;
4310 }
4311
4312
4313 /* ------------------------------------------------------------------------ */
4314 /* Function:    ipf_nat_tabmove                                             */
4315 /* Returns:     Nil                                                         */
4316 /* Parameters:  softn(I) - pointer to NAT context structure                 */
4317 /*              nat(I)   - pointer to NAT structure                         */
4318 /* Write Lock:  ipf_nat                                                     */
4319 /*                                                                          */
4320 /* This function is only called for TCP/UDP NAT table entries where the     */
4321 /* original was placed in the table without hashing on the ports and we now */
4322 /* want to include hashing on port numbers.                                 */
4323 /* ------------------------------------------------------------------------ */
4324 static void
4325 ipf_nat_tabmove(softn, nat)
4326         ipf_nat_softc_t *softn;
4327         nat_t *nat;
4328 {
4329         u_int hv0, hv1, rhv0, rhv1;
4330         natstat_t *nsp;
4331         nat_t **natp;
4332
4333         if (nat->nat_flags & SI_CLONE)
4334                 return;
4335
4336         nsp = &softn->ipf_nat_stats;
4337         /*
4338          * Remove the NAT entry from the old location
4339          */
4340         if (nat->nat_hnext[0])
4341                 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
4342         *nat->nat_phnext[0] = nat->nat_hnext[0];
4343         nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] %
4344                                      softn->ipf_nat_table_sz]--;
4345
4346         if (nat->nat_hnext[1])
4347                 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
4348         *nat->nat_phnext[1] = nat->nat_hnext[1];
4349         nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] %
4350                                      softn->ipf_nat_table_sz]--;
4351
4352         /*
4353          * Add into the NAT table in the new position
4354          */
4355         rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff);
4356         rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport,
4357                            0xffffffff);
4358         rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff);
4359         rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport,
4360                            0xffffffff);
4361
4362         hv0 = rhv0 % softn->ipf_nat_table_sz;
4363         hv1 = rhv1 % softn->ipf_nat_table_sz;
4364
4365         if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
4366                 u_int swap;
4367
4368                 swap = hv0;
4369                 hv0 = hv1;
4370                 hv1 = swap;
4371         }
4372
4373         /* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */
4374         /* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */
4375
4376         nat->nat_hv[0] = rhv0;
4377         natp = &softn->ipf_nat_table[0][hv0];
4378         if (*natp)
4379                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
4380         nat->nat_phnext[0] = natp;
4381         nat->nat_hnext[0] = *natp;
4382         *natp = nat;
4383         nsp->ns_side[0].ns_bucketlen[hv0]++;
4384
4385         nat->nat_hv[1] = rhv1;
4386         natp = &softn->ipf_nat_table[1][hv1];
4387         if (*natp)
4388                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
4389         nat->nat_phnext[1] = natp;
4390         nat->nat_hnext[1] = *natp;
4391         *natp = nat;
4392         nsp->ns_side[1].ns_bucketlen[hv1]++;
4393 }
4394
4395
4396 /* ------------------------------------------------------------------------ */
4397 /* Function:    ipf_nat_outlookup                                           */
4398 /* Returns:     nat_t* - NULL == no match,                                  */
4399 /*                       else pointer to matching NAT entry                 */
4400 /* Parameters:  fin(I)   - pointer to packet information                    */
4401 /*              flags(I) - NAT flags for this packet                        */
4402 /*              p(I)     - protocol for this packet                         */
4403 /*              src(I)   - source IP address                                */
4404 /*              dst(I)   - destination IP address                           */
4405 /*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
4406 /*                                                                          */
4407 /* Lookup a nat entry based on the source 'real' ip address/port and        */
4408 /* destination address/port.  We use this lookup when sending a packet out, */
4409 /* we're looking for a table entry, based on the source address.            */
4410 /*                                                                          */
4411 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4412 /*                                                                          */
4413 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4414 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4415 /*                                                                          */
4416 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4417 /*            the packet is of said protocol                                */
4418 /* ------------------------------------------------------------------------ */
4419 nat_t *
4420 ipf_nat_outlookup(fin, flags, p, src, dst)
4421         fr_info_t *fin;
4422         u_int flags, p;
4423         struct in_addr src , dst;
4424 {
4425         ipf_main_softc_t *softc = fin->fin_main_soft;
4426         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4427         u_short sport, dport;
4428         u_int sflags;
4429         ipnat_t *ipn;
4430         nat_t *nat;
4431         void *ifp;
4432         u_int hv;
4433
4434         ifp = fin->fin_ifp;
4435         sflags = flags & IPN_TCPUDPICMP;
4436         sport = 0;
4437         dport = 0;
4438
4439         switch (p)
4440         {
4441         case IPPROTO_TCP :
4442         case IPPROTO_UDP :
4443                 sport = htons(fin->fin_data[0]);
4444                 dport = htons(fin->fin_data[1]);
4445                 break;
4446         case IPPROTO_ICMP :
4447                 if (flags & IPN_ICMPERR)
4448                         sport = fin->fin_data[1];
4449                 else
4450                         dport = fin->fin_data[1];
4451                 break;
4452         default :
4453                 break;
4454         }
4455
4456         if ((flags & SI_WILDP) != 0)
4457                 goto find_out_wild_ports;
4458
4459         hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff);
4460         hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz);
4461         nat = softn->ipf_nat_table[0][hv];
4462
4463         /* TRACE src, sport, dst, dport, hv, nat */
4464
4465         for (; nat; nat = nat->nat_hnext[0]) {
4466                 if (nat->nat_ifps[1] != NULL) {
4467                         if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4468                                 continue;
4469                 }
4470
4471                 if (nat->nat_pr[1] != p)
4472                         continue;
4473
4474                 switch (nat->nat_dir)
4475                 {
4476                 case NAT_INBOUND :
4477                 case NAT_DIVERTIN :
4478                         if (nat->nat_v[1] != 4)
4479                                 continue;
4480                         if (nat->nat_ndstaddr != src.s_addr ||
4481                             nat->nat_nsrcaddr != dst.s_addr)
4482                                 continue;
4483
4484                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4485                                 if (nat->nat_ndport != sport)
4486                                         continue;
4487                                 if (nat->nat_nsport != dport)
4488                                         continue;
4489
4490                         } else if (p == IPPROTO_ICMP) {
4491                                 if (nat->nat_osport != dport) {
4492                                         continue;
4493                                 }
4494                         }
4495                         break;
4496                 case NAT_OUTBOUND :
4497                 case NAT_DIVERTOUT :
4498                         if (nat->nat_v[0] != 4)
4499                                 continue;
4500                         if (nat->nat_osrcaddr != src.s_addr ||
4501                             nat->nat_odstaddr != dst.s_addr)
4502                                 continue;
4503
4504                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4505                                 if (nat->nat_odport != dport)
4506                                         continue;
4507                                 if (nat->nat_osport != sport)
4508                                         continue;
4509
4510                         } else if (p == IPPROTO_ICMP) {
4511                                 if (nat->nat_osport != dport) {
4512                                         continue;
4513                                 }
4514                         }
4515                         break;
4516                 }
4517
4518                 ipn = nat->nat_ptr;
4519                 if ((ipn != NULL) && (nat->nat_aps != NULL))
4520                         if (ipf_proxy_match(fin, nat) != 0)
4521                                 continue;
4522
4523                 if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4524                         nat->nat_ifps[1] = ifp;
4525                         nat->nat_mtu[1] = GETIFMTU_4(ifp);
4526                 }
4527                 return nat;
4528         }
4529
4530         /*
4531          * So if we didn't find it but there are wildcard members in the hash
4532          * table, go back and look for them.  We do this search and update here
4533          * because it is modifying the NAT table and we want to do this only
4534          * for the first packet that matches.  The exception, of course, is
4535          * for "dummy" (FI_IGNORE) lookups.
4536          */
4537 find_out_wild_ports:
4538         if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4539                 NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1);
4540                 return NULL;
4541         }
4542         if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4543                 NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1);
4544                 return NULL;
4545         }
4546
4547         RWLOCK_EXIT(&softc->ipf_nat);
4548
4549         hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff);
4550         hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz);
4551
4552         WRITE_ENTER(&softc->ipf_nat);
4553
4554         nat = softn->ipf_nat_table[0][hv];
4555         for (; nat; nat = nat->nat_hnext[0]) {
4556                 if (nat->nat_ifps[1] != NULL) {
4557                         if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4558                                 continue;
4559                 }
4560
4561                 if (nat->nat_pr[1] != fin->fin_p)
4562                         continue;
4563
4564                 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4565                 {
4566                 case NAT_INBOUND :
4567                         if (nat->nat_v[1] != 4)
4568                                 continue;
4569                         if (nat->nat_ndstaddr != src.s_addr ||
4570                             nat->nat_nsrcaddr != dst.s_addr)
4571                                 continue;
4572                         break;
4573                 case NAT_OUTBOUND :
4574                         if (nat->nat_v[0] != 4)
4575                                 continue;
4576                         if (nat->nat_osrcaddr != src.s_addr ||
4577                             nat->nat_odstaddr != dst.s_addr)
4578                                 continue;
4579                         break;
4580                 }
4581
4582                 if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
4583                         continue;
4584
4585                 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
4586                                    NAT_OUTBOUND) == 1) {
4587                         if ((fin->fin_flx & FI_IGNORE) != 0)
4588                                 break;
4589                         if ((nat->nat_flags & SI_CLONE) != 0) {
4590                                 nat = ipf_nat_clone(fin, nat);
4591                                 if (nat == NULL)
4592                                         break;
4593                         } else {
4594                                 MUTEX_ENTER(&softn->ipf_nat_new);
4595                                 softn->ipf_nat_stats.ns_wilds--;
4596                                 MUTEX_EXIT(&softn->ipf_nat_new);
4597                         }
4598
4599                         if (nat->nat_dir == NAT_OUTBOUND) {
4600                                 if (nat->nat_osport == 0) {
4601                                         nat->nat_osport = sport;
4602                                         nat->nat_nsport = sport;
4603                                 }
4604                                 if (nat->nat_odport == 0) {
4605                                         nat->nat_odport = dport;
4606                                         nat->nat_ndport = dport;
4607                                 }
4608                         } else if (nat->nat_dir == NAT_INBOUND) {
4609                                 if (nat->nat_osport == 0) {
4610                                         nat->nat_osport = dport;
4611                                         nat->nat_nsport = dport;
4612                                 }
4613                                 if (nat->nat_odport == 0) {
4614                                         nat->nat_odport = sport;
4615                                         nat->nat_ndport = sport;
4616                                 }
4617                         }
4618                         if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4619                                 nat->nat_ifps[1] = ifp;
4620                                 nat->nat_mtu[1] = GETIFMTU_4(ifp);
4621                         }
4622                         nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4623                         ipf_nat_tabmove(softn, nat);
4624                         break;
4625                 }
4626         }
4627
4628         MUTEX_DOWNGRADE(&softc->ipf_nat);
4629
4630         if (nat == NULL) {
4631                 NBUMPSIDE(1, ns_lookup_miss);
4632         }
4633         return nat;
4634 }
4635
4636
4637 /* ------------------------------------------------------------------------ */
4638 /* Function:    ipf_nat_lookupredir                                         */
4639 /* Returns:     nat_t* - NULL == no match,                                  */
4640 /*                       else pointer to matching NAT entry                 */
4641 /* Parameters:  np(I) - pointer to description of packet to find NAT table  */
4642 /*                      entry for.                                          */
4643 /*                                                                          */
4644 /* Lookup the NAT tables to search for a matching redirect                  */
4645 /* The contents of natlookup_t should imitate those found in a packet that  */
4646 /* would be translated - ie a packet coming in for RDR or going out for MAP.*/
4647 /* We can do the lookup in one of two ways, imitating an inbound or         */
4648 /* outbound  packet.  By default we assume outbound, unless IPN_IN is set.  */
4649 /* For IN, the fields are set as follows:                                   */
4650 /*     nl_real* = source information                                        */
4651 /*     nl_out* = destination information (translated)                       */
4652 /* For an out packet, the fields are set like this:                         */
4653 /*     nl_in* = source information (untranslated)                           */
4654 /*     nl_out* = destination information (translated)                       */
4655 /* ------------------------------------------------------------------------ */
4656 nat_t *
4657 ipf_nat_lookupredir(np)
4658         natlookup_t *np;
4659 {
4660         fr_info_t fi;
4661         nat_t *nat;
4662
4663         bzero((char *)&fi, sizeof(fi));
4664         if (np->nl_flags & IPN_IN) {
4665                 fi.fin_data[0] = ntohs(np->nl_realport);
4666                 fi.fin_data[1] = ntohs(np->nl_outport);
4667         } else {
4668                 fi.fin_data[0] = ntohs(np->nl_inport);
4669                 fi.fin_data[1] = ntohs(np->nl_outport);
4670         }
4671         if (np->nl_flags & IPN_TCP)
4672                 fi.fin_p = IPPROTO_TCP;
4673         else if (np->nl_flags & IPN_UDP)
4674                 fi.fin_p = IPPROTO_UDP;
4675         else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
4676                 fi.fin_p = IPPROTO_ICMP;
4677
4678         /*
4679          * We can do two sorts of lookups:
4680          * - IPN_IN: we have the `real' and `out' address, look for `in'.
4681          * - default: we have the `in' and `out' address, look for `real'.
4682          */
4683         if (np->nl_flags & IPN_IN) {
4684                 if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p,
4685                                             np->nl_realip, np->nl_outip))) {
4686                         np->nl_inip = nat->nat_odstip;
4687                         np->nl_inport = nat->nat_odport;
4688                 }
4689         } else {
4690                 /*
4691                  * If nl_inip is non null, this is a lookup based on the real
4692                  * ip address. Else, we use the fake.
4693                  */
4694                 if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p,
4695                                          np->nl_inip, np->nl_outip))) {
4696
4697                         if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
4698                                 fr_info_t fin;
4699                                 bzero((char *)&fin, sizeof(fin));
4700                                 fin.fin_p = nat->nat_pr[0];
4701                                 fin.fin_data[0] = ntohs(nat->nat_ndport);
4702                                 fin.fin_data[1] = ntohs(nat->nat_nsport);
4703                                 if (ipf_nat_inlookup(&fin, np->nl_flags,
4704                                                      fin.fin_p, nat->nat_ndstip,
4705                                                      nat->nat_nsrcip) != NULL) {
4706                                         np->nl_flags &= ~IPN_FINDFORWARD;
4707                                 }
4708                         }
4709
4710                         np->nl_realip = nat->nat_ndstip;
4711                         np->nl_realport = nat->nat_ndport;
4712                 }
4713         }
4714
4715         return nat;
4716 }
4717
4718
4719 /* ------------------------------------------------------------------------ */
4720 /* Function:    ipf_nat_match                                               */
4721 /* Returns:     int - 0 == no match, 1 == match                             */
4722 /* Parameters:  fin(I)   - pointer to packet information                    */
4723 /*              np(I)    - pointer to NAT rule                              */
4724 /*                                                                          */
4725 /* Pull the matching of a packet against a NAT rule out of that complex     */
4726 /* loop inside ipf_nat_checkin() and lay it out properly in its own function. */
4727 /* ------------------------------------------------------------------------ */
4728 static int
4729 ipf_nat_match(fin, np)
4730         fr_info_t *fin;
4731         ipnat_t *np;
4732 {
4733         ipf_main_softc_t *softc = fin->fin_main_soft;
4734         frtuc_t *ft;
4735         int match;
4736
4737         match = 0;
4738         switch (np->in_osrcatype)
4739         {
4740         case FRI_NORMAL :
4741                 match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr);
4742                 break;
4743         case FRI_LOOKUP :
4744                 match = (*np->in_osrcfunc)(softc, np->in_osrcptr,
4745                                            4, &fin->fin_saddr, fin->fin_plen);
4746                 break;
4747         }
4748         match ^= ((np->in_flags & IPN_NOTSRC) != 0);
4749         if (match)
4750                 return 0;
4751
4752         match = 0;
4753         switch (np->in_odstatype)
4754         {
4755         case FRI_NORMAL :
4756                 match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr);
4757                 break;
4758         case FRI_LOOKUP :
4759                 match = (*np->in_odstfunc)(softc, np->in_odstptr,
4760                                            4, &fin->fin_daddr, fin->fin_plen);
4761                 break;
4762         }
4763
4764         match ^= ((np->in_flags & IPN_NOTDST) != 0);
4765         if (match)
4766                 return 0;
4767
4768         ft = &np->in_tuc;
4769         if (!(fin->fin_flx & FI_TCPUDP) ||
4770             (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
4771                 if (ft->ftu_scmp || ft->ftu_dcmp)
4772                         return 0;
4773                 return 1;
4774         }
4775
4776         return ipf_tcpudpchk(&fin->fin_fi, ft);
4777 }
4778
4779
4780 /* ------------------------------------------------------------------------ */
4781 /* Function:    ipf_nat_update                                              */
4782 /* Returns:     Nil                                                         */
4783 /* Parameters:  fin(I) - pointer to packet information                      */
4784 /*              nat(I) - pointer to NAT structure                           */
4785 /*                                                                          */
4786 /* Updates the lifetime of a NAT table entry for non-TCP packets.  Must be  */
4787 /* called with fin_rev updated - i.e. after calling ipf_nat_proto().        */
4788 /*                                                                          */
4789 /* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to     */
4790 /* already be set.                                                          */
4791 /* ------------------------------------------------------------------------ */
4792 void
4793 ipf_nat_update(fin, nat)
4794         fr_info_t *fin;
4795         nat_t *nat;
4796 {
4797         ipf_main_softc_t *softc = fin->fin_main_soft;
4798         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4799         ipftq_t *ifq, *ifq2;
4800         ipftqent_t *tqe;
4801         ipnat_t *np = nat->nat_ptr;
4802
4803         tqe = &nat->nat_tqe;
4804         ifq = tqe->tqe_ifq;
4805
4806         /*
4807          * We allow over-riding of NAT timeouts from NAT rules, even for
4808          * TCP, however, if it is TCP and there is no rule timeout set,
4809          * then do not update the timeout here.
4810          */
4811         if (np != NULL) {
4812                 np->in_bytes[fin->fin_rev] += fin->fin_plen;
4813                 ifq2 = np->in_tqehead[fin->fin_rev];
4814         } else {
4815                 ifq2 = NULL;
4816         }
4817
4818         if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) {
4819                 (void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq,
4820                                    0, 2);
4821         } else {
4822                 if (ifq2 == NULL) {
4823                         if (nat->nat_pr[0] == IPPROTO_UDP)
4824                                 ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq :
4825                                                       &softn->ipf_nat_udptq;
4826                         else if (nat->nat_pr[0] == IPPROTO_ICMP ||
4827                                  nat->nat_pr[0] == IPPROTO_ICMPV6)
4828                                 ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq:
4829                                                       &softn->ipf_nat_icmptq;
4830                         else
4831                                 ifq2 = &softn->ipf_nat_iptq;
4832                 }
4833
4834                 ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2);
4835         }
4836 }
4837
4838
4839 /* ------------------------------------------------------------------------ */
4840 /* Function:    ipf_nat_checkout                                            */
4841 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
4842 /*                     0 == no packet translation occurred,                 */
4843 /*                     1 == packet was successfully translated.             */
4844 /* Parameters:  fin(I)   - pointer to packet information                    */
4845 /*              passp(I) - pointer to filtering result flags                */
4846 /*                                                                          */
4847 /* Check to see if an outcoming packet should be changed.  ICMP packets are */
4848 /* first checked to see if they match an existing entry (if an error),      */
4849 /* otherwise a search of the current NAT table is made.  If neither results */
4850 /* in a match then a search for a matching NAT rule is made.  Create a new  */
4851 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
4852 /* packet header(s) as required.                                            */
4853 /* ------------------------------------------------------------------------ */
4854 int
4855 ipf_nat_checkout(fin, passp)
4856         fr_info_t *fin;
4857         u_32_t *passp;
4858 {
4859         ipnat_t *np = NULL, *npnext;
4860         struct ifnet *ifp, *sifp;
4861         ipf_main_softc_t *softc;
4862         ipf_nat_softc_t *softn;
4863         icmphdr_t *icmp = NULL;
4864         tcphdr_t *tcp = NULL;
4865         int rval, natfailed;
4866         u_int nflags = 0;
4867         u_32_t ipa, iph;
4868         int natadd = 1;
4869         frentry_t *fr;
4870         nat_t *nat;
4871
4872         if (fin->fin_v == 6) {
4873 #ifdef USE_INET6
4874                 return ipf_nat6_checkout(fin, passp);
4875 #else
4876                 return 0;
4877 #endif
4878         }
4879
4880         softc = fin->fin_main_soft;
4881         softn = softc->ipf_nat_soft;
4882
4883         if (softn->ipf_nat_lock != 0)
4884                 return 0;
4885         if (softn->ipf_nat_stats.ns_rules == 0 &&
4886             softn->ipf_nat_instances == NULL)
4887                 return 0;
4888
4889         natfailed = 0;
4890         fr = fin->fin_fr;
4891         sifp = fin->fin_ifp;
4892         if (fr != NULL) {
4893                 ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
4894                 if ((ifp != NULL) && (ifp != (void *)-1))
4895                         fin->fin_ifp = ifp;
4896         }
4897         ifp = fin->fin_ifp;
4898
4899         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
4900                 switch (fin->fin_p)
4901                 {
4902                 case IPPROTO_TCP :
4903                         nflags = IPN_TCP;
4904                         break;
4905                 case IPPROTO_UDP :
4906                         nflags = IPN_UDP;
4907                         break;
4908                 case IPPROTO_ICMP :
4909                         icmp = fin->fin_dp;
4910
4911                         /*
4912                          * This is an incoming packet, so the destination is
4913                          * the icmp_id and the source port equals 0
4914                          */
4915                         if ((fin->fin_flx & FI_ICMPQUERY) != 0)
4916                                 nflags = IPN_ICMPQUERY;
4917                         break;
4918                 default :
4919                         break;
4920                 }
4921
4922                 if ((nflags & IPN_TCPUDP))
4923                         tcp = fin->fin_dp;
4924         }
4925
4926         ipa = fin->fin_saddr;
4927
4928         READ_ENTER(&softc->ipf_nat);
4929
4930         if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
4931             (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
4932                 /*EMPTY*/;
4933         else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
4934                 natadd = 0;
4935         else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH,
4936                                       (u_int)fin->fin_p, fin->fin_src,
4937                                       fin->fin_dst))) {
4938                 nflags = nat->nat_flags;
4939         } else if (fin->fin_off == 0) {
4940                 u_32_t hv, msk, nmsk = 0;
4941
4942                 /*
4943                  * If there is no current entry in the nat table for this IP#,
4944                  * create one for it (if there is a matching rule).
4945                  */
4946 maskloop:
4947                 msk = softn->ipf_nat_map_active_masks[nmsk];
4948                 iph = ipa & msk;
4949                 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz);
4950 retry_roundrobin:
4951                 for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) {
4952                         npnext = np->in_mnext;
4953                         if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
4954                                 continue;
4955                         if (np->in_v[0] != 4)
4956                                 continue;
4957                         if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
4958                                 continue;
4959                         if ((np->in_flags & IPN_RF) &&
4960                             !(np->in_flags & nflags))
4961                                 continue;
4962                         if (np->in_flags & IPN_FILTER) {
4963                                 switch (ipf_nat_match(fin, np))
4964                                 {
4965                                 case 0 :
4966                                         continue;
4967                                 case -1 :
4968                                         rval = -1;
4969                                         goto outmatchfail;
4970                                 case 1 :
4971                                 default :
4972                                         break;
4973                                 }
4974                         } else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr)
4975                                 continue;
4976
4977                         if ((fr != NULL) &&
4978                             !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
4979                                 continue;
4980
4981                         if (np->in_plabel != -1) {
4982                                 if (((np->in_flags & IPN_FILTER) == 0) &&
4983                                     (np->in_odport != fin->fin_data[1]))
4984                                         continue;
4985                                 if (ipf_proxy_ok(fin, tcp, np) == 0)
4986                                         continue;
4987                         }
4988
4989                         if (np->in_flags & IPN_NO) {
4990                                 np->in_hits++;
4991                                 break;
4992                         }
4993                         MUTEX_ENTER(&softn->ipf_nat_new);
4994                         /*
4995                          * If we've matched a round-robin rule but it has
4996                          * moved in the list since we got it, start over as
4997                          * this is now no longer correct.
4998                          */
4999                         if (npnext != np->in_mnext) {
5000                                 if ((np->in_flags & IPN_ROUNDR) != 0) {
5001                                         MUTEX_EXIT(&softn->ipf_nat_new);
5002                                         goto retry_roundrobin;
5003                                 }
5004                                 npnext = np->in_mnext;
5005                         }
5006
5007                         nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND);
5008                         MUTEX_EXIT(&softn->ipf_nat_new);
5009                         if (nat != NULL) {
5010                                 natfailed = 0;
5011                                 break;
5012                         }
5013                         natfailed = -1;
5014                 }
5015                 if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) {
5016                         nmsk++;
5017                         goto maskloop;
5018                 }
5019         }
5020
5021         if (nat != NULL) {
5022                 rval = ipf_nat_out(fin, nat, natadd, nflags);
5023                 if (rval == 1) {
5024                         MUTEX_ENTER(&nat->nat_lock);
5025                         ipf_nat_update(fin, nat);
5026                         nat->nat_bytes[1] += fin->fin_plen;
5027                         nat->nat_pkts[1]++;
5028                         fin->fin_pktnum = nat->nat_pkts[1];
5029                         MUTEX_EXIT(&nat->nat_lock);
5030                 }
5031         } else
5032                 rval = natfailed;
5033 outmatchfail:
5034         RWLOCK_EXIT(&softc->ipf_nat);
5035
5036         switch (rval)
5037         {
5038         case -1 :
5039                 if (passp != NULL) {
5040                         DT1(frb_natv4out, fr_info_t *, fin);
5041                         NBUMPSIDED(1, ns_drop);
5042                         *passp = FR_BLOCK;
5043                         fin->fin_reason = FRB_NATV4;
5044                 }
5045                 fin->fin_flx |= FI_BADNAT;
5046                 NBUMPSIDED(1, ns_badnat);
5047                 break;
5048         case 0 :
5049                 NBUMPSIDE(1, ns_ignored);
5050                 break;
5051         case 1 :
5052                 NBUMPSIDE(1, ns_translated);
5053                 break;
5054         }
5055         fin->fin_ifp = sifp;
5056         return rval;
5057 }
5058
5059 /* ------------------------------------------------------------------------ */
5060 /* Function:    ipf_nat_out                                                 */
5061 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5062 /*                     1 == packet was successfully translated.             */
5063 /* Parameters:  fin(I)    - pointer to packet information                   */
5064 /*              nat(I)    - pointer to NAT structure                        */
5065 /*              natadd(I) - flag indicating if it is safe to add frag cache */
5066 /*              nflags(I) - NAT flags set for this packet                   */
5067 /*                                                                          */
5068 /* Translate a packet coming "out" on an interface.                         */
5069 /* ------------------------------------------------------------------------ */
5070 int
5071 ipf_nat_out(fin, nat, natadd, nflags)
5072         fr_info_t *fin;
5073         nat_t *nat;
5074         int natadd;
5075         u_32_t nflags;
5076 {
5077         ipf_main_softc_t *softc = fin->fin_main_soft;
5078         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5079         icmphdr_t *icmp;
5080         tcphdr_t *tcp;
5081         ipnat_t *np;
5082         int skip;
5083         int i;
5084
5085         tcp = NULL;
5086         icmp = NULL;
5087         np = nat->nat_ptr;
5088
5089         if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
5090                 (void) ipf_frag_natnew(softc, fin, 0, nat);
5091
5092         /*
5093          * Fix up checksums, not by recalculating them, but
5094          * simply computing adjustments.
5095          * This is only done for STREAMS based IP implementations where the
5096          * checksum has already been calculated by IP.  In all other cases,
5097          * IPFilter is called before the checksum needs calculating so there
5098          * is no call to modify whatever is in the header now.
5099          */
5100         if (nflags == IPN_ICMPERR) {
5101                 u_32_t s1, s2, sumd, msumd;
5102
5103                 s1 = LONG_SUM(ntohl(fin->fin_saddr));
5104                 if (nat->nat_dir == NAT_OUTBOUND) {
5105                         s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
5106                 } else {
5107                         s2 = LONG_SUM(ntohl(nat->nat_odstaddr));
5108                 }
5109                 CALC_SUMD(s1, s2, sumd);
5110                 msumd = sumd;
5111
5112                 s1 = LONG_SUM(ntohl(fin->fin_daddr));
5113                 if (nat->nat_dir == NAT_OUTBOUND) {
5114                         s2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
5115                 } else {
5116                         s2 = LONG_SUM(ntohl(nat->nat_osrcaddr));
5117                 }
5118                 CALC_SUMD(s1, s2, sumd);
5119                 msumd += sumd;
5120
5121                 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0);
5122         }
5123 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5124     defined(linux) || defined(BRIDGE_IPF)
5125         else {
5126                 /*
5127                  * Strictly speaking, this isn't necessary on BSD
5128                  * kernels because they do checksum calculation after
5129                  * this code has run BUT if ipfilter is being used
5130                  * to do NAT as a bridge, that code doesn't exist.
5131                  */
5132                 switch (nat->nat_dir)
5133                 {
5134                 case NAT_OUTBOUND :
5135                         ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART,
5136                                          &fin->fin_ip->ip_sum,
5137                                          nat->nat_ipsumd, 0);
5138                         break;
5139
5140                 case NAT_INBOUND :
5141                         ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART,
5142                                         &fin->fin_ip->ip_sum,
5143                                         nat->nat_ipsumd, 0);
5144                         break;
5145
5146                 default :
5147                         break;
5148                 }
5149         }
5150 #endif
5151
5152         /*
5153          * Address assignment is after the checksum modification because
5154          * we are using the address in the packet for determining the
5155          * correct checksum offset (the ICMP error could be coming from
5156          * anyone...)
5157          */
5158         switch (nat->nat_dir)
5159         {
5160         case NAT_OUTBOUND :
5161                 fin->fin_ip->ip_src = nat->nat_nsrcip;
5162                 fin->fin_saddr = nat->nat_nsrcaddr;
5163                 fin->fin_ip->ip_dst = nat->nat_ndstip;
5164                 fin->fin_daddr = nat->nat_ndstaddr;
5165                 break;
5166
5167         case NAT_INBOUND :
5168                 fin->fin_ip->ip_src = nat->nat_odstip;
5169                 fin->fin_saddr = nat->nat_ndstaddr;
5170                 fin->fin_ip->ip_dst = nat->nat_osrcip;
5171                 fin->fin_daddr = nat->nat_nsrcaddr;
5172                 break;
5173
5174         case NAT_DIVERTIN :
5175             {
5176                 mb_t *m;
5177
5178                 skip = ipf_nat_decap(fin, nat);
5179                 if (skip <= 0) {
5180                         NBUMPSIDED(1, ns_decap_fail);
5181                         return -1;
5182                 }
5183
5184                 m = fin->fin_m;
5185
5186 #if defined(MENTAT) && defined(_KERNEL)
5187                 m->b_rptr += skip;
5188 #else
5189                 m->m_data += skip;
5190                 m->m_len -= skip;
5191
5192 # ifdef M_PKTHDR
5193                 if (m->m_flags & M_PKTHDR)
5194                         m->m_pkthdr.len -= skip;
5195 # endif
5196 #endif
5197
5198                 MUTEX_ENTER(&nat->nat_lock);
5199                 ipf_nat_update(fin, nat);
5200                 MUTEX_EXIT(&nat->nat_lock);
5201                 fin->fin_flx |= FI_NATED;
5202                 if (np != NULL && np->in_tag.ipt_num[0] != 0)
5203                         fin->fin_nattag = &np->in_tag;
5204                 return 1;
5205                 /* NOTREACHED */
5206             }
5207
5208         case NAT_DIVERTOUT :
5209             {
5210                 u_32_t s1, s2, sumd;
5211                 udphdr_t *uh;
5212                 ip_t *ip;
5213                 mb_t *m;
5214
5215                 m = M_DUP(np->in_divmp);
5216                 if (m == NULL) {
5217                         NBUMPSIDED(1, ns_divert_dup);
5218                         return -1;
5219                 }
5220
5221                 ip = MTOD(m, ip_t *);
5222                 ip->ip_id = htons(ipf_nextipid(fin));
5223                 s2 = ntohs(ip->ip_id);
5224
5225                 s1 = ip->ip_len;
5226                 ip->ip_len = ntohs(ip->ip_len);
5227                 ip->ip_len += fin->fin_plen;
5228                 ip->ip_len = htons(ip->ip_len);
5229                 s2 += ntohs(ip->ip_len);
5230                 CALC_SUMD(s1, s2, sumd);
5231
5232                 uh = (udphdr_t *)(ip + 1);
5233                 uh->uh_ulen += fin->fin_plen;
5234                 uh->uh_ulen = htons(uh->uh_ulen);
5235 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5236     defined(linux) || defined(BRIDGE_IPF)
5237                 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5238 #endif
5239
5240                 PREP_MB_T(fin, m);
5241
5242                 fin->fin_src = ip->ip_src;
5243                 fin->fin_dst = ip->ip_dst;
5244                 fin->fin_ip = ip;
5245                 fin->fin_plen += sizeof(ip_t) + 8;      /* UDP + IPv4 hdr */
5246                 fin->fin_dlen += sizeof(ip_t) + 8;      /* UDP + IPv4 hdr */
5247
5248                 nflags &= ~IPN_TCPUDPICMP;
5249
5250                 break;
5251             }
5252
5253         default :
5254                 break;
5255         }
5256
5257         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5258                 u_short *csump;
5259
5260                 if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
5261                         tcp = fin->fin_dp;
5262
5263                         switch (nat->nat_dir)
5264                         {
5265                         case NAT_OUTBOUND :
5266                                 tcp->th_sport = nat->nat_nsport;
5267                                 fin->fin_data[0] = ntohs(nat->nat_nsport);
5268                                 tcp->th_dport = nat->nat_ndport;
5269                                 fin->fin_data[1] = ntohs(nat->nat_ndport);
5270                                 break;
5271
5272                         case NAT_INBOUND :
5273                                 tcp->th_sport = nat->nat_odport;
5274                                 fin->fin_data[0] = ntohs(nat->nat_odport);
5275                                 tcp->th_dport = nat->nat_osport;
5276                                 fin->fin_data[1] = ntohs(nat->nat_osport);
5277                                 break;
5278                         }
5279                 }
5280
5281                 if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
5282                         icmp = fin->fin_dp;
5283                         icmp->icmp_id = nat->nat_nicmpid;
5284                 }
5285
5286                 csump = ipf_nat_proto(fin, nat, nflags);
5287
5288                 /*
5289                  * The above comments do not hold for layer 4 (or higher)
5290                  * checksums...
5291                  */
5292                 if (csump != NULL) {
5293                         if (nat->nat_dir == NAT_OUTBOUND)
5294                                 ipf_fix_outcksum(fin->fin_cksum, csump,
5295                                                  nat->nat_sumd[0],
5296                                                  nat->nat_sumd[1] +
5297                                                  fin->fin_dlen);
5298                         else
5299                                 ipf_fix_incksum(fin->fin_cksum, csump,
5300                                                 nat->nat_sumd[0],
5301                                                 nat->nat_sumd[1] +
5302                                                 fin->fin_dlen);
5303                 }
5304         }
5305
5306         ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5307         /* ------------------------------------------------------------- */
5308         /* A few quick notes:                                            */
5309         /*      Following are test conditions prior to calling the       */
5310         /*      ipf_proxy_check routine.                                 */
5311         /*                                                               */
5312         /*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5313         /*      with a redirect rule, we attempt to match the packet's   */
5314         /*      source port against in_dport, otherwise we'd compare the */
5315         /*      packet's destination.                                    */
5316         /* ------------------------------------------------------------- */
5317         if ((np != NULL) && (np->in_apr != NULL)) {
5318                 i = ipf_proxy_check(fin, nat);
5319                 if (i == 0) {
5320                         i = 1;
5321                 } else if (i == -1) {
5322                         NBUMPSIDED(1, ns_ipf_proxy_fail);
5323                 }
5324         } else {
5325                 i = 1;
5326         }
5327         fin->fin_flx |= FI_NATED;
5328         return i;
5329 }
5330
5331
5332 /* ------------------------------------------------------------------------ */
5333 /* Function:    ipf_nat_checkin                                             */
5334 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5335 /*                     0 == no packet translation occurred,                 */
5336 /*                     1 == packet was successfully translated.             */
5337 /* Parameters:  fin(I)   - pointer to packet information                    */
5338 /*              passp(I) - pointer to filtering result flags                */
5339 /*                                                                          */
5340 /* Check to see if an incoming packet should be changed.  ICMP packets are  */
5341 /* first checked to see if they match an existing entry (if an error),      */
5342 /* otherwise a search of the current NAT table is made.  If neither results */
5343 /* in a match then a search for a matching NAT rule is made.  Create a new  */
5344 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
5345 /* packet header(s) as required.                                            */
5346 /* ------------------------------------------------------------------------ */
5347 int
5348 ipf_nat_checkin(fin, passp)
5349         fr_info_t *fin;
5350         u_32_t *passp;
5351 {
5352         ipf_main_softc_t *softc;
5353         ipf_nat_softc_t *softn;
5354         u_int nflags, natadd;
5355         ipnat_t *np, *npnext;
5356         int rval, natfailed;
5357         struct ifnet *ifp;
5358         struct in_addr in;
5359         icmphdr_t *icmp;
5360         tcphdr_t *tcp;
5361         u_short dport;
5362         nat_t *nat;
5363         u_32_t iph;
5364
5365         softc = fin->fin_main_soft;
5366         softn = softc->ipf_nat_soft;
5367
5368         if (softn->ipf_nat_lock != 0)
5369                 return 0;
5370         if (softn->ipf_nat_stats.ns_rules == 0 &&
5371             softn->ipf_nat_instances == NULL)
5372                 return 0;
5373
5374         tcp = NULL;
5375         icmp = NULL;
5376         dport = 0;
5377         natadd = 1;
5378         nflags = 0;
5379         natfailed = 0;
5380         ifp = fin->fin_ifp;
5381
5382         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5383                 switch (fin->fin_p)
5384                 {
5385                 case IPPROTO_TCP :
5386                         nflags = IPN_TCP;
5387                         break;
5388                 case IPPROTO_UDP :
5389                         nflags = IPN_UDP;
5390                         break;
5391                 case IPPROTO_ICMP :
5392                         icmp = fin->fin_dp;
5393
5394                         /*
5395                          * This is an incoming packet, so the destination is
5396                          * the icmp_id and the source port equals 0
5397                          */
5398                         if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
5399                                 nflags = IPN_ICMPQUERY;
5400                                 dport = icmp->icmp_id;
5401                         } break;
5402                 default :
5403                         break;
5404                 }
5405
5406                 if ((nflags & IPN_TCPUDP)) {
5407                         tcp = fin->fin_dp;
5408                         dport = fin->fin_data[1];
5409                 }
5410         }
5411
5412         in = fin->fin_dst;
5413
5414         READ_ENTER(&softc->ipf_nat);
5415
5416         if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
5417             (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND)))
5418                 /*EMPTY*/;
5419         else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
5420                 natadd = 0;
5421         else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH,
5422                                          (u_int)fin->fin_p,
5423                                          fin->fin_src, in))) {
5424                 nflags = nat->nat_flags;
5425         } else if (fin->fin_off == 0) {
5426                 u_32_t hv, msk, rmsk = 0;
5427
5428                 /*
5429                  * If there is no current entry in the nat table for this IP#,
5430                  * create one for it (if there is a matching rule).
5431                  */
5432 maskloop:
5433                 msk = softn->ipf_nat_rdr_active_masks[rmsk];
5434                 iph = in.s_addr & msk;
5435                 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz);
5436 retry_roundrobin:
5437                 /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */
5438                 for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) {
5439                         npnext = np->in_rnext;
5440                         if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
5441                                 continue;
5442                         if (np->in_v[0] != 4)
5443                                 continue;
5444                         if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
5445                                 continue;
5446                         if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
5447                                 continue;
5448                         if (np->in_flags & IPN_FILTER) {
5449                                 switch (ipf_nat_match(fin, np))
5450                                 {
5451                                 case 0 :
5452                                         continue;
5453                                 case -1 :
5454                                         rval = -1;
5455                                         goto inmatchfail;
5456                                 case 1 :
5457                                 default :
5458                                         break;
5459                                 }
5460                         } else {
5461                                 if ((in.s_addr & np->in_odstmsk) !=
5462                                     np->in_odstaddr)
5463                                         continue;
5464                                 if (np->in_odport &&
5465                                     ((np->in_dtop < dport) ||
5466                                      (dport < np->in_odport)))
5467                                         continue;
5468                         }
5469
5470                         if (np->in_plabel != -1) {
5471                                 if (!ipf_proxy_ok(fin, tcp, np)) {
5472                                         continue;
5473                                 }
5474                         }
5475
5476                         if (np->in_flags & IPN_NO) {
5477                                 np->in_hits++;
5478                                 break;
5479                         }
5480
5481                         MUTEX_ENTER(&softn->ipf_nat_new);
5482                         /*
5483                          * If we've matched a round-robin rule but it has
5484                          * moved in the list since we got it, start over as
5485                          * this is now no longer correct.
5486                          */
5487                         if (npnext != np->in_rnext) {
5488                                 if ((np->in_flags & IPN_ROUNDR) != 0) {
5489                                         MUTEX_EXIT(&softn->ipf_nat_new);
5490                                         goto retry_roundrobin;
5491                                 }
5492                                 npnext = np->in_rnext;
5493                         }
5494
5495                         nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND);
5496                         MUTEX_EXIT(&softn->ipf_nat_new);
5497                         if (nat != NULL) {
5498                                 natfailed = 0;
5499                                 break;
5500                         }
5501                         natfailed = -1;
5502                 }
5503                 if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) {
5504                         rmsk++;
5505                         goto maskloop;
5506                 }
5507         }
5508
5509         if (nat != NULL) {
5510                 rval = ipf_nat_in(fin, nat, natadd, nflags);
5511                 if (rval == 1) {
5512                         MUTEX_ENTER(&nat->nat_lock);
5513                         ipf_nat_update(fin, nat);
5514                         nat->nat_bytes[0] += fin->fin_plen;
5515                         nat->nat_pkts[0]++;
5516                         fin->fin_pktnum = nat->nat_pkts[0];
5517                         MUTEX_EXIT(&nat->nat_lock);
5518                 }
5519         } else
5520                 rval = natfailed;
5521 inmatchfail:
5522         RWLOCK_EXIT(&softc->ipf_nat);
5523
5524         switch (rval)
5525         {
5526         case -1 :
5527                 if (passp != NULL) {
5528                         DT1(frb_natv4in, fr_info_t *, fin);
5529                         NBUMPSIDED(0, ns_drop);
5530                         *passp = FR_BLOCK;
5531                         fin->fin_reason = FRB_NATV4;
5532                 }
5533                 fin->fin_flx |= FI_BADNAT;
5534                 NBUMPSIDED(0, ns_badnat);
5535                 break;
5536         case 0 :
5537                 NBUMPSIDE(0, ns_ignored);
5538                 break;
5539         case 1 :
5540                 NBUMPSIDE(0, ns_translated);
5541                 break;
5542         }
5543         return rval;
5544 }
5545
5546
5547 /* ------------------------------------------------------------------------ */
5548 /* Function:    ipf_nat_in                                                  */
5549 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5550 /*                     1 == packet was successfully translated.             */
5551 /* Parameters:  fin(I)    - pointer to packet information                   */
5552 /*              nat(I)    - pointer to NAT structure                        */
5553 /*              natadd(I) - flag indicating if it is safe to add frag cache */
5554 /*              nflags(I) - NAT flags set for this packet                   */
5555 /* Locks Held:  ipf_nat(READ)                                               */
5556 /*                                                                          */
5557 /* Translate a packet coming "in" on an interface.                          */
5558 /* ------------------------------------------------------------------------ */
5559 int
5560 ipf_nat_in(fin, nat, natadd, nflags)
5561         fr_info_t *fin;
5562         nat_t *nat;
5563         int natadd;
5564         u_32_t nflags;
5565 {
5566         ipf_main_softc_t *softc = fin->fin_main_soft;
5567         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5568         u_32_t sumd, ipsumd, sum1, sum2;
5569         icmphdr_t *icmp;
5570         tcphdr_t *tcp;
5571         ipnat_t *np;
5572         int skip;
5573         int i;
5574
5575         tcp = NULL;
5576         np = nat->nat_ptr;
5577         fin->fin_fr = nat->nat_fr;
5578
5579         if (np != NULL) {
5580                 if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
5581                         (void) ipf_frag_natnew(softc, fin, 0, nat);
5582
5583         /* ------------------------------------------------------------- */
5584         /* A few quick notes:                                            */
5585         /*      Following are test conditions prior to calling the       */
5586         /*      ipf_proxy_check routine.                                 */
5587         /*                                                               */
5588         /*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5589         /*      with a map rule, we attempt to match the packet's        */
5590         /*      source port against in_dport, otherwise we'd compare the */
5591         /*      packet's destination.                                    */
5592         /* ------------------------------------------------------------- */
5593                 if (np->in_apr != NULL) {
5594                         i = ipf_proxy_check(fin, nat);
5595                         if (i == -1) {
5596                                 NBUMPSIDED(0, ns_ipf_proxy_fail);
5597                                 return -1;
5598                         }
5599                 }
5600         }
5601
5602         ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5603
5604         ipsumd = nat->nat_ipsumd;
5605         /*
5606          * Fix up checksums, not by recalculating them, but
5607          * simply computing adjustments.
5608          * Why only do this for some platforms on inbound packets ?
5609          * Because for those that it is done, IP processing is yet to happen
5610          * and so the IPv4 header checksum has not yet been evaluated.
5611          * Perhaps it should always be done for the benefit of things like
5612          * fast forwarding (so that it doesn't need to be recomputed) but with
5613          * header checksum offloading, perhaps it is a moot point.
5614          */
5615
5616         switch (nat->nat_dir)
5617         {
5618         case NAT_INBOUND :
5619                 if ((fin->fin_flx & FI_ICMPERR) == 0) {
5620                         fin->fin_ip->ip_src = nat->nat_nsrcip;
5621                         fin->fin_saddr = nat->nat_nsrcaddr;
5622                 } else {
5623                         sum1 = nat->nat_osrcaddr;
5624                         sum2 = nat->nat_nsrcaddr;
5625                         CALC_SUMD(sum1, sum2, sumd);
5626                         ipsumd -= sumd;
5627                 }
5628                 fin->fin_ip->ip_dst = nat->nat_ndstip;
5629                 fin->fin_daddr = nat->nat_ndstaddr;
5630 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5631      defined(__osf__) || defined(linux)
5632                 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5633 #endif
5634                 break;
5635
5636         case NAT_OUTBOUND :
5637                 if ((fin->fin_flx & FI_ICMPERR) == 0) {
5638                         fin->fin_ip->ip_src = nat->nat_odstip;
5639                         fin->fin_saddr = nat->nat_odstaddr;
5640                 } else {
5641                         sum1 = nat->nat_odstaddr;
5642                         sum2 = nat->nat_ndstaddr;
5643                         CALC_SUMD(sum1, sum2, sumd);
5644                         ipsumd -= sumd;
5645                 }
5646                 fin->fin_ip->ip_dst = nat->nat_osrcip;
5647                 fin->fin_daddr = nat->nat_osrcaddr;
5648 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5649      defined(__osf__) || defined(linux)
5650                 ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5651 #endif
5652                 break;
5653
5654         case NAT_DIVERTIN :
5655             {
5656                 udphdr_t *uh;
5657                 ip_t *ip;
5658                 mb_t *m;
5659
5660                 m = M_DUP(np->in_divmp);
5661                 if (m == NULL) {
5662                         NBUMPSIDED(0, ns_divert_dup);
5663                         return -1;
5664                 }
5665
5666                 ip = MTOD(m, ip_t *);
5667                 ip->ip_id = htons(ipf_nextipid(fin));
5668                 sum1 = ntohs(ip->ip_len);
5669                 ip->ip_len = ntohs(ip->ip_len);
5670                 ip->ip_len += fin->fin_plen;
5671                 ip->ip_len = htons(ip->ip_len);
5672
5673                 uh = (udphdr_t *)(ip + 1);
5674                 uh->uh_ulen += fin->fin_plen;
5675                 uh->uh_ulen = htons(uh->uh_ulen);
5676
5677                 sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len);
5678                 sum2 += ntohs(ip->ip_off) & IP_DF;
5679                 CALC_SUMD(sum1, sum2, sumd);
5680
5681 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5682      defined(__osf__) || defined(linux)
5683                 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5684 #endif
5685                 PREP_MB_T(fin, m);
5686
5687                 fin->fin_ip = ip;
5688                 fin->fin_plen += sizeof(ip_t) + 8;      /* UDP + new IPv4 hdr */
5689                 fin->fin_dlen += sizeof(ip_t) + 8;      /* UDP + old IPv4 hdr */
5690
5691                 nflags &= ~IPN_TCPUDPICMP;
5692
5693                 break;
5694             }
5695
5696         case NAT_DIVERTOUT :
5697             {
5698                 mb_t *m;
5699
5700                 skip = ipf_nat_decap(fin, nat);
5701                 if (skip <= 0) {
5702                         NBUMPSIDED(0, ns_decap_fail);
5703                         return -1;
5704                 }
5705
5706                 m = fin->fin_m;
5707
5708 #if defined(MENTAT) && defined(_KERNEL)
5709                 m->b_rptr += skip;
5710 #else
5711                 m->m_data += skip;
5712                 m->m_len -= skip;
5713
5714 # ifdef M_PKTHDR
5715                 if (m->m_flags & M_PKTHDR)
5716                         m->m_pkthdr.len -= skip;
5717 # endif
5718 #endif
5719
5720                 ipf_nat_update(fin, nat);
5721                 nflags &= ~IPN_TCPUDPICMP;
5722                 fin->fin_flx |= FI_NATED;
5723                 if (np != NULL && np->in_tag.ipt_num[0] != 0)
5724                         fin->fin_nattag = &np->in_tag;
5725                 return 1;
5726                 /* NOTREACHED */
5727             }
5728         }
5729         if (nflags & IPN_TCPUDP)
5730                 tcp = fin->fin_dp;
5731
5732         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5733                 u_short *csump;
5734
5735                 if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
5736                         switch (nat->nat_dir)
5737                         {
5738                         case NAT_INBOUND :
5739                                 tcp->th_sport = nat->nat_nsport;
5740                                 fin->fin_data[0] = ntohs(nat->nat_nsport);
5741                                 tcp->th_dport = nat->nat_ndport;
5742                                 fin->fin_data[1] = ntohs(nat->nat_ndport);
5743                                 break;
5744
5745                         case NAT_OUTBOUND :
5746                                 tcp->th_sport = nat->nat_odport;
5747                                 fin->fin_data[0] = ntohs(nat->nat_odport);
5748                                 tcp->th_dport = nat->nat_osport;
5749                                 fin->fin_data[1] = ntohs(nat->nat_osport);
5750                                 break;
5751                         }
5752                 }
5753
5754
5755                 if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
5756                         icmp = fin->fin_dp;
5757
5758                         icmp->icmp_id = nat->nat_nicmpid;
5759                 }
5760
5761                 csump = ipf_nat_proto(fin, nat, nflags);
5762
5763                 /*
5764                  * The above comments do not hold for layer 4 (or higher)
5765                  * checksums...
5766                  */
5767                 if (csump != NULL) {
5768                         if (nat->nat_dir == NAT_OUTBOUND)
5769                                 ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
5770                         else
5771                                 ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
5772                 }
5773         }
5774
5775         fin->fin_flx |= FI_NATED;
5776         if (np != NULL && np->in_tag.ipt_num[0] != 0)
5777                 fin->fin_nattag = &np->in_tag;
5778         return 1;
5779 }
5780
5781
5782 /* ------------------------------------------------------------------------ */
5783 /* Function:    ipf_nat_proto                                               */
5784 /* Returns:     u_short* - pointer to transport header checksum to update,  */
5785 /*                         NULL if the transport protocol is not recognised */
5786 /*                         as needing a checksum update.                    */
5787 /* Parameters:  fin(I)    - pointer to packet information                   */
5788 /*              nat(I)    - pointer to NAT structure                        */
5789 /*              nflags(I) - NAT flags set for this packet                   */
5790 /*                                                                          */
5791 /* Return the pointer to the checksum field for each protocol so understood.*/
5792 /* If support for making other changes to a protocol header is required,    */
5793 /* that is not strictly 'address' translation, such as clamping the MSS in  */
5794 /* TCP down to a specific value, then do it from here.                      */
5795 /* ------------------------------------------------------------------------ */
5796 u_short *
5797 ipf_nat_proto(fin, nat, nflags)
5798         fr_info_t *fin;
5799         nat_t *nat;
5800         u_int nflags;
5801 {
5802         icmphdr_t *icmp;
5803         u_short *csump;
5804         tcphdr_t *tcp;
5805         udphdr_t *udp;
5806
5807         csump = NULL;
5808         if (fin->fin_out == 0) {
5809                 fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND);
5810         } else {
5811                 fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0);
5812         }
5813
5814         switch (fin->fin_p)
5815         {
5816         case IPPROTO_TCP :
5817                 tcp = fin->fin_dp;
5818
5819                 if ((nflags & IPN_TCP) != 0)
5820                         csump = &tcp->th_sum;
5821
5822                 /*
5823                  * Do a MSS CLAMPING on a SYN packet,
5824                  * only deal IPv4 for now.
5825                  */
5826                 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
5827                         ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
5828
5829                 break;
5830
5831         case IPPROTO_UDP :
5832                 udp = fin->fin_dp;
5833
5834                 if ((nflags & IPN_UDP) != 0) {
5835                         if (udp->uh_sum != 0)
5836                                 csump = &udp->uh_sum;
5837                 }
5838                 break;
5839
5840         case IPPROTO_ICMP :
5841                 icmp = fin->fin_dp;
5842
5843                 if ((nflags & IPN_ICMPQUERY) != 0) {
5844                         if (icmp->icmp_cksum != 0)
5845                                 csump = &icmp->icmp_cksum;
5846                 }
5847                 break;
5848
5849 #ifdef USE_INET6
5850         case IPPROTO_ICMPV6 :
5851             {
5852                 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp;
5853
5854                 icmp6 = fin->fin_dp;
5855
5856                 if ((nflags & IPN_ICMPQUERY) != 0) {
5857                         if (icmp6->icmp6_cksum != 0)
5858                                 csump = &icmp6->icmp6_cksum;
5859                 }
5860                 break;
5861             }
5862 #endif
5863         }
5864         return csump;
5865 }
5866
5867
5868 /* ------------------------------------------------------------------------ */
5869 /* Function:    ipf_nat_expire                                              */
5870 /* Returns:     Nil                                                         */
5871 /* Parameters:  softc(I) - pointer to soft context main structure           */
5872 /*                                                                          */
5873 /* Check all of the timeout queues for entries at the top which need to be  */
5874 /* expired.                                                                 */
5875 /* ------------------------------------------------------------------------ */
5876 void
5877 ipf_nat_expire(softc)
5878         ipf_main_softc_t *softc;
5879 {
5880         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5881         ipftq_t *ifq, *ifqnext;
5882         ipftqent_t *tqe, *tqn;
5883         int i;
5884         SPL_INT(s);
5885
5886         SPL_NET(s);
5887         WRITE_ENTER(&softc->ipf_nat);
5888         for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL;
5889              ifq = ifq->ifq_next) {
5890                 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5891                         if (tqe->tqe_die > softc->ipf_ticks)
5892                                 break;
5893                         tqn = tqe->tqe_next;
5894                         ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5895                 }
5896         }
5897
5898         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) {
5899                 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5900                         if (tqe->tqe_die > softc->ipf_ticks)
5901                                 break;
5902                         tqn = tqe->tqe_next;
5903                         ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5904                 }
5905         }
5906
5907         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
5908                 ifqnext = ifq->ifq_next;
5909
5910                 if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
5911                     (ifq->ifq_ref == 0)) {
5912                         ipf_freetimeoutqueue(softc, ifq);
5913                 }
5914         }
5915
5916         if (softn->ipf_nat_doflush != 0) {
5917                 ipf_nat_extraflush(softc, softn, 2);
5918                 softn->ipf_nat_doflush = 0;
5919         }
5920
5921         RWLOCK_EXIT(&softc->ipf_nat);
5922         SPL_X(s);
5923 }
5924
5925
5926 /* ------------------------------------------------------------------------ */
5927 /* Function:    ipf_nat_sync                                                */
5928 /* Returns:     Nil                                                         */
5929 /* Parameters:  softc(I) - pointer to soft context main structure           */
5930 /*              ifp(I) - pointer to network interface                       */
5931 /*                                                                          */
5932 /* Walk through all of the currently active NAT sessions, looking for those */
5933 /* which need to have their translated address updated.                     */
5934 /* ------------------------------------------------------------------------ */
5935 void
5936 ipf_nat_sync(softc, ifp)
5937         ipf_main_softc_t *softc;
5938         void *ifp;
5939 {
5940         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5941         u_32_t sum1, sum2, sumd;
5942         i6addr_t in;
5943         ipnat_t *n;
5944         nat_t *nat;
5945         void *ifp2;
5946         int idx;
5947         SPL_INT(s);
5948
5949         if (softc->ipf_running <= 0)
5950                 return;
5951
5952         /*
5953          * Change IP addresses for NAT sessions for any protocol except TCP
5954          * since it will break the TCP connection anyway.  The only rules
5955          * which will get changed are those which are "map ... -> 0/32",
5956          * where the rule specifies the address is taken from the interface.
5957          */
5958         SPL_NET(s);
5959         WRITE_ENTER(&softc->ipf_nat);
5960
5961         if (softc->ipf_running <= 0) {
5962                 RWLOCK_EXIT(&softc->ipf_nat);
5963                 return;
5964         }
5965
5966         for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
5967                 if ((nat->nat_flags & IPN_TCP) != 0)
5968                         continue;
5969
5970                 n = nat->nat_ptr;
5971                 if (n != NULL) {
5972                         if (n->in_v[1] == 4) {
5973                                 if (n->in_redir & NAT_MAP) {
5974                                         if ((n->in_nsrcaddr != 0) ||
5975                                             (n->in_nsrcmsk != 0xffffffff))
5976                                                 continue;
5977                                 } else if (n->in_redir & NAT_REDIRECT) {
5978                                         if ((n->in_ndstaddr != 0) ||
5979                                             (n->in_ndstmsk != 0xffffffff))
5980                                                 continue;
5981                                 }
5982                         }
5983 #ifdef USE_INET6
5984                         if (n->in_v[1] == 4) {
5985                                 if (n->in_redir & NAT_MAP) {
5986                                         if (!IP6_ISZERO(&n->in_nsrcaddr) ||
5987                                             !IP6_ISONES(&n->in_nsrcmsk))
5988                                                 continue;
5989                                 } else if (n->in_redir & NAT_REDIRECT) {
5990                                         if (!IP6_ISZERO(&n->in_ndstaddr) ||
5991                                             !IP6_ISONES(&n->in_ndstmsk))
5992                                                 continue;
5993                                 }
5994                         }
5995 #endif
5996                 }
5997
5998                 if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) ||
5999                      (ifp == nat->nat_ifps[1]))) {
6000                         nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0],
6001                                                   nat->nat_v[0]);
6002                         if ((nat->nat_ifps[0] != NULL) &&
6003                             (nat->nat_ifps[0] != (void *)-1)) {
6004                                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
6005                         }
6006                         if (nat->nat_ifnames[1][0] != '\0') {
6007                                 nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1],
6008                                                           nat->nat_v[1]);
6009                         } else {
6010                                 nat->nat_ifps[1] = nat->nat_ifps[0];
6011                         }
6012                         if ((nat->nat_ifps[1] != NULL) &&
6013                             (nat->nat_ifps[1] != (void *)-1)) {
6014                                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
6015                         }
6016                         ifp2 = nat->nat_ifps[0];
6017                         if (ifp2 == NULL)
6018                                 continue;
6019
6020                         /*
6021                          * Change the map-to address to be the same as the
6022                          * new one.
6023                          */
6024                         sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6025                         if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2,
6026                                        &in, NULL) != -1) {
6027                                 if (nat->nat_v[0] == 4)
6028                                         nat->nat_nsrcip = in.in4;
6029                         }
6030                         sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6031
6032                         if (sum1 == sum2)
6033                                 continue;
6034                         /*
6035                          * Readjust the checksum adjustment to take into
6036                          * account the new IP#.
6037                          */
6038                         CALC_SUMD(sum1, sum2, sumd);
6039                         /* XXX - dont change for TCP when solaris does
6040                          * hardware checksumming.
6041                          */
6042                         sumd += nat->nat_sumd[0];
6043                         nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
6044                         nat->nat_sumd[1] = nat->nat_sumd[0];
6045                 }
6046         }
6047
6048         for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) {
6049                 char *base = n->in_names;
6050
6051                 if ((ifp == NULL) || (n->in_ifps[0] == ifp))
6052                         n->in_ifps[0] = ipf_resolvenic(softc,
6053                                                        base + n->in_ifnames[0],
6054                                                        n->in_v[0]);
6055                 if ((ifp == NULL) || (n->in_ifps[1] == ifp))
6056                         n->in_ifps[1] = ipf_resolvenic(softc,
6057                                                        base + n->in_ifnames[1],
6058                                                        n->in_v[1]);
6059
6060                 if (n->in_redir & NAT_REDIRECT)
6061                         idx = 1;
6062                 else
6063                         idx = 0;
6064
6065                 if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) &&
6066                     (n->in_ifps[idx] != NULL &&
6067                      n->in_ifps[idx] != (void *)-1)) {
6068
6069                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc,
6070                                              0, n->in_ifps[idx]);
6071                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst,
6072                                              0, n->in_ifps[idx]);
6073                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc,
6074                                              0, n->in_ifps[idx]);
6075                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst,
6076                                              0, n->in_ifps[idx]);
6077                 }
6078         }
6079         RWLOCK_EXIT(&softc->ipf_nat);
6080         SPL_X(s);
6081 }
6082
6083
6084 /* ------------------------------------------------------------------------ */
6085 /* Function:    ipf_nat_icmpquerytype                                       */
6086 /* Returns:     int - 1 == success, 0 == failure                            */
6087 /* Parameters:  icmptype(I) - ICMP type number                              */
6088 /*                                                                          */
6089 /* Tests to see if the ICMP type number passed is a query/response type or  */
6090 /* not.                                                                     */
6091 /* ------------------------------------------------------------------------ */
6092 static int
6093 ipf_nat_icmpquerytype(icmptype)
6094         int icmptype;
6095 {
6096
6097         /*
6098          * For the ICMP query NAT code, it is essential that both the query
6099          * and the reply match on the NAT rule. Because the NAT structure
6100          * does not keep track of the icmptype, and a single NAT structure
6101          * is used for all icmp types with the same src, dest and id, we
6102          * simply define the replies as queries as well. The funny thing is,
6103          * altough it seems silly to call a reply a query, this is exactly
6104          * as it is defined in the IPv4 specification
6105          */
6106         switch (icmptype)
6107         {
6108         case ICMP_ECHOREPLY:
6109         case ICMP_ECHO:
6110         /* route aedvertisement/solliciation is currently unsupported: */
6111         /* it would require rewriting the ICMP data section            */
6112         case ICMP_TSTAMP:
6113         case ICMP_TSTAMPREPLY:
6114         case ICMP_IREQ:
6115         case ICMP_IREQREPLY:
6116         case ICMP_MASKREQ:
6117         case ICMP_MASKREPLY:
6118                 return 1;
6119         default:
6120                 return 0;
6121         }
6122 }
6123
6124
6125 /* ------------------------------------------------------------------------ */
6126 /* Function:    nat_log                                                     */
6127 /* Returns:     Nil                                                         */
6128 /* Parameters:  softc(I) - pointer to soft context main structure           */
6129 /*              softn(I) - pointer to NAT context structure                 */
6130 /*              nat(I)    - pointer to NAT structure                        */
6131 /*              action(I) - action related to NAT structure being performed */
6132 /*                                                                          */
6133 /* Creates a NAT log entry.                                                 */
6134 /* ------------------------------------------------------------------------ */
6135 void
6136 ipf_nat_log(softc, softn, nat, action)
6137         ipf_main_softc_t *softc;
6138         ipf_nat_softc_t *softn;
6139         struct nat *nat;
6140         u_int action;
6141 {
6142 #ifdef  IPFILTER_LOG
6143 # ifndef LARGE_NAT
6144         struct ipnat *np;
6145         int rulen;
6146 # endif
6147         struct natlog natl;
6148         void *items[1];
6149         size_t sizes[1];
6150         int types[1];
6151
6152         bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip,
6153               sizeof(natl.nl_osrcip));
6154         bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip,
6155               sizeof(natl.nl_nsrcip));
6156         bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip,
6157               sizeof(natl.nl_odstip));
6158         bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip,
6159               sizeof(natl.nl_ndstip));
6160
6161         natl.nl_bytes[0] = nat->nat_bytes[0];
6162         natl.nl_bytes[1] = nat->nat_bytes[1];
6163         natl.nl_pkts[0] = nat->nat_pkts[0];
6164         natl.nl_pkts[1] = nat->nat_pkts[1];
6165         natl.nl_odstport = nat->nat_odport;
6166         natl.nl_osrcport = nat->nat_osport;
6167         natl.nl_nsrcport = nat->nat_nsport;
6168         natl.nl_ndstport = nat->nat_ndport;
6169         natl.nl_p[0] = nat->nat_pr[0];
6170         natl.nl_p[1] = nat->nat_pr[1];
6171         natl.nl_v[0] = nat->nat_v[0];
6172         natl.nl_v[1] = nat->nat_v[1];
6173         natl.nl_type = nat->nat_redir;
6174         natl.nl_action = action;
6175         natl.nl_rule = -1;
6176
6177         bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0],
6178               sizeof(nat->nat_ifnames[0]));
6179         bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1],
6180               sizeof(nat->nat_ifnames[1]));
6181
6182 # ifndef LARGE_NAT
6183         if (nat->nat_ptr != NULL) {
6184                 for (rulen = 0, np = softn->ipf_nat_list; np != NULL;
6185                      np = np->in_next, rulen++)
6186                         if (np == nat->nat_ptr) {
6187                                 natl.nl_rule = rulen;
6188                                 break;
6189                         }
6190         }
6191 # endif
6192         items[0] = &natl;
6193         sizes[0] = sizeof(natl);
6194         types[0] = 0;
6195
6196         (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1);
6197 #endif
6198 }
6199
6200
6201 #if defined(__OpenBSD__)
6202 /* ------------------------------------------------------------------------ */
6203 /* Function:    ipf_nat_ifdetach                                            */
6204 /* Returns:     Nil                                                         */
6205 /* Parameters:  ifp(I) - pointer to network interface                       */
6206 /*                                                                          */
6207 /* Compatibility interface for OpenBSD to trigger the correct updating of   */
6208 /* interface references within IPFilter.                                    */
6209 /* ------------------------------------------------------------------------ */
6210 void
6211 ipf_nat_ifdetach(ifp)
6212         void *ifp;
6213 {
6214         ipf_main_softc_t *softc;
6215
6216         softc = ipf_get_softc(0);
6217
6218         ipf_sync(ifp);
6219         return;
6220 }
6221 #endif
6222
6223
6224 /* ------------------------------------------------------------------------ */
6225 /* Function:    ipf_nat_rule_deref                                          */
6226 /* Returns:     Nil                                                         */
6227 /* Parameters:  softc(I) - pointer to soft context main structure           */
6228 /*              inp(I)   - pointer to pointer to NAT rule                   */
6229 /* Write Locks: ipf_nat                                                     */
6230 /*                                                                          */
6231 /* Dropping the refernce count for a rule means that whatever held the      */
6232 /* pointer to this rule (*inp) is no longer interested in it and when the   */
6233 /* reference count drops to zero, any resources allocated for the rule can  */
6234 /* be released and the rule itself free'd.                                  */
6235 /* ------------------------------------------------------------------------ */
6236 void
6237 ipf_nat_rule_deref(softc, inp)
6238         ipf_main_softc_t *softc;
6239         ipnat_t **inp;
6240 {
6241         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6242         ipnat_t *n;
6243
6244         n = *inp;
6245         *inp = NULL;
6246         n->in_use--;
6247         if (n->in_use > 0)
6248                 return;
6249
6250         if (n->in_apr != NULL)
6251                 ipf_proxy_deref(n->in_apr);
6252
6253         ipf_nat_rule_fini(softc, n);
6254
6255         if (n->in_redir & NAT_REDIRECT) {
6256                 if ((n->in_flags & IPN_PROXYRULE) == 0) {
6257                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr);
6258                 }
6259         }
6260         if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
6261                 if ((n->in_flags & IPN_PROXYRULE) == 0) {
6262                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map);
6263                 }
6264         }
6265
6266         if (n->in_tqehead[0] != NULL) {
6267                 if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
6268                         ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6269                 }
6270         }
6271
6272         if (n->in_tqehead[1] != NULL) {
6273                 if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
6274                         ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6275                 }
6276         }
6277
6278         if ((n->in_flags & IPN_PROXYRULE) == 0) {
6279                 ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules);
6280         }
6281
6282         MUTEX_DESTROY(&n->in_lock);
6283
6284         KFREES(n, n->in_size);
6285
6286 #if SOLARIS && !defined(INSTANCES)
6287         if (softn->ipf_nat_stats.ns_rules == 0)
6288                 pfil_delayed_copy = 1;
6289 #endif
6290 }
6291
6292
6293 /* ------------------------------------------------------------------------ */
6294 /* Function:    ipf_nat_deref                                               */
6295 /* Returns:     Nil                                                         */
6296 /* Parameters:  softc(I) - pointer to soft context main structure           */
6297 /*              natp(I)  - pointer to pointer to NAT table entry            */
6298 /*                                                                          */
6299 /* Decrement the reference counter for this NAT table entry and free it if  */
6300 /* there are no more things using it.                                       */
6301 /*                                                                          */
6302 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */
6303 /* structure *because* it only gets called on paths _after_ nat_ref has been*/
6304 /* incremented.  If nat_ref == 1 then we shouldn't decrement it here        */
6305 /* because nat_delete() will do that and send nat_ref to -1.                */
6306 /*                                                                          */
6307 /* Holding the lock on nat_lock is required to serialise nat_delete() being */
6308 /* called from a NAT flush ioctl with a deref happening because of a packet.*/
6309 /* ------------------------------------------------------------------------ */
6310 void
6311 ipf_nat_deref(softc, natp)
6312         ipf_main_softc_t *softc;
6313         nat_t **natp;
6314 {
6315         nat_t *nat;
6316
6317         nat = *natp;
6318         *natp = NULL;
6319
6320         MUTEX_ENTER(&nat->nat_lock);
6321         if (nat->nat_ref > 1) {
6322                 nat->nat_ref--;
6323                 ASSERT(nat->nat_ref >= 0);
6324                 MUTEX_EXIT(&nat->nat_lock);
6325                 return;
6326         }
6327         MUTEX_EXIT(&nat->nat_lock);
6328
6329         WRITE_ENTER(&softc->ipf_nat);
6330         ipf_nat_delete(softc, nat, NL_EXPIRE);
6331         RWLOCK_EXIT(&softc->ipf_nat);
6332 }
6333
6334
6335 /* ------------------------------------------------------------------------ */
6336 /* Function:    ipf_nat_clone                                               */
6337 /* Returns:     ipstate_t* - NULL == cloning failed,                        */
6338 /*                           else pointer to new state structure            */
6339 /* Parameters:  fin(I) - pointer to packet information                      */
6340 /*              is(I)  - pointer to master state structure                  */
6341 /* Write Lock:  ipf_nat                                                     */
6342 /*                                                                          */
6343 /* Create a "duplcate" state table entry from the master.                   */
6344 /* ------------------------------------------------------------------------ */
6345 nat_t *
6346 ipf_nat_clone(fin, nat)
6347         fr_info_t *fin;
6348         nat_t *nat;
6349 {
6350         ipf_main_softc_t *softc = fin->fin_main_soft;
6351         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6352         frentry_t *fr;
6353         nat_t *clone;
6354         ipnat_t *np;
6355
6356         KMALLOC(clone, nat_t *);
6357         if (clone == NULL) {
6358                 NBUMPSIDED(fin->fin_out, ns_clone_nomem);
6359                 return NULL;
6360         }
6361         bcopy((char *)nat, (char *)clone, sizeof(*clone));
6362
6363         MUTEX_NUKE(&clone->nat_lock);
6364
6365         clone->nat_rev = fin->fin_rev;
6366         clone->nat_aps = NULL;
6367         /*
6368          * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
6369          */
6370         clone->nat_tqe.tqe_pnext = NULL;
6371         clone->nat_tqe.tqe_next = NULL;
6372         clone->nat_tqe.tqe_ifq = NULL;
6373         clone->nat_tqe.tqe_parent = clone;
6374
6375         clone->nat_flags &= ~SI_CLONE;
6376         clone->nat_flags |= SI_CLONED;
6377
6378         if (clone->nat_hm)
6379                 clone->nat_hm->hm_ref++;
6380
6381         if (ipf_nat_insert(softc, softn, clone) == -1) {
6382                 KFREE(clone);
6383                 NBUMPSIDED(fin->fin_out, ns_insert_fail);
6384                 return NULL;
6385         }
6386
6387         np = clone->nat_ptr;
6388         if (np != NULL) {
6389                 if (softn->ipf_nat_logging)
6390                         ipf_nat_log(softc, softn, clone, NL_CLONE);
6391                 np->in_use++;
6392         }
6393         fr = clone->nat_fr;
6394         if (fr != NULL) {
6395                 MUTEX_ENTER(&fr->fr_lock);
6396                 fr->fr_ref++;
6397                 MUTEX_EXIT(&fr->fr_lock);
6398         }
6399
6400
6401         /*
6402          * Because the clone is created outside the normal loop of things and
6403          * TCP has special needs in terms of state, initialise the timeout
6404          * state of the new NAT from here.
6405          */
6406         if (clone->nat_pr[0] == IPPROTO_TCP) {
6407                 (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq,
6408                                    clone->nat_flags, 2);
6409         }
6410         clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone);
6411         if (softn->ipf_nat_logging)
6412                 ipf_nat_log(softc, softn, clone, NL_CLONE);
6413         return clone;
6414 }
6415
6416
6417 /* ------------------------------------------------------------------------ */
6418 /* Function:   ipf_nat_wildok                                               */
6419 /* Returns:    int - 1 == packet's ports match wildcards                    */
6420 /*                   0 == packet's ports don't match wildcards              */
6421 /* Parameters: nat(I)   - NAT entry                                         */
6422 /*             sport(I) - source port                                       */
6423 /*             dport(I) - destination port                                  */
6424 /*             flags(I) - wildcard flags                                    */
6425 /*             dir(I)   - packet direction                                  */
6426 /*                                                                          */
6427 /* Use NAT entry and packet direction to determine which combination of     */
6428 /* wildcard flags should be used.                                           */
6429 /* ------------------------------------------------------------------------ */
6430 int
6431 ipf_nat_wildok(nat, sport, dport, flags, dir)
6432         nat_t *nat;
6433         int sport, dport, flags, dir;
6434 {
6435         /*
6436          * When called by       dir is set to
6437          * nat_inlookup         NAT_INBOUND (0)
6438          * nat_outlookup        NAT_OUTBOUND (1)
6439          *
6440          * We simply combine the packet's direction in dir with the original
6441          * "intended" direction of that NAT entry in nat->nat_dir to decide
6442          * which combination of wildcard flags to allow.
6443          */
6444         switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)))
6445         {
6446         case 3: /* outbound packet / outbound entry */
6447                 if (((nat->nat_osport == sport) ||
6448                     (flags & SI_W_SPORT)) &&
6449                     ((nat->nat_odport == dport) ||
6450                     (flags & SI_W_DPORT)))
6451                         return 1;
6452                 break;
6453         case 2: /* outbound packet / inbound entry */
6454                 if (((nat->nat_osport == dport) ||
6455                     (flags & SI_W_SPORT)) &&
6456                     ((nat->nat_odport == sport) ||
6457                     (flags & SI_W_DPORT)))
6458                         return 1;
6459                 break;
6460         case 1: /* inbound packet / outbound entry */
6461                 if (((nat->nat_osport == dport) ||
6462                     (flags & SI_W_SPORT)) &&
6463                     ((nat->nat_odport == sport) ||
6464                     (flags & SI_W_DPORT)))
6465                         return 1;
6466                 break;
6467         case 0: /* inbound packet / inbound entry */
6468                 if (((nat->nat_osport == sport) ||
6469                     (flags & SI_W_SPORT)) &&
6470                     ((nat->nat_odport == dport) ||
6471                     (flags & SI_W_DPORT)))
6472                         return 1;
6473                 break;
6474         default:
6475                 break;
6476         }
6477
6478         return(0);
6479 }
6480
6481
6482 /* ------------------------------------------------------------------------ */
6483 /* Function:    nat_mssclamp                                                */
6484 /* Returns:     Nil                                                         */
6485 /* Parameters:  tcp(I)    - pointer to TCP header                           */
6486 /*              maxmss(I) - value to clamp the TCP MSS to                   */
6487 /*              fin(I)    - pointer to packet information                   */
6488 /*              csump(I)  - pointer to TCP checksum                         */
6489 /*                                                                          */
6490 /* Check for MSS option and clamp it if necessary.  If found and changed,   */
6491 /* then the TCP header checksum will be updated to reflect the change in    */
6492 /* the MSS.                                                                 */
6493 /* ------------------------------------------------------------------------ */
6494 static void
6495 ipf_nat_mssclamp(tcp, maxmss, fin, csump)
6496         tcphdr_t *tcp;
6497         u_32_t maxmss;
6498         fr_info_t *fin;
6499         u_short *csump;
6500 {
6501         u_char *cp, *ep, opt;
6502         int hlen, advance;
6503         u_32_t mss, sumd;
6504
6505         hlen = TCP_OFF(tcp) << 2;
6506         if (hlen > sizeof(*tcp)) {
6507                 cp = (u_char *)tcp + sizeof(*tcp);
6508                 ep = (u_char *)tcp + hlen;
6509
6510                 while (cp < ep) {
6511                         opt = cp[0];
6512                         if (opt == TCPOPT_EOL)
6513                                 break;
6514                         else if (opt == TCPOPT_NOP) {
6515                                 cp++;
6516                                 continue;
6517                         }
6518
6519                         if (cp + 1 >= ep)
6520                                 break;
6521                         advance = cp[1];
6522                         if ((cp + advance > ep) || (advance <= 0))
6523                                 break;
6524                         switch (opt)
6525                         {
6526                         case TCPOPT_MAXSEG:
6527                                 if (advance != 4)
6528                                         break;
6529                                 mss = cp[2] * 256 + cp[3];
6530                                 if (mss > maxmss) {
6531                                         cp[2] = maxmss / 256;
6532                                         cp[3] = maxmss & 0xff;
6533                                         CALC_SUMD(mss, maxmss, sumd);
6534                                         ipf_fix_outcksum(0, csump, sumd, 0);
6535                                 }
6536                                 break;
6537                         default:
6538                                 /* ignore unknown options */
6539                                 break;
6540                         }
6541
6542                         cp += advance;
6543                 }
6544         }
6545 }
6546
6547
6548 /* ------------------------------------------------------------------------ */
6549 /* Function:    ipf_nat_setqueue                                            */
6550 /* Returns:     Nil                                                         */
6551 /* Parameters:  softc(I) - pointer to soft context main structure           */
6552 /*              softn(I) - pointer to NAT context structure                 */
6553 /*              nat(I)- pointer to NAT structure                            */
6554 /* Locks:       ipf_nat (read or write)                                     */
6555 /*                                                                          */
6556 /* Put the NAT entry on its default queue entry, using rev as a helped in   */
6557 /* determining which queue it should be placed on.                          */
6558 /* ------------------------------------------------------------------------ */
6559 void
6560 ipf_nat_setqueue(softc, softn, nat)
6561         ipf_main_softc_t *softc;
6562         ipf_nat_softc_t *softn;
6563         nat_t *nat;
6564 {
6565         ipftq_t *oifq, *nifq;
6566         int rev = nat->nat_rev;
6567
6568         if (nat->nat_ptr != NULL)
6569                 nifq = nat->nat_ptr->in_tqehead[rev];
6570         else
6571                 nifq = NULL;
6572
6573         if (nifq == NULL) {
6574                 switch (nat->nat_pr[0])
6575                 {
6576                 case IPPROTO_UDP :
6577                         nifq = &softn->ipf_nat_udptq;
6578                         break;
6579                 case IPPROTO_ICMP :
6580                         nifq = &softn->ipf_nat_icmptq;
6581                         break;
6582                 case IPPROTO_TCP :
6583                         nifq = softn->ipf_nat_tcptq +
6584                                nat->nat_tqe.tqe_state[rev];
6585                         break;
6586                 default :
6587                         nifq = &softn->ipf_nat_iptq;
6588                         break;
6589                 }
6590         }
6591
6592         oifq = nat->nat_tqe.tqe_ifq;
6593         /*
6594          * If it's currently on a timeout queue, move it from one queue to
6595          * another, else put it on the end of the newly determined queue.
6596          */
6597         if (oifq != NULL)
6598                 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq);
6599         else
6600                 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat);
6601         return;
6602 }
6603
6604
6605 /* ------------------------------------------------------------------------ */
6606 /* Function:    nat_getnext                                                 */
6607 /* Returns:     int - 0 == ok, else error                                   */
6608 /* Parameters:  softc(I) - pointer to soft context main structure           */
6609 /*              t(I)   - pointer to ipftoken structure                      */
6610 /*              itp(I) - pointer to ipfgeniter_t structure                  */
6611 /*                                                                          */
6612 /* Fetch the next nat/ipnat structure pointer from the linked list and      */
6613 /* copy it out to the storage space pointed to by itp_data.  The next item  */
6614 /* in the list to look at is put back in the ipftoken struture.             */
6615 /* ------------------------------------------------------------------------ */
6616 static int
6617 ipf_nat_getnext(softc, t, itp, objp)
6618         ipf_main_softc_t *softc;
6619         ipftoken_t *t;
6620         ipfgeniter_t *itp;
6621         ipfobj_t *objp;
6622 {
6623         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6624         hostmap_t *hm, *nexthm = NULL, zerohm;
6625         ipnat_t *ipn, *nextipnat = NULL, zeroipn;
6626         nat_t *nat, *nextnat = NULL, zeronat;
6627         int error = 0;
6628         void *nnext;
6629
6630         if (itp->igi_nitems != 1) {
6631                 IPFERROR(60075);
6632                 return ENOSPC;
6633         }
6634
6635         READ_ENTER(&softc->ipf_nat);
6636
6637         switch (itp->igi_type)
6638         {
6639         case IPFGENITER_HOSTMAP :
6640                 hm = t->ipt_data;
6641                 if (hm == NULL) {
6642                         nexthm = softn->ipf_hm_maplist;
6643                 } else {
6644                         nexthm = hm->hm_next;
6645                 }
6646                 if (nexthm != NULL) {
6647                         ATOMIC_INC32(nexthm->hm_ref);
6648                         t->ipt_data = nexthm;
6649                 } else {
6650                         bzero(&zerohm, sizeof(zerohm));
6651                         nexthm = &zerohm;
6652                         t->ipt_data = NULL;
6653                 }
6654                 nnext = nexthm->hm_next;
6655                 break;
6656
6657         case IPFGENITER_IPNAT :
6658                 ipn = t->ipt_data;
6659                 if (ipn == NULL) {
6660                         nextipnat = softn->ipf_nat_list;
6661                 } else {
6662                         nextipnat = ipn->in_next;
6663                 }
6664                 if (nextipnat != NULL) {
6665                         ATOMIC_INC32(nextipnat->in_use);
6666                         t->ipt_data = nextipnat;
6667                 } else {
6668                         bzero(&zeroipn, sizeof(zeroipn));
6669                         nextipnat = &zeroipn;
6670                         t->ipt_data = NULL;
6671                 }
6672                 nnext = nextipnat->in_next;
6673                 break;
6674
6675         case IPFGENITER_NAT :
6676                 nat = t->ipt_data;
6677                 if (nat == NULL) {
6678                         nextnat = softn->ipf_nat_instances;
6679                 } else {
6680                         nextnat = nat->nat_next;
6681                 }
6682                 if (nextnat != NULL) {
6683                         MUTEX_ENTER(&nextnat->nat_lock);
6684                         nextnat->nat_ref++;
6685                         MUTEX_EXIT(&nextnat->nat_lock);
6686                         t->ipt_data = nextnat;
6687                 } else {
6688                         bzero(&zeronat, sizeof(zeronat));
6689                         nextnat = &zeronat;
6690                         t->ipt_data = NULL;
6691                 }
6692                 nnext = nextnat->nat_next;
6693                 break;
6694
6695         default :
6696                 RWLOCK_EXIT(&softc->ipf_nat);
6697                 IPFERROR(60055);
6698                 return EINVAL;
6699         }
6700
6701         RWLOCK_EXIT(&softc->ipf_nat);
6702
6703         objp->ipfo_ptr = itp->igi_data;
6704
6705         switch (itp->igi_type)
6706         {
6707         case IPFGENITER_HOSTMAP :
6708                 error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm));
6709                 if (error != 0) {
6710                         IPFERROR(60049);
6711                         error = EFAULT;
6712                 }
6713                 if (hm != NULL) {
6714                         WRITE_ENTER(&softc->ipf_nat);
6715                         ipf_nat_hostmapdel(softc, &hm);
6716                         RWLOCK_EXIT(&softc->ipf_nat);
6717                 }
6718                 break;
6719
6720         case IPFGENITER_IPNAT :
6721                 objp->ipfo_size = nextipnat->in_size;
6722                 objp->ipfo_type = IPFOBJ_IPNAT;
6723                 error = ipf_outobjk(softc, objp, nextipnat);
6724                 if (ipn != NULL) {
6725                         WRITE_ENTER(&softc->ipf_nat);
6726                         ipf_nat_rule_deref(softc, &ipn);
6727                         RWLOCK_EXIT(&softc->ipf_nat);
6728                 }
6729                 break;
6730
6731         case IPFGENITER_NAT :
6732                 objp->ipfo_size = sizeof(nat_t);
6733                 objp->ipfo_type = IPFOBJ_NAT;
6734                 error = ipf_outobjk(softc, objp, nextnat);
6735                 if (nat != NULL)
6736                         ipf_nat_deref(softc, &nat);
6737
6738                 break;
6739         }
6740
6741         if (nnext == NULL)
6742                 ipf_token_mark_complete(t);
6743
6744         return error;
6745 }
6746
6747
6748 /* ------------------------------------------------------------------------ */
6749 /* Function:    nat_extraflush                                              */
6750 /* Returns:     int - 0 == success, -1 == failure                           */
6751 /* Parameters:  softc(I) - pointer to soft context main structure           */
6752 /*              softn(I) - pointer to NAT context structure                 */
6753 /*              which(I) - how to flush the active NAT table                */
6754 /* Write Locks: ipf_nat                                                     */
6755 /*                                                                          */
6756 /* Flush nat tables.  Three actions currently defined:                      */
6757 /* which == 0 : flush all nat table entries                                 */
6758 /* which == 1 : flush TCP connections which have started to close but are   */
6759 /*            stuck for some reason.                                        */
6760 /* which == 2 : flush TCP connections which have been idle for a long time, */
6761 /*            starting at > 4 days idle and working back in successive half-*/
6762 /*            days to at most 12 hours old.  If this fails to free enough   */
6763 /*            slots then work backwards in half hour slots to 30 minutes.   */
6764 /*            If that too fails, then work backwards in 30 second intervals */
6765 /*            for the last 30 minutes to at worst 30 seconds idle.          */
6766 /* ------------------------------------------------------------------------ */
6767 static int
6768 ipf_nat_extraflush(softc, softn, which)
6769         ipf_main_softc_t *softc;
6770         ipf_nat_softc_t *softn;
6771         int which;
6772 {
6773         nat_t *nat, **natp;
6774         ipftqent_t *tqn;
6775         ipftq_t *ifq;
6776         int removed;
6777         SPL_INT(s);
6778
6779         removed = 0;
6780
6781         SPL_NET(s);
6782         switch (which)
6783         {
6784         case 0 :
6785                 softn->ipf_nat_stats.ns_flush_all++;
6786                 /*
6787                  * Style 0 flush removes everything...
6788                  */
6789                 for (natp = &softn->ipf_nat_instances;
6790                      ((nat = *natp) != NULL); ) {
6791                         ipf_nat_delete(softc, nat, NL_FLUSH);
6792                         removed++;
6793                 }
6794                 break;
6795
6796         case 1 :
6797                 softn->ipf_nat_stats.ns_flush_closing++;
6798                 /*
6799                  * Since we're only interested in things that are closing,
6800                  * we can start with the appropriate timeout queue.
6801                  */
6802                 for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT;
6803                      ifq != NULL; ifq = ifq->ifq_next) {
6804
6805                         for (tqn = ifq->ifq_head; tqn != NULL; ) {
6806                                 nat = tqn->tqe_parent;
6807                                 tqn = tqn->tqe_next;
6808                                 if (nat->nat_pr[0] != IPPROTO_TCP ||
6809                                     nat->nat_pr[1] != IPPROTO_TCP)
6810                                         break;
6811                                 ipf_nat_delete(softc, nat, NL_EXPIRE);
6812                                 removed++;
6813                         }
6814                 }
6815
6816                 /*
6817                  * Also need to look through the user defined queues.
6818                  */
6819                 for (ifq = softn->ipf_nat_utqe; ifq != NULL;
6820                      ifq = ifq->ifq_next) {
6821                         for (tqn = ifq->ifq_head; tqn != NULL; ) {
6822                                 nat = tqn->tqe_parent;
6823                                 tqn = tqn->tqe_next;
6824                                 if (nat->nat_pr[0] != IPPROTO_TCP ||
6825                                     nat->nat_pr[1] != IPPROTO_TCP)
6826                                         continue;
6827
6828                                 if ((nat->nat_tcpstate[0] >
6829                                      IPF_TCPS_ESTABLISHED) &&
6830                                     (nat->nat_tcpstate[1] >
6831                                      IPF_TCPS_ESTABLISHED)) {
6832                                         ipf_nat_delete(softc, nat, NL_EXPIRE);
6833                                         removed++;
6834                                 }
6835                         }
6836                 }
6837                 break;
6838
6839                 /*
6840                  * Args 5-11 correspond to flushing those particular states
6841                  * for TCP connections.
6842                  */
6843         case IPF_TCPS_CLOSE_WAIT :
6844         case IPF_TCPS_FIN_WAIT_1 :
6845         case IPF_TCPS_CLOSING :
6846         case IPF_TCPS_LAST_ACK :
6847         case IPF_TCPS_FIN_WAIT_2 :
6848         case IPF_TCPS_TIME_WAIT :
6849         case IPF_TCPS_CLOSED :
6850                 softn->ipf_nat_stats.ns_flush_state++;
6851                 tqn = softn->ipf_nat_tcptq[which].ifq_head;
6852                 while (tqn != NULL) {
6853                         nat = tqn->tqe_parent;
6854                         tqn = tqn->tqe_next;
6855                         ipf_nat_delete(softc, nat, NL_FLUSH);
6856                         removed++;
6857                 }
6858                 break;
6859
6860         default :
6861                 if (which < 30)
6862                         break;
6863
6864                 softn->ipf_nat_stats.ns_flush_timeout++;
6865                 /*
6866                  * Take a large arbitrary number to mean the number of seconds
6867                  * for which which consider to be the maximum value we'll allow
6868                  * the expiration to be.
6869                  */
6870                 which = IPF_TTLVAL(which);
6871                 for (natp = &softn->ipf_nat_instances;
6872                      ((nat = *natp) != NULL); ) {
6873                         if (softc->ipf_ticks - nat->nat_touched > which) {
6874                                 ipf_nat_delete(softc, nat, NL_FLUSH);
6875                                 removed++;
6876                         } else
6877                                 natp = &nat->nat_next;
6878                 }
6879                 break;
6880         }
6881
6882         if (which != 2) {
6883                 SPL_X(s);
6884                 return removed;
6885         }
6886
6887         softn->ipf_nat_stats.ns_flush_queue++;
6888
6889         /*
6890          * Asked to remove inactive entries because the table is full, try
6891          * again, 3 times, if first attempt failed with a different criteria
6892          * each time.  The order tried in must be in decreasing age.
6893          * Another alternative is to implement random drop and drop N entries
6894          * at random until N have been freed up.
6895          */
6896         if (softc->ipf_ticks - softn->ipf_nat_last_force_flush >
6897             IPF_TTLVAL(5)) {
6898                 softn->ipf_nat_last_force_flush = softc->ipf_ticks;
6899
6900                 removed = ipf_queueflush(softc, ipf_nat_flush_entry,
6901                                          softn->ipf_nat_tcptq,
6902                                          softn->ipf_nat_utqe,
6903                                          &softn->ipf_nat_stats.ns_active,
6904                                          softn->ipf_nat_table_sz,
6905                                          softn->ipf_nat_table_wm_low);
6906         }
6907
6908         SPL_X(s);
6909         return removed;
6910 }
6911
6912
6913 /* ------------------------------------------------------------------------ */
6914 /* Function:    ipf_nat_flush_entry                                         */
6915 /* Returns:     0 - always succeeds                                         */
6916 /* Parameters:  softc(I) - pointer to soft context main structure           */
6917 /*              entry(I) - pointer to NAT entry                             */
6918 /* Write Locks: ipf_nat                                                     */
6919 /*                                                                          */
6920 /* This function is a stepping stone between ipf_queueflush() and           */
6921 /* nat_dlete().  It is used so we can provide a uniform interface via the   */
6922 /* ipf_queueflush() function.  Since the nat_delete() function returns void */
6923 /* we translate that to mean it always succeeds in deleting something.      */
6924 /* ------------------------------------------------------------------------ */
6925 static int
6926 ipf_nat_flush_entry(softc, entry)
6927         ipf_main_softc_t *softc;
6928         void *entry;
6929 {
6930         ipf_nat_delete(softc, entry, NL_FLUSH);
6931         return 0;
6932 }
6933
6934
6935 /* ------------------------------------------------------------------------ */
6936 /* Function:    ipf_nat_iterator                                            */
6937 /* Returns:     int - 0 == ok, else error                                   */
6938 /* Parameters:  softc(I) - pointer to soft context main structure           */
6939 /*              token(I) - pointer to ipftoken structure                    */
6940 /*              itp(I)   - pointer to ipfgeniter_t structure                */
6941 /*              obj(I)   - pointer to data description structure            */
6942 /*                                                                          */
6943 /* This function acts as a handler for the SIOCGENITER ioctls that use a    */
6944 /* generic structure to iterate through a list.  There are three different  */
6945 /* linked lists of NAT related information to go through: NAT rules, active */
6946 /* NAT mappings and the NAT fragment cache.                                 */
6947 /* ------------------------------------------------------------------------ */
6948 static int
6949 ipf_nat_iterator(softc, token, itp, obj)
6950         ipf_main_softc_t *softc;
6951         ipftoken_t *token;
6952         ipfgeniter_t *itp;
6953         ipfobj_t *obj;
6954 {
6955         int error;
6956
6957         if (itp->igi_data == NULL) {
6958                 IPFERROR(60052);
6959                 return EFAULT;
6960         }
6961
6962         switch (itp->igi_type)
6963         {
6964         case IPFGENITER_HOSTMAP :
6965         case IPFGENITER_IPNAT :
6966         case IPFGENITER_NAT :
6967                 error = ipf_nat_getnext(softc, token, itp, obj);
6968                 break;
6969
6970         case IPFGENITER_NATFRAG :
6971                 error = ipf_frag_nat_next(softc, token, itp);
6972                 break;
6973         default :
6974                 IPFERROR(60053);
6975                 error = EINVAL;
6976                 break;
6977         }
6978
6979         return error;
6980 }
6981
6982
6983 /* ------------------------------------------------------------------------ */
6984 /* Function:    ipf_nat_setpending                                          */
6985 /* Returns:     Nil                                                         */
6986 /* Parameters:  softc(I) - pointer to soft context main structure           */
6987 /*              nat(I)   - pointer to NAT structure                         */
6988 /* Locks:       ipf_nat (read or write)                                     */
6989 /*                                                                          */
6990 /* Put the NAT entry on to the pending queue - this queue has a very short  */
6991 /* lifetime where items are put that can't be deleted straight away because */
6992 /* of locking issues but we want to delete them ASAP, anyway.  In calling   */
6993 /* this function, it is assumed that the owner (if there is one, as shown   */
6994 /* by nat_me) is no longer interested in it.                                */
6995 /* ------------------------------------------------------------------------ */
6996 void
6997 ipf_nat_setpending(softc, nat)
6998         ipf_main_softc_t *softc;
6999         nat_t *nat;
7000 {
7001         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7002         ipftq_t *oifq;
7003
7004         oifq = nat->nat_tqe.tqe_ifq;
7005         if (oifq != NULL)
7006                 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq,
7007                               &softn->ipf_nat_pending);
7008         else
7009                 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe,
7010                                 &softn->ipf_nat_pending, nat);
7011
7012         if (nat->nat_me != NULL) {
7013                 *nat->nat_me = NULL;
7014                 nat->nat_me = NULL;
7015                 nat->nat_ref--;
7016                 ASSERT(nat->nat_ref >= 0);
7017         }
7018 }
7019
7020
7021 /* ------------------------------------------------------------------------ */
7022 /* Function:    nat_newrewrite                                              */
7023 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
7024 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
7025 /* Parameters:  fin(I) - pointer to packet information                      */
7026 /*              nat(I) - pointer to NAT entry                               */
7027 /*              ni(I)  - pointer to structure with misc. information needed */
7028 /*                       to create new NAT entry.                           */
7029 /* Write Lock:  ipf_nat                                                     */
7030 /*                                                                          */
7031 /* This function is responsible for setting up an active NAT session where  */
7032 /* we are changing both the source and destination parameters at the same   */
7033 /* time.  The loop in here works differently to elsewhere - each iteration  */
7034 /* is responsible for changing a single parameter that can be incremented.  */
7035 /* So one pass may increase the source IP#, next source port, next dest. IP#*/
7036 /* and the last destination port for a total of 4 iterations to try each.   */
7037 /* This is done to try and exhaustively use the translation space available.*/
7038 /* ------------------------------------------------------------------------ */
7039 static int
7040 ipf_nat_newrewrite(fin, nat, nai)
7041         fr_info_t *fin;
7042         nat_t *nat;
7043         natinfo_t *nai;
7044 {
7045         int src_search = 1;
7046         int dst_search = 1;
7047         fr_info_t frnat;
7048         u_32_t flags;
7049         u_short swap;
7050         ipnat_t *np;
7051         nat_t *natl;
7052         int l = 0;
7053         int changed;
7054
7055         natl = NULL;
7056         changed = -1;
7057         np = nai->nai_np;
7058         flags = nat->nat_flags;
7059         bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7060
7061         nat->nat_hm = NULL;
7062
7063         do {
7064                 changed = -1;
7065                 /* TRACE (l, src_search, dst_search, np) */
7066
7067                 if ((src_search == 0) && (np->in_spnext == 0) &&
7068                     (dst_search == 0) && (np->in_dpnext == 0)) {
7069                         if (l > 0)
7070                                 return -1;
7071                 }
7072
7073                 /*
7074                  * Find a new source address
7075                  */
7076                 if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr,
7077                                      &frnat.fin_saddr) == -1) {
7078                         return -1;
7079                 }
7080
7081                 if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) {
7082                         src_search = 0;
7083                         if (np->in_stepnext == 0)
7084                                 np->in_stepnext = 1;
7085
7086                 } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
7087                         src_search = 0;
7088                         if (np->in_stepnext == 0)
7089                                 np->in_stepnext = 1;
7090
7091                 } else if (np->in_nsrcmsk == 0xffffffff) {
7092                         src_search = 0;
7093                         if (np->in_stepnext == 0)
7094                                 np->in_stepnext = 1;
7095
7096                 } else if (np->in_nsrcmsk != 0xffffffff) {
7097                         if (np->in_stepnext == 0 && changed == -1) {
7098                                 np->in_snip++;
7099                                 np->in_stepnext++;
7100                                 changed = 0;
7101                         }
7102                 }
7103
7104                 if ((flags & IPN_TCPUDPICMP) != 0) {
7105                         if (np->in_spnext != 0)
7106                                 frnat.fin_data[0] = np->in_spnext;
7107
7108                         /*
7109                          * Standard port translation.  Select next port.
7110                          */
7111                         if ((flags & IPN_FIXEDSPORT) != 0) {
7112                                 np->in_stepnext = 2;
7113                         } else if ((np->in_stepnext == 1) &&
7114                                    (changed == -1) && (natl != NULL)) {
7115                                 np->in_spnext++;
7116                                 np->in_stepnext++;
7117                                 changed = 1;
7118                                 if (np->in_spnext > np->in_spmax)
7119                                         np->in_spnext = np->in_spmin;
7120                         }
7121                 } else {
7122                         np->in_stepnext = 2;
7123                 }
7124                 np->in_stepnext &= 0x3;
7125
7126                 /*
7127                  * Find a new destination address
7128                  */
7129                 /* TRACE (fin, np, l, frnat) */
7130
7131                 if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr,
7132                                      &frnat.fin_daddr) == -1)
7133                         return -1;
7134                 if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
7135                         dst_search = 0;
7136                         if (np->in_stepnext == 2)
7137                                 np->in_stepnext = 3;
7138
7139                 } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) {
7140                         dst_search = 0;
7141                         if (np->in_stepnext == 2)
7142                                 np->in_stepnext = 3;
7143
7144                 } else if (np->in_ndstmsk == 0xffffffff) {
7145                         dst_search = 0;
7146                         if (np->in_stepnext == 2)
7147                                 np->in_stepnext = 3;
7148
7149                 } else if (np->in_ndstmsk != 0xffffffff) {
7150                         if ((np->in_stepnext == 2) && (changed == -1) &&
7151                             (natl != NULL)) {
7152                                 changed = 2;
7153                                 np->in_stepnext++;
7154                                 np->in_dnip++;
7155                         }
7156                 }
7157
7158                 if ((flags & IPN_TCPUDPICMP) != 0) {
7159                         if (np->in_dpnext != 0)
7160                                 frnat.fin_data[1] = np->in_dpnext;
7161
7162                         /*
7163                          * Standard port translation.  Select next port.
7164                          */
7165                         if ((flags & IPN_FIXEDDPORT) != 0) {
7166                                 np->in_stepnext = 0;
7167                         } else if (np->in_stepnext == 3 && changed == -1) {
7168                                 np->in_dpnext++;
7169                                 np->in_stepnext++;
7170                                 changed = 3;
7171                                 if (np->in_dpnext > np->in_dpmax)
7172                                         np->in_dpnext = np->in_dpmin;
7173                         }
7174                 } else {
7175                         if (np->in_stepnext == 3)
7176                                 np->in_stepnext = 0;
7177                 }
7178
7179                 /* TRACE (frnat) */
7180
7181                 /*
7182                  * Here we do a lookup of the connection as seen from
7183                  * the outside.  If an IP# pair already exists, try
7184                  * again.  So if you have A->B becomes C->B, you can
7185                  * also have D->E become C->E but not D->B causing
7186                  * another C->B.  Also take protocol and ports into
7187                  * account when determining whether a pre-existing
7188                  * NAT setup will cause an external conflict where
7189                  * this is appropriate.
7190                  *
7191                  * fin_data[] is swapped around because we are doing a
7192                  * lookup of the packet is if it were moving in the opposite
7193                  * direction of the one we are working with now.
7194                  */
7195                 if (flags & IPN_TCPUDP) {
7196                         swap = frnat.fin_data[0];
7197                         frnat.fin_data[0] = frnat.fin_data[1];
7198                         frnat.fin_data[1] = swap;
7199                 }
7200                 if (fin->fin_out == 1) {
7201                         natl = ipf_nat_inlookup(&frnat,
7202                                                 flags & ~(SI_WILDP|NAT_SEARCH),
7203                                                 (u_int)frnat.fin_p,
7204                                                 frnat.fin_dst, frnat.fin_src);
7205
7206                 } else {
7207                         natl = ipf_nat_outlookup(&frnat,
7208                                                  flags & ~(SI_WILDP|NAT_SEARCH),
7209                                                  (u_int)frnat.fin_p,
7210                                                  frnat.fin_dst, frnat.fin_src);
7211                 }
7212                 if (flags & IPN_TCPUDP) {
7213                         swap = frnat.fin_data[0];
7214                         frnat.fin_data[0] = frnat.fin_data[1];
7215                         frnat.fin_data[1] = swap;
7216                 }
7217
7218                 /* TRACE natl, in_stepnext, l */
7219
7220                 if ((natl != NULL) && (l > 8))  /* XXX 8 is arbitrary */
7221                         return -1;
7222
7223                 np->in_stepnext &= 0x3;
7224
7225                 l++;
7226                 changed = -1;
7227         } while (natl != NULL);
7228
7229         nat->nat_osrcip = fin->fin_src;
7230         nat->nat_odstip = fin->fin_dst;
7231         nat->nat_nsrcip = frnat.fin_src;
7232         nat->nat_ndstip = frnat.fin_dst;
7233
7234         if ((flags & IPN_TCPUDP) != 0) {
7235                 nat->nat_osport = htons(fin->fin_data[0]);
7236                 nat->nat_odport = htons(fin->fin_data[1]);
7237                 nat->nat_nsport = htons(frnat.fin_data[0]);
7238                 nat->nat_ndport = htons(frnat.fin_data[1]);
7239         } else if ((flags & IPN_ICMPQUERY) != 0) {
7240                 nat->nat_oicmpid = fin->fin_data[1];
7241                 nat->nat_nicmpid = frnat.fin_data[1];
7242         }
7243
7244         return 0;
7245 }
7246
7247
7248 /* ------------------------------------------------------------------------ */
7249 /* Function:    nat_newdivert                                               */
7250 /* Returns:     int - -1 == error, 0 == success                             */
7251 /* Parameters:  fin(I) - pointer to packet information                      */
7252 /*              nat(I) - pointer to NAT entry                               */
7253 /*              ni(I)  - pointer to structure with misc. information needed */
7254 /*                       to create new NAT entry.                           */
7255 /* Write Lock:  ipf_nat                                                     */
7256 /*                                                                          */
7257 /* Create a new NAT  divert session as defined by the NAT rule.  This is    */
7258 /* somewhat different to other NAT session creation routines because we     */
7259 /* do not iterate through either port numbers or IP addresses, searching    */
7260 /* for a unique mapping, however, a complimentary duplicate check is made.  */
7261 /* ------------------------------------------------------------------------ */
7262 static int
7263 ipf_nat_newdivert(fin, nat, nai)
7264         fr_info_t *fin;
7265         nat_t *nat;
7266         natinfo_t *nai;
7267 {
7268         ipf_main_softc_t *softc = fin->fin_main_soft;
7269         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7270         fr_info_t frnat;
7271         ipnat_t *np;
7272         nat_t *natl;
7273         int p;
7274
7275         np = nai->nai_np;
7276         bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7277
7278         nat->nat_pr[0] = 0;
7279         nat->nat_osrcaddr = fin->fin_saddr;
7280         nat->nat_odstaddr = fin->fin_daddr;
7281         frnat.fin_saddr = htonl(np->in_snip);
7282         frnat.fin_daddr = htonl(np->in_dnip);
7283         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7284                 nat->nat_osport = htons(fin->fin_data[0]);
7285                 nat->nat_odport = htons(fin->fin_data[1]);
7286         } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7287                 nat->nat_oicmpid = fin->fin_data[1];
7288         }
7289
7290         if (np->in_redir & NAT_DIVERTUDP) {
7291                 frnat.fin_data[0] = np->in_spnext;
7292                 frnat.fin_data[1] = np->in_dpnext;
7293                 frnat.fin_flx |= FI_TCPUDP;
7294                 p = IPPROTO_UDP;
7295         } else {
7296                 frnat.fin_flx &= ~FI_TCPUDP;
7297                 p = IPPROTO_IPIP;
7298         }
7299
7300         if (fin->fin_out == 1) {
7301                 natl = ipf_nat_inlookup(&frnat, 0, p,
7302                                         frnat.fin_dst, frnat.fin_src);
7303
7304         } else {
7305                 natl = ipf_nat_outlookup(&frnat, 0, p,
7306                                          frnat.fin_dst, frnat.fin_src);
7307         }
7308
7309         if (natl != NULL) {
7310                 NBUMPSIDED(fin->fin_out, ns_divert_exist);
7311                 return -1;
7312         }
7313
7314         nat->nat_nsrcaddr = frnat.fin_saddr;
7315         nat->nat_ndstaddr = frnat.fin_daddr;
7316         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7317                 nat->nat_nsport = htons(frnat.fin_data[0]);
7318                 nat->nat_ndport = htons(frnat.fin_data[1]);
7319         } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7320                 nat->nat_nicmpid = frnat.fin_data[1];
7321         }
7322
7323         nat->nat_pr[fin->fin_out] = fin->fin_p;
7324         nat->nat_pr[1 - fin->fin_out] = p;
7325
7326         if (np->in_redir & NAT_REDIRECT)
7327                 nat->nat_dir = NAT_DIVERTIN;
7328         else
7329                 nat->nat_dir = NAT_DIVERTOUT;
7330
7331         return 0;
7332 }
7333
7334
7335 /* ------------------------------------------------------------------------ */
7336 /* Function:    nat_builddivertmp                                           */
7337 /* Returns:     int - -1 == error, 0 == success                             */
7338 /* Parameters:  softn(I) - pointer to NAT context structure                 */
7339 /*              np(I)    - pointer to a NAT rule                            */
7340 /*                                                                          */
7341 /* For divert rules, a skeleton packet representing what will be prepended  */
7342 /* to the real packet is created.  Even though we don't have the full       */
7343 /* packet here, a checksum is calculated that we update later when we       */
7344 /* fill in the final details.  At present a 0 checksum for UDP is being set */
7345 /* here because it is expected that divert will be used for localhost.      */
7346 /* ------------------------------------------------------------------------ */
7347 static int
7348 ipf_nat_builddivertmp(softn, np)
7349         ipf_nat_softc_t *softn;
7350         ipnat_t *np;
7351 {
7352         udphdr_t *uh;
7353         size_t len;
7354         ip_t *ip;
7355
7356         if ((np->in_redir & NAT_DIVERTUDP) != 0)
7357                 len = sizeof(ip_t) + sizeof(udphdr_t);
7358         else
7359                 len = sizeof(ip_t);
7360
7361         ALLOC_MB_T(np->in_divmp, len);
7362         if (np->in_divmp == NULL) {
7363                 NBUMPD(ipf_nat_stats, ns_divert_build);
7364                 return -1;
7365         }
7366
7367         /*
7368          * First, the header to get the packet diverted to the new destination
7369          */
7370         ip = MTOD(np->in_divmp, ip_t *);
7371         IP_V_A(ip, 4);
7372         IP_HL_A(ip, 5);
7373         ip->ip_tos = 0;
7374         if ((np->in_redir & NAT_DIVERTUDP) != 0)
7375                 ip->ip_p = IPPROTO_UDP;
7376         else
7377                 ip->ip_p = IPPROTO_IPIP;
7378         ip->ip_ttl = 255;
7379         ip->ip_off = 0;
7380         ip->ip_sum = 0;
7381         ip->ip_len = htons(len);
7382         ip->ip_id = 0;
7383         ip->ip_src.s_addr = htonl(np->in_snip);
7384         ip->ip_dst.s_addr = htonl(np->in_dnip);
7385         ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
7386
7387         if (np->in_redir & NAT_DIVERTUDP) {
7388                 uh = (udphdr_t *)(ip + 1);
7389                 uh->uh_sum = 0;
7390                 uh->uh_ulen = 8;
7391                 uh->uh_sport = htons(np->in_spnext);
7392                 uh->uh_dport = htons(np->in_dpnext);
7393         }
7394
7395         return 0;
7396 }
7397
7398
7399 #define MINDECAP        (sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t))
7400
7401 /* ------------------------------------------------------------------------ */
7402 /* Function:    nat_decap                                                   */
7403 /* Returns:     int - -1 == error, 0 == success                             */
7404 /* Parameters:  fin(I) - pointer to packet information                      */
7405 /*              nat(I) - pointer to current NAT session                     */
7406 /*                                                                          */
7407 /* This function is responsible for undoing a packet's encapsulation in the */
7408 /* reverse of an encap/divert rule.  After removing the outer encapsulation */
7409 /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
7410 /* match the "new" packet as it may still be used by IPFilter elsewhere.    */
7411 /* We use "dir" here as the basis for some of the expectations about the    */
7412 /* outer header.  If we return an error, the goal is to leave the original  */
7413 /* packet information undisturbed - this falls short at the end where we'd  */
7414 /* need to back a backup copy of "fin" - expensive.                         */
7415 /* ------------------------------------------------------------------------ */
7416 static int
7417 ipf_nat_decap(fin, nat)
7418         fr_info_t *fin;
7419         nat_t *nat;
7420 {
7421         ipf_main_softc_t *softc = fin->fin_main_soft;
7422         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7423         char *hdr;
7424         int hlen;
7425         int skip;
7426         mb_t *m;
7427
7428         if ((fin->fin_flx & FI_ICMPERR) != 0) {
7429                 /*
7430                  * ICMP packets don't get decapsulated, instead what we need
7431                  * to do is change the ICMP reply from including (in the data
7432                  * portion for errors) the encapsulated packet that we sent
7433                  * out to something that resembles the original packet prior
7434                  * to encapsulation.  This isn't done here - all we're doing
7435                  * here is changing the outer address to ensure that it gets
7436                  * targetted back to the correct system.
7437                  */
7438
7439                 if (nat->nat_dir & NAT_OUTBOUND) {
7440                         u_32_t sum1, sum2, sumd;
7441
7442                         sum1 = ntohl(fin->fin_daddr);
7443                         sum2 = ntohl(nat->nat_osrcaddr);
7444                         CALC_SUMD(sum1, sum2, sumd);
7445                         fin->fin_ip->ip_dst = nat->nat_osrcip;
7446                         fin->fin_daddr = nat->nat_osrcaddr;
7447 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
7448      defined(__osf__) || defined(linux)
7449                         ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0);
7450 #endif
7451                 }
7452                 return 0;
7453         }
7454
7455         m = fin->fin_m;
7456         skip = fin->fin_hlen;
7457
7458         switch (nat->nat_dir)
7459         {
7460         case NAT_DIVERTIN :
7461         case NAT_DIVERTOUT :
7462                 if (fin->fin_plen < MINDECAP)
7463                         return -1;
7464                 skip += sizeof(udphdr_t);
7465                 break;
7466
7467         case NAT_ENCAPIN :
7468         case NAT_ENCAPOUT :
7469                 if (fin->fin_plen < (skip + sizeof(ip_t)))
7470                         return -1;
7471                 break;
7472         default :
7473                 return -1;
7474                 /* NOTREACHED */
7475         }
7476
7477         /*
7478          * The aim here is to keep the original packet details in "fin" for
7479          * as long as possible so that returning with an error is for the
7480          * original packet and there is little undoing work to do.
7481          */
7482         if (M_LEN(m) < skip + sizeof(ip_t)) {
7483                 if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1)
7484                         return -1;
7485         }
7486
7487         hdr = MTOD(fin->fin_m, char *);
7488         fin->fin_ip = (ip_t *)(hdr + skip);
7489         hlen = IP_HL(fin->fin_ip) << 2;
7490
7491         if (ipf_pr_pullup(fin, skip + hlen) == -1) {
7492                 NBUMPSIDED(fin->fin_out, ns_decap_pullup);
7493                 return -1;
7494         }
7495
7496         fin->fin_hlen = hlen;
7497         fin->fin_dlen -= skip;
7498         fin->fin_plen -= skip;
7499         fin->fin_ipoff += skip;
7500
7501         if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) {
7502                 NBUMPSIDED(fin->fin_out, ns_decap_bad);
7503                 return -1;
7504         }
7505
7506         return skip;
7507 }
7508
7509
7510 /* ------------------------------------------------------------------------ */
7511 /* Function:    nat_nextaddr                                                */
7512 /* Returns:     int - -1 == bad input (no new address),                     */
7513 /*                     0 == success and dst has new address                 */
7514 /* Parameters:  fin(I) - pointer to packet information                      */
7515 /*              na(I)  - how to generate new address                        */
7516 /*              old(I) - original address being replaced                    */
7517 /*              dst(O) - where to put the new address                       */
7518 /* Write Lock:  ipf_nat                                                     */
7519 /*                                                                          */
7520 /* This function uses the contents of the "na" structure, in combination    */
7521 /* with "old" to produce a new address to store in "dst".  Not all of the   */
7522 /* possible uses of "na" will result in a new address.                      */
7523 /* ------------------------------------------------------------------------ */
7524 static int
7525 ipf_nat_nextaddr(fin, na, old, dst)
7526         fr_info_t *fin;
7527         nat_addr_t *na;
7528         u_32_t *old, *dst;
7529 {
7530         ipf_main_softc_t *softc = fin->fin_main_soft;
7531         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7532         u_32_t amin, amax, new;
7533         i6addr_t newip;
7534         int error;
7535
7536         new = 0;
7537         amin = na->na_addr[0].in4.s_addr;
7538
7539         switch (na->na_atype)
7540         {
7541         case FRI_RANGE :
7542                 amax = na->na_addr[1].in4.s_addr;
7543                 break;
7544
7545         case FRI_NETMASKED :
7546         case FRI_DYNAMIC :
7547         case FRI_NORMAL :
7548                 /*
7549                  * Compute the maximum address by adding the inverse of the
7550                  * netmask to the minimum address.
7551                  */
7552                 amax = ~na->na_addr[1].in4.s_addr;
7553                 amax |= amin;
7554                 break;
7555
7556         case FRI_LOOKUP :
7557                 break;
7558
7559         case FRI_BROADCAST :
7560         case FRI_PEERADDR :
7561         case FRI_NETWORK :
7562         default :
7563                 return -1;
7564         }
7565
7566         error = -1;
7567
7568         if (na->na_atype == FRI_LOOKUP) {
7569                 if (na->na_type == IPLT_DSTLIST) {
7570                         error = ipf_dstlist_select_node(fin, na->na_ptr, dst,
7571                                                         NULL);
7572                 } else {
7573                         NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7574                 }
7575
7576         } else if (na->na_atype == IPLT_NONE) {
7577                 /*
7578                  * 0/0 as the new address means leave it alone.
7579                  */
7580                 if (na->na_addr[0].in4.s_addr == 0 &&
7581                     na->na_addr[1].in4.s_addr == 0) {
7582                         new = *old;
7583
7584                 /*
7585                  * 0/32 means get the interface's address
7586                  */
7587                 } else if (na->na_addr[0].in4.s_addr == 0 &&
7588                            na->na_addr[1].in4.s_addr == 0xffffffff) {
7589                         if (ipf_ifpaddr(softc, 4, na->na_atype,
7590                                         fin->fin_ifp, &newip, NULL) == -1) {
7591                                 NBUMPSIDED(fin->fin_out, ns_ifpaddrfail);
7592                                 return -1;
7593                         }
7594                         new = newip.in4.s_addr;
7595                 } else {
7596                         new = htonl(na->na_nextip);
7597                 }
7598                 *dst = new;
7599                 error = 0;
7600
7601         } else {
7602                 NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7603         }
7604
7605         return error;
7606 }
7607
7608
7609 /* ------------------------------------------------------------------------ */
7610 /* Function:    nat_nextaddrinit                                            */
7611 /* Returns:     int - 0 == success, else error number                       */
7612 /* Parameters:  softc(I) - pointer to soft context main structure           */
7613 /*              na(I)      - NAT address information for generating new addr*/
7614 /*              initial(I) - flag indicating if it is the first call for    */
7615 /*                           this "na" structure.                           */
7616 /*              ifp(I)     - network interface to derive address            */
7617 /*                           information from.                              */
7618 /*                                                                          */
7619 /* This function is expected to be called in two scenarious: when a new NAT */
7620 /* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
7621 /* up with the valid network interfaces (possibly due to them changing.)    */
7622 /* To distinguish between these, the "initial" parameter is used.  If it is */
7623 /* 1 then this indicates the rule has just been reloaded and 0 for when we  */
7624 /* are updating information.  This difference is important because in       */
7625 /* instances where we are not updating address information associated with  */
7626 /* a network interface, we don't want to disturb what the "next" address to */
7627 /* come out of ipf_nat_nextaddr() will be.                                  */
7628 /* ------------------------------------------------------------------------ */
7629 static int
7630 ipf_nat_nextaddrinit(softc, base, na, initial, ifp)
7631         ipf_main_softc_t *softc;
7632         char *base;
7633         nat_addr_t *na;
7634         int initial;
7635         void *ifp;
7636 {
7637
7638         switch (na->na_atype)
7639         {
7640         case FRI_LOOKUP :
7641                 if (na->na_subtype == 0) {
7642                         na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
7643                                                         na->na_type,
7644                                                         na->na_num,
7645                                                         &na->na_func);
7646                 } else if (na->na_subtype == 1) {
7647                         na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
7648                                                          na->na_type,
7649                                                          base + na->na_num,
7650                                                          &na->na_func);
7651                 }
7652                 if (na->na_func == NULL) {
7653                         IPFERROR(60060);
7654                         return ESRCH;
7655                 }
7656                 if (na->na_ptr == NULL) {
7657                         IPFERROR(60056);
7658                         return ESRCH;
7659                 }
7660                 break;
7661
7662         case FRI_DYNAMIC :
7663         case FRI_BROADCAST :
7664         case FRI_NETWORK :
7665         case FRI_NETMASKED :
7666         case FRI_PEERADDR :
7667                 if (ifp != NULL)
7668                         (void )ipf_ifpaddr(softc, 4, na->na_atype, ifp,
7669                                            &na->na_addr[0], &na->na_addr[1]);
7670                 break;
7671
7672         case FRI_SPLIT :
7673         case FRI_RANGE :
7674                 if (initial)
7675                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7676                 break;
7677
7678         case FRI_NONE :
7679                 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7680                 return 0;
7681
7682         case FRI_NORMAL :
7683                 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7684                 break;
7685
7686         default :
7687                 IPFERROR(60054);
7688                 return EINVAL;
7689         }
7690
7691         if (initial && (na->na_atype == FRI_NORMAL)) {
7692                 if (na->na_addr[0].in4.s_addr == 0) {
7693                         if ((na->na_addr[1].in4.s_addr == 0xffffffff) ||
7694                             (na->na_addr[1].in4.s_addr == 0)) {
7695                                 return 0;
7696                         }
7697                 }
7698
7699                 if (na->na_addr[1].in4.s_addr == 0xffffffff) {
7700                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7701                 } else {
7702                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1;
7703                 }
7704         }
7705
7706         return 0;
7707 }
7708
7709
7710 /* ------------------------------------------------------------------------ */
7711 /* Function:    ipf_nat_matchflush                                          */
7712 /* Returns:     int - -1 == error, 0 == success                             */
7713 /* Parameters:  softc(I) - pointer to soft context main structure           */
7714 /*              softn(I) - pointer to NAT context structure                 */
7715 /*              nat(I)   - pointer to current NAT session                   */
7716 /*                                                                          */
7717 /* ------------------------------------------------------------------------ */
7718 static int
7719 ipf_nat_matchflush(softc, softn, data)
7720         ipf_main_softc_t *softc;
7721         ipf_nat_softc_t *softn;
7722         caddr_t data;
7723 {
7724         int *array, flushed, error;
7725         nat_t *nat, *natnext;
7726         ipfobj_t obj;
7727
7728         error = ipf_matcharray_load(softc, data, &obj, &array);
7729         if (error != 0)
7730                 return error;
7731
7732         flushed = 0;
7733
7734         for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) {
7735                 natnext = nat->nat_next;
7736                 if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) {
7737                         ipf_nat_delete(softc, nat, NL_FLUSH);
7738                         flushed++;
7739                 }
7740         }
7741
7742         obj.ipfo_retval = flushed;
7743         error = BCOPYOUT(&obj, data, sizeof(obj));
7744
7745         KFREES(array, array[0] * sizeof(*array));
7746
7747         return error;
7748 }
7749
7750
7751 /* ------------------------------------------------------------------------ */
7752 /* Function:    ipf_nat_matcharray                                          */
7753 /* Returns:     int - -1 == error, 0 == success                             */
7754 /* Parameters:  fin(I) - pointer to packet information                      */
7755 /*              nat(I) - pointer to current NAT session                     */
7756 /*                                                                          */
7757 /* ------------------------------------------------------------------------ */
7758 static int
7759 ipf_nat_matcharray(nat, array, ticks)
7760         nat_t *nat;
7761         int *array;
7762         u_long ticks;
7763 {
7764         int i, n, *x, e, p;
7765
7766         e = 0;
7767         n = array[0];
7768         x = array + 1;
7769
7770         for (; n > 0; x += 3 + x[2]) {
7771                 if (x[0] == IPF_EXP_END)
7772                         break;
7773                 e = 0;
7774
7775                 n -= x[2] + 3;
7776                 if (n < 0)
7777                         break;
7778
7779                 p = x[0] >> 16;
7780                 if (p != 0 && p != nat->nat_pr[1])
7781                         break;
7782
7783                 switch (x[0])
7784                 {
7785                 case IPF_EXP_IP_PR :
7786                         for (i = 0; !e && i < x[2]; i++) {
7787                                 e |= (nat->nat_pr[1] == x[i + 3]);
7788                         }
7789                         break;
7790
7791                 case IPF_EXP_IP_SRCADDR :
7792                         if (nat->nat_v[0] == 4) {
7793                                 for (i = 0; !e && i < x[2]; i++) {
7794                                         e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7795                                               x[i + 3]);
7796                                 }
7797                         }
7798                         if (nat->nat_v[1] == 4) {
7799                                 for (i = 0; !e && i < x[2]; i++) {
7800                                         e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7801                                               x[i + 3]);
7802                                 }
7803                         }
7804                         break;
7805
7806                 case IPF_EXP_IP_DSTADDR :
7807                         if (nat->nat_v[0] == 4) {
7808                                 for (i = 0; !e && i < x[2]; i++) {
7809                                         e |= ((nat->nat_odstaddr & x[i + 4]) ==
7810                                               x[i + 3]);
7811                                 }
7812                         }
7813                         if (nat->nat_v[1] == 4) {
7814                                 for (i = 0; !e && i < x[2]; i++) {
7815                                         e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7816                                               x[i + 3]);
7817                                 }
7818                         }
7819                         break;
7820
7821                 case IPF_EXP_IP_ADDR :
7822                         for (i = 0; !e && i < x[2]; i++) {
7823                                 if (nat->nat_v[0] == 4) {
7824                                         e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7825                                               x[i + 3]);
7826                                 }
7827                                 if (nat->nat_v[1] == 4) {
7828                                         e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7829                                               x[i + 3]);
7830                                 }
7831                                 if (nat->nat_v[0] == 4) {
7832                                         e |= ((nat->nat_odstaddr & x[i + 4]) ==
7833                                               x[i + 3]);
7834                                 }
7835                                 if (nat->nat_v[1] == 4) {
7836                                         e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7837                                               x[i + 3]);
7838                                 }
7839                         }
7840                         break;
7841
7842 #ifdef USE_INET6
7843                 case IPF_EXP_IP6_SRCADDR :
7844                         if (nat->nat_v[0] == 6) {
7845                                 for (i = 0; !e && i < x[3]; i++) {
7846                                         e |= IP6_MASKEQ(&nat->nat_osrc6,
7847                                                         x + i + 7, x + i + 3);
7848                                 }
7849                         }
7850                         if (nat->nat_v[1] == 6) {
7851                                 for (i = 0; !e && i < x[3]; i++) {
7852                                         e |= IP6_MASKEQ(&nat->nat_nsrc6,
7853                                                         x + i + 7, x + i + 3);
7854                                 }
7855                         }
7856                         break;
7857
7858                 case IPF_EXP_IP6_DSTADDR :
7859                         if (nat->nat_v[0] == 6) {
7860                                 for (i = 0; !e && i < x[3]; i++) {
7861                                         e |= IP6_MASKEQ(&nat->nat_odst6,
7862                                                         x + i + 7,
7863                                                         x + i + 3);
7864                                 }
7865                         }
7866                         if (nat->nat_v[1] == 6) {
7867                                 for (i = 0; !e && i < x[3]; i++) {
7868                                         e |= IP6_MASKEQ(&nat->nat_ndst6,
7869                                                         x + i + 7,
7870                                                         x + i + 3);
7871                                 }
7872                         }
7873                         break;
7874
7875                 case IPF_EXP_IP6_ADDR :
7876                         for (i = 0; !e && i < x[3]; i++) {
7877                                 if (nat->nat_v[0] == 6) {
7878                                         e |= IP6_MASKEQ(&nat->nat_osrc6,
7879                                                         x + i + 7,
7880                                                         x + i + 3);
7881                                 }
7882                                 if (nat->nat_v[0] == 6) {
7883                                         e |= IP6_MASKEQ(&nat->nat_odst6,
7884                                                         x + i + 7,
7885                                                         x + i + 3);
7886                                 }
7887                                 if (nat->nat_v[1] == 6) {
7888                                         e |= IP6_MASKEQ(&nat->nat_nsrc6,
7889                                                         x + i + 7,
7890                                                         x + i + 3);
7891                                 }
7892                                 if (nat->nat_v[1] == 6) {
7893                                         e |= IP6_MASKEQ(&nat->nat_ndst6,
7894                                                         x + i + 7,
7895                                                         x + i + 3);
7896                                 }
7897                         }
7898                         break;
7899 #endif
7900
7901                 case IPF_EXP_UDP_PORT :
7902                 case IPF_EXP_TCP_PORT :
7903                         for (i = 0; !e && i < x[2]; i++) {
7904                                 e |= (nat->nat_nsport == x[i + 3]) ||
7905                                      (nat->nat_ndport == x[i + 3]);
7906                         }
7907                         break;
7908
7909                 case IPF_EXP_UDP_SPORT :
7910                 case IPF_EXP_TCP_SPORT :
7911                         for (i = 0; !e && i < x[2]; i++) {
7912                                 e |= (nat->nat_nsport == x[i + 3]);
7913                         }
7914                         break;
7915
7916                 case IPF_EXP_UDP_DPORT :
7917                 case IPF_EXP_TCP_DPORT :
7918                         for (i = 0; !e && i < x[2]; i++) {
7919                                 e |= (nat->nat_ndport == x[i + 3]);
7920                         }
7921                         break;
7922
7923                 case IPF_EXP_TCP_STATE :
7924                         for (i = 0; !e && i < x[2]; i++) {
7925                                 e |= (nat->nat_tcpstate[0] == x[i + 3]) ||
7926                                      (nat->nat_tcpstate[1] == x[i + 3]);
7927                         }
7928                         break;
7929
7930                 case IPF_EXP_IDLE_GT :
7931                         e |= (ticks - nat->nat_touched > x[3]);
7932                         break;
7933                 }
7934                 e ^= x[1];
7935
7936                 if (!e)
7937                         break;
7938         }
7939
7940         return e;
7941 }
7942
7943
7944 /* ------------------------------------------------------------------------ */
7945 /* Function:    ipf_nat_gettable                                            */
7946 /* Returns:     int     - 0 = success, else error                           */
7947 /* Parameters:  softc(I) - pointer to soft context main structure           */
7948 /*              softn(I) - pointer to NAT context structure                 */
7949 /*              data(I)  - pointer to ioctl data                            */
7950 /*                                                                          */
7951 /* This function handles ioctl requests for tables of nat information.      */
7952 /* At present the only table it deals with is the hash bucket statistics.   */
7953 /* ------------------------------------------------------------------------ */
7954 static int
7955 ipf_nat_gettable(softc, softn, data)
7956         ipf_main_softc_t *softc;
7957         ipf_nat_softc_t *softn;
7958         char *data;
7959 {
7960         ipftable_t table;
7961         int error;
7962
7963         error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
7964         if (error != 0)
7965                 return error;
7966
7967         switch (table.ita_type)
7968         {
7969         case IPFTABLE_BUCKETS_NATIN :
7970                 error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
7971                                 table.ita_table,
7972                                 softn->ipf_nat_table_sz * sizeof(u_int));
7973                 break;
7974
7975         case IPFTABLE_BUCKETS_NATOUT :
7976                 error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
7977                                 table.ita_table,
7978                                 softn->ipf_nat_table_sz * sizeof(u_int));
7979                 break;
7980
7981         default :
7982                 IPFERROR(60058);
7983                 return EINVAL;
7984         }
7985
7986         if (error != 0) {
7987                 IPFERROR(60059);
7988                 error = EFAULT;
7989         }
7990         return error;
7991 }
7992
7993
7994 /* ------------------------------------------------------------------------ */
7995 /* Function:    ipf_nat_settimeout                                          */
7996 /* Returns:     int  - 0 = success, else failure                            */
7997 /* Parameters:  softc(I) - pointer to soft context main structure           */
7998 /*              t(I) - pointer to tunable                                   */
7999 /*              p(I) - pointer to new tuning data                           */
8000 /*                                                                          */
8001 /* Apply the timeout change to the NAT timeout queues.                      */
8002 /* ------------------------------------------------------------------------ */
8003 int
8004 ipf_nat_settimeout(softc, t, p)
8005         struct ipf_main_softc_s *softc;
8006         ipftuneable_t *t;
8007         ipftuneval_t *p;
8008 {
8009         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8010
8011         if (!strncmp(t->ipft_name, "tcp_", 4))
8012                 return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq);
8013
8014         if (!strcmp(t->ipft_name, "udp_timeout")) {
8015                 ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int);
8016         } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
8017                 ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int);
8018         } else if (!strcmp(t->ipft_name, "icmp_timeout")) {
8019                 ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int);
8020         } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
8021                 ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int);
8022         } else if (!strcmp(t->ipft_name, "ip_timeout")) {
8023                 ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int);
8024         } else {
8025                 IPFERROR(60062);
8026                 return ESRCH;
8027         }
8028         return 0;
8029 }
8030
8031
8032 /* ------------------------------------------------------------------------ */
8033 /* Function:    ipf_nat_rehash                                              */
8034 /* Returns:     int  - 0 = success, else failure                            */
8035 /* Parameters:  softc(I) - pointer to soft context main structure           */
8036 /*              t(I) - pointer to tunable                                   */
8037 /*              p(I) - pointer to new tuning data                           */
8038 /*                                                                          */
8039 /* To change the size of the basic NAT table, we need to first allocate the */
8040 /* new tables (lest it fails and we've got nowhere to store all of the NAT  */
8041 /* sessions currently active) and then walk through the entire list and     */
8042 /* insert them into the table.  There are two tables here: an inbound one   */
8043 /* and an outbound one.  Each NAT entry goes into each table once.          */
8044 /* ------------------------------------------------------------------------ */
8045 int
8046 ipf_nat_rehash(softc, t, p)
8047         ipf_main_softc_t *softc;
8048         ipftuneable_t *t;
8049         ipftuneval_t *p;
8050 {
8051         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8052         nat_t **newtab[2], *nat, **natp;
8053         u_int *bucketlens[2];
8054         u_int maxbucket;
8055         u_int newsize;
8056         int error;
8057         u_int hv;
8058         int i;
8059
8060         newsize = p->ipftu_int;
8061         /*
8062          * In case there is nothing to do...
8063          */
8064         if (newsize == softn->ipf_nat_table_sz)
8065                 return 0;
8066
8067         newtab[0] = NULL;
8068         newtab[1] = NULL;
8069         bucketlens[0] = NULL;
8070         bucketlens[1] = NULL;
8071         /*
8072          * 4 tables depend on the NAT table size: the inbound looking table,
8073          * the outbound lookup table and the hash chain length for each.
8074          */
8075         KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *));
8076         if (newtab == NULL) {
8077                 error = 60063;
8078                 goto badrehash;
8079         }
8080
8081         KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *));
8082         if (newtab == NULL) {
8083                 error = 60064;
8084                 goto badrehash;
8085         }
8086
8087         KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int));
8088         if (bucketlens[0] == NULL) {
8089                 error = 60065;
8090                 goto badrehash;
8091         }
8092
8093         KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int));
8094         if (bucketlens[1] == NULL) {
8095                 error = 60066;
8096                 goto badrehash;
8097         }
8098
8099         /*
8100          * Recalculate the maximum length based on the new size.
8101          */
8102         for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
8103                 maxbucket++;
8104         maxbucket *= 2;
8105
8106         bzero((char *)newtab[0], newsize * sizeof(nat_t *));
8107         bzero((char *)newtab[1], newsize * sizeof(nat_t *));
8108         bzero((char *)bucketlens[0], newsize * sizeof(u_int));
8109         bzero((char *)bucketlens[1], newsize * sizeof(u_int));
8110
8111         WRITE_ENTER(&softc->ipf_nat);
8112
8113         if (softn->ipf_nat_table[0] != NULL) {
8114                 KFREES(softn->ipf_nat_table[0],
8115                        softn->ipf_nat_table_sz *
8116                        sizeof(*softn->ipf_nat_table[0]));
8117         }
8118         softn->ipf_nat_table[0] = newtab[0];
8119
8120         if (softn->ipf_nat_table[1] != NULL) {
8121                 KFREES(softn->ipf_nat_table[1],
8122                        softn->ipf_nat_table_sz *
8123                        sizeof(*softn->ipf_nat_table[1]));
8124         }
8125         softn->ipf_nat_table[1] = newtab[1];
8126
8127         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
8128                 KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
8129                        softn->ipf_nat_table_sz * sizeof(u_int));
8130         }
8131         softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0];
8132
8133         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
8134                 KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
8135                        softn->ipf_nat_table_sz * sizeof(u_int));
8136         }
8137         softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1];
8138
8139 #ifdef USE_INET6
8140         if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) {
8141                 KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen,
8142                        softn->ipf_nat_table_sz * sizeof(u_int));
8143         }
8144         softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0];
8145
8146         if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) {
8147                 KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen,
8148                        softn->ipf_nat_table_sz * sizeof(u_int));
8149         }
8150         softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1];
8151 #endif
8152
8153         softn->ipf_nat_maxbucket = maxbucket;
8154         softn->ipf_nat_table_sz = newsize;
8155         /*
8156          * Walk through the entire list of NAT table entries and put them
8157          * in the new NAT table, somewhere.  Because we have a new table,
8158          * we need to restart the counter of how many chains are in use.
8159          */
8160         softn->ipf_nat_stats.ns_side[0].ns_inuse = 0;
8161         softn->ipf_nat_stats.ns_side[1].ns_inuse = 0;
8162 #ifdef USE_INET6
8163         softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0;
8164         softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0;
8165 #endif
8166
8167         for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) {
8168                 nat->nat_hnext[0] = NULL;
8169                 nat->nat_phnext[0] = NULL;
8170                 hv = nat->nat_hv[0] % softn->ipf_nat_table_sz;
8171
8172                 natp = &softn->ipf_nat_table[0][hv];
8173                 if (*natp) {
8174                         (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
8175                 } else {
8176                         NBUMPSIDE(0, ns_inuse);
8177                 }
8178                 nat->nat_phnext[0] = natp;
8179                 nat->nat_hnext[0] = *natp;
8180                 *natp = nat;
8181                 NBUMPSIDE(0, ns_bucketlen[hv]);
8182
8183                 nat->nat_hnext[1] = NULL;
8184                 nat->nat_phnext[1] = NULL;
8185                 hv = nat->nat_hv[1] % softn->ipf_nat_table_sz;
8186
8187                 natp = &softn->ipf_nat_table[1][hv];
8188                 if (*natp) {
8189                         (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
8190                 } else {
8191                         NBUMPSIDE(1, ns_inuse);
8192                 }
8193                 nat->nat_phnext[1] = natp;
8194                 nat->nat_hnext[1] = *natp;
8195                 *natp = nat;
8196                 NBUMPSIDE(1, ns_bucketlen[hv]);
8197         }
8198         RWLOCK_EXIT(&softc->ipf_nat);
8199
8200         return 0;
8201
8202 badrehash:
8203         if (bucketlens[1] != NULL) {
8204                 KFREES(bucketlens[0], newsize * sizeof(u_int));
8205         }
8206         if (bucketlens[0] != NULL) {
8207                 KFREES(bucketlens[0], newsize * sizeof(u_int));
8208         }
8209         if (newtab[0] != NULL) {
8210                 KFREES(newtab[0], newsize * sizeof(nat_t *));
8211         }
8212         if (newtab[1] != NULL) {
8213                 KFREES(newtab[1], newsize * sizeof(nat_t *));
8214         }
8215         IPFERROR(error);
8216         return ENOMEM;
8217 }
8218
8219
8220 /* ------------------------------------------------------------------------ */
8221 /* Function:    ipf_nat_rehash_rules                                        */
8222 /* Returns:     int  - 0 = success, else failure                            */
8223 /* Parameters:  softc(I) - pointer to soft context main structure           */
8224 /*              t(I) - pointer to tunable                                   */
8225 /*              p(I) - pointer to new tuning data                           */
8226 /*                                                                          */
8227 /* All of the NAT rules hang off of a hash table that is searched with a    */
8228 /* hash on address after the netmask is applied.  There is a different table*/
8229 /* for both inbound rules (rdr) and outbound (map.)  The resizing will only */
8230 /* affect one of these two tables.                                          */
8231 /* ------------------------------------------------------------------------ */
8232 int
8233 ipf_nat_rehash_rules(softc, t, p)
8234         ipf_main_softc_t *softc;
8235         ipftuneable_t *t;
8236         ipftuneval_t *p;
8237 {
8238         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8239         ipnat_t **newtab, *np, ***old, **npp;
8240         u_int newsize;
8241         u_int mask;
8242         u_int hv;
8243
8244         newsize = p->ipftu_int;
8245         /*
8246          * In case there is nothing to do...
8247          */
8248         if (newsize == *t->ipft_pint)
8249                 return 0;
8250
8251         /*
8252          * All inbound rules have the NAT_REDIRECT bit set in in_redir and
8253          * all outbound rules have either NAT_MAP or MAT_MAPBLK set.
8254          * This if statement allows for some more generic code to be below,
8255          * rather than two huge gobs of code that almost do the same thing.
8256          */
8257         if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) {
8258                 old = &softn->ipf_nat_rdr_rules;
8259                 mask = NAT_REDIRECT;
8260         } else {
8261                 old = &softn->ipf_nat_map_rules;
8262                 mask = NAT_MAP|NAT_MAPBLK;
8263         }
8264
8265         KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *));
8266         if (newtab == NULL) {
8267                 IPFERROR(60067);
8268                 return ENOMEM;
8269         }
8270
8271         bzero((char *)newtab, newsize * sizeof(ipnat_t *));
8272
8273         WRITE_ENTER(&softc->ipf_nat);
8274
8275         if (*old != NULL) {
8276                 KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **));
8277         }
8278         *old = newtab;
8279         *t->ipft_pint = newsize;
8280
8281         for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) {
8282                 if ((np->in_redir & mask) == 0)
8283                         continue;
8284
8285                 if (np->in_redir & NAT_REDIRECT) {
8286                         np->in_rnext = NULL;
8287                         hv = np->in_hv[0] % newsize;
8288                         for (npp = newtab + hv; *npp != NULL; )
8289                                 npp = &(*npp)->in_rnext;
8290                         np->in_prnext = npp;
8291                         *npp = np;
8292                 }
8293                 if (np->in_redir & NAT_MAP) {
8294                         np->in_mnext = NULL;
8295                         hv = np->in_hv[1] % newsize;
8296                         for (npp = newtab + hv; *npp != NULL; )
8297                                 npp = &(*npp)->in_mnext;
8298                         np->in_pmnext = npp;
8299                         *npp = np;
8300                 }
8301
8302         }
8303         RWLOCK_EXIT(&softc->ipf_nat);
8304
8305         return 0;
8306 }
8307
8308
8309 /* ------------------------------------------------------------------------ */
8310 /* Function:    ipf_nat_hostmap_rehash                                      */
8311 /* Returns:     int  - 0 = success, else failure                            */
8312 /* Parameters:  softc(I) - pointer to soft context main structure           */
8313 /*              t(I) - pointer to tunable                                   */
8314 /*              p(I) - pointer to new tuning data                           */
8315 /*                                                                          */
8316 /* Allocate and populate a new hash table that will contain a reference to  */
8317 /* all of the active IP# translations currently in place.                   */
8318 /* ------------------------------------------------------------------------ */
8319 int
8320 ipf_nat_hostmap_rehash(softc, t, p)
8321         ipf_main_softc_t *softc;
8322         ipftuneable_t *t;
8323         ipftuneval_t *p;
8324 {
8325         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8326         hostmap_t *hm, **newtab;
8327         u_int newsize;
8328         u_int hv;
8329
8330         newsize = p->ipftu_int;
8331         /*
8332          * In case there is nothing to do...
8333          */
8334         if (newsize == *t->ipft_pint)
8335                 return 0;
8336
8337         KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *));
8338         if (newtab == NULL) {
8339                 IPFERROR(60068);
8340                 return ENOMEM;
8341         }
8342
8343         bzero((char *)newtab, newsize * sizeof(hostmap_t *));
8344
8345         WRITE_ENTER(&softc->ipf_nat);
8346         if (softn->ipf_hm_maptable != NULL) {
8347                 KFREES(softn->ipf_hm_maptable,
8348                        softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *));
8349         }
8350         softn->ipf_hm_maptable = newtab;
8351         softn->ipf_nat_hostmap_sz = newsize;
8352
8353         for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) {
8354                 hv = hm->hm_hv % softn->ipf_nat_hostmap_sz;
8355                 hm->hm_hnext = softn->ipf_hm_maptable[hv];
8356                 hm->hm_phnext = softn->ipf_hm_maptable + hv;
8357                 if (softn->ipf_hm_maptable[hv] != NULL)
8358                         softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
8359                 softn->ipf_hm_maptable[hv] = hm;
8360         }
8361         RWLOCK_EXIT(&softc->ipf_nat);
8362
8363         return 0;
8364 }
8365
8366
8367 /* ------------------------------------------------------------------------ */
8368 /* Function:    ipf_nat_add_tq                                              */
8369 /* Parameters:  softc(I) - pointer to soft context main structure           */
8370 /*                                                                          */
8371 /* ------------------------------------------------------------------------ */
8372 ipftq_t *
8373 ipf_nat_add_tq(softc, ttl)
8374         ipf_main_softc_t *softc;
8375         int ttl;
8376 {
8377         ipf_nat_softc_t *softs = softc->ipf_nat_soft;
8378
8379         return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl);
8380 }
8381
8382 /* ------------------------------------------------------------------------ */
8383 /* Function:    ipf_nat_uncreate                                            */
8384 /* Returns:     Nil                                                         */
8385 /* Parameters:  fin(I) - pointer to packet information                      */
8386 /*                                                                          */
8387 /* This function is used to remove a NAT entry from the NAT table when we   */
8388 /* decide that the create was actually in error. It is thus assumed that    */
8389 /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
8390 /* with the translated packet (not the original), we have to reverse the    */
8391 /* lookup. Although doing the lookup is expensive (relatively speaking), it */
8392 /* is not anticipated that this will be a frequent occurance for normal     */
8393 /* traffic patterns.                                                        */
8394 /* ------------------------------------------------------------------------ */
8395 void
8396 ipf_nat_uncreate(fin)
8397         fr_info_t *fin;
8398 {
8399         ipf_main_softc_t *softc = fin->fin_main_soft;
8400         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8401         int nflags;
8402         nat_t *nat;
8403
8404         switch (fin->fin_p)
8405         {
8406         case IPPROTO_TCP :
8407                 nflags = IPN_TCP;
8408                 break;
8409         case IPPROTO_UDP :
8410                 nflags = IPN_UDP;
8411                 break;
8412         default :
8413                 nflags = 0;
8414                 break;
8415         }
8416
8417         WRITE_ENTER(&softc->ipf_nat);
8418
8419         if (fin->fin_out == 0) {
8420                 nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
8421                                         fin->fin_dst, fin->fin_src);
8422         } else {
8423                 nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
8424                                        fin->fin_src, fin->fin_dst);
8425         }
8426
8427         if (nat != NULL) {
8428                 NBUMPSIDE(fin->fin_out, ns_uncreate[0]);
8429                 ipf_nat_delete(softc, nat, NL_DESTROY);
8430         } else {
8431                 NBUMPSIDE(fin->fin_out, ns_uncreate[1]);
8432         }
8433
8434         RWLOCK_EXIT(&softc->ipf_nat);
8435 }
8436
8437
8438 /* ------------------------------------------------------------------------ */
8439 /* Function:    ipf_nat_cmp_rules                                           */
8440 /* Returns:     int   - 0 == success, else rules do not match.              */
8441 /* Parameters:  n1(I) - first rule to compare                               */
8442 /*              n2(I) - first rule to compare                               */
8443 /*                                                                          */
8444 /* Compare two rules using pointers to each rule. A straight bcmp will not  */
8445 /* work as some fields (such as in_dst, in_pkts) actually do change once    */
8446 /* the rule has been loaded into the kernel. Whilst this function returns   */
8447 /* various non-zero returns, they're strictly to aid in debugging. Use of   */
8448 /* this function should simply care if the result is zero or not.           */
8449 /* ------------------------------------------------------------------------ */
8450 static int
8451 ipf_nat_cmp_rules(n1, n2)
8452         ipnat_t *n1, *n2;
8453 {
8454         if (n1->in_size != n2->in_size)
8455                 return 1;
8456
8457         if (bcmp((char *)&n1->in_v, (char *)&n2->in_v,
8458                  offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0)
8459                 return 2;
8460
8461         if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc,
8462                  n1->in_size - offsetof(ipnat_t, in_tuc)) != 0)
8463                 return 3;
8464         if (n1->in_ndst.na_atype != n2->in_ndst.na_atype)
8465                 return 5;
8466         if (n1->in_ndst.na_function != n2->in_ndst.na_function)
8467                 return 6;
8468         if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr,
8469                  sizeof(n1->in_ndst.na_addr)))
8470                 return 7;
8471         if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype)
8472                 return 8;
8473         if (n1->in_nsrc.na_function != n2->in_nsrc.na_function)
8474                 return 9;
8475         if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr,
8476                  sizeof(n1->in_nsrc.na_addr)))
8477                 return 10;
8478         if (n1->in_odst.na_atype != n2->in_odst.na_atype)
8479                 return 11;
8480         if (n1->in_odst.na_function != n2->in_odst.na_function)
8481                 return 12;
8482         if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr,
8483                  sizeof(n1->in_odst.na_addr)))
8484                 return 13;
8485         if (n1->in_osrc.na_atype != n2->in_osrc.na_atype)
8486                 return 14;
8487         if (n1->in_osrc.na_function != n2->in_osrc.na_function)
8488                 return 15;
8489         if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr,
8490                  sizeof(n1->in_osrc.na_addr)))
8491                 return 16;
8492         return 0;
8493 }
8494
8495
8496 /* ------------------------------------------------------------------------ */
8497 /* Function:    ipf_nat_rule_init                                           */
8498 /* Returns:     int   - 0 == success, else rules do not match.              */
8499 /* Parameters:  softc(I) - pointer to soft context main structure           */
8500 /*              softn(I) - pointer to NAT context structure                 */
8501 /*              n(I)     - first rule to compare                            */
8502 /*                                                                          */
8503 /* ------------------------------------------------------------------------ */
8504 static int
8505 ipf_nat_rule_init(softc, softn, n)
8506         ipf_main_softc_t *softc;
8507         ipf_nat_softc_t *softn;
8508         ipnat_t *n;
8509 {
8510         int error = 0;
8511
8512         if ((n->in_flags & IPN_SIPRANGE) != 0)
8513                 n->in_nsrcatype = FRI_RANGE;
8514
8515         if ((n->in_flags & IPN_DIPRANGE) != 0)
8516                 n->in_ndstatype = FRI_RANGE;
8517
8518         if ((n->in_flags & IPN_SPLIT) != 0)
8519                 n->in_ndstatype = FRI_SPLIT;
8520
8521         if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0)
8522                 n->in_spnext = n->in_spmin;
8523
8524         if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) {
8525                 n->in_dpnext = n->in_dpmin;
8526         } else if (n->in_redir == NAT_REDIRECT) {
8527                 n->in_dpnext = n->in_dpmin;
8528         }
8529
8530         n->in_stepnext = 0;
8531
8532         switch (n->in_v[0])
8533         {
8534         case 4 :
8535                 error = ipf_nat_ruleaddrinit(softc, softn, n);
8536                 if (error != 0)
8537                         return error;
8538                 break;
8539 #ifdef USE_INET6
8540         case 6 :
8541                 error = ipf_nat6_ruleaddrinit(softc, softn, n);
8542                 if (error != 0)
8543                         return error;
8544                 break;
8545 #endif
8546         default :
8547                 break;
8548         }
8549
8550         if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
8551                 /*
8552                  * Prerecord whether or not the destination of the divert
8553                  * is local or not to the interface the packet is going
8554                  * to be sent out.
8555                  */
8556                 n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
8557                                                 n->in_ifps[1], &n->in_ndstip6);
8558         }
8559
8560         return error;
8561 }
8562
8563
8564 /* ------------------------------------------------------------------------ */
8565 /* Function:    ipf_nat_rule_fini                                           */
8566 /* Returns:     int   - 0 == success, else rules do not match.              */
8567 /* Parameters:  softc(I) - pointer to soft context main structure           */
8568 /*              n(I)     - rule to work on                                  */
8569 /*                                                                          */
8570 /* This function is used to release any objects that were referenced during */
8571 /* the rule initialisation. This is useful both when free'ing the rule and  */
8572 /* when handling ioctls that need to initialise these fields but not        */
8573 /* actually use them after the ioctl processing has finished.               */
8574 /* ------------------------------------------------------------------------ */
8575 static void
8576 ipf_nat_rule_fini(softc, n)
8577         ipf_main_softc_t *softc;
8578         ipnat_t *n;
8579 {
8580         if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL)
8581                 ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr);
8582
8583         if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL)
8584                 ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr);
8585
8586         if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL)
8587                 ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr);
8588
8589         if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL)
8590                 ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr);
8591
8592         if (n->in_divmp != NULL)
8593                 FREE_MB_T(n->in_divmp);
8594 }