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