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