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