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