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