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