| @@ -1,1114 +1,1114 @@ | | | @@ -1,1114 +1,1114 @@ |
1 | /* $NetBSD: ip_nat.c,v 1.23 2020/08/01 06:50:42 maxv Exp $ */ | | 1 | /* $NetBSD: ip_nat.c,v 1.24 2021/05/26 14:48:02 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (C) 2012 by Darren Reed. | | 4 | * Copyright (C) 2012 by Darren Reed. |
5 | * | | 5 | * |
6 | * See the IPFILTER.LICENCE file for details on licencing. | | 6 | * See the IPFILTER.LICENCE file for details on licencing. |
7 | */ | | 7 | */ |
8 | #if defined(KERNEL) || defined(_KERNEL) | | 8 | #if defined(KERNEL) || defined(_KERNEL) |
9 | # undef KERNEL | | 9 | # undef KERNEL |
10 | # undef KERNEL | | 10 | # undef KERNEL |
11 | # define KERNEL 1 | | 11 | # define KERNEL 1 |
12 | # define KERNEL 1 | | 12 | # define KERNEL 1 |
13 | #endif | | 13 | #endif |
14 | #include <sys/errno.h> | | 14 | #include <sys/errno.h> |
15 | #include <sys/types.h> | | 15 | #include <sys/types.h> |
16 | #include <sys/param.h> | | 16 | #include <sys/param.h> |
17 | #include <sys/time.h> | | 17 | #include <sys/time.h> |
18 | #include <sys/file.h> | | 18 | #include <sys/file.h> |
19 | #if defined(_KERNEL) && \ | | 19 | #if defined(_KERNEL) && \ |
20 | (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000)) | | 20 | (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000)) |
21 | # include <sys/kauth.h> | | 21 | # include <sys/kauth.h> |
22 | #endif | | 22 | #endif |
23 | #if !defined(_KERNEL) | | 23 | #if !defined(_KERNEL) |
24 | # include <stdio.h> | | 24 | # include <stdio.h> |
25 | # include <string.h> | | 25 | # include <string.h> |
26 | # include <stdlib.h> | | 26 | # include <stdlib.h> |
27 | # define KERNEL | | 27 | # define KERNEL |
28 | # ifdef _OpenBSD__ | | 28 | # ifdef _OpenBSD__ |
29 | struct file; | | 29 | struct file; |
30 | # endif | | 30 | # endif |
31 | # include <sys/uio.h> | | 31 | # include <sys/uio.h> |
32 | # undef KERNEL | | 32 | # undef KERNEL |
33 | #endif | | 33 | #endif |
34 | #if defined(_KERNEL) && \ | | 34 | #if defined(_KERNEL) && \ |
35 | defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) | | 35 | defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) |
36 | # include <sys/filio.h> | | 36 | # include <sys/filio.h> |
37 | # include <sys/fcntl.h> | | 37 | # include <sys/fcntl.h> |
38 | #else | | 38 | #else |
39 | # include <sys/ioctl.h> | | 39 | # include <sys/ioctl.h> |
40 | #endif | | 40 | #endif |
41 | #if !defined(AIX) | | 41 | #if !defined(AIX) |
42 | # include <sys/fcntl.h> | | 42 | # include <sys/fcntl.h> |
43 | #endif | | 43 | #endif |
44 | #if !defined(linux) | | 44 | #if !defined(linux) |
45 | # include <sys/protosw.h> | | 45 | # include <sys/protosw.h> |
46 | #endif | | 46 | #endif |
47 | #include <sys/socket.h> | | 47 | #include <sys/socket.h> |
48 | #if defined(_KERNEL) | | 48 | #if defined(_KERNEL) |
49 | # include <sys/systm.h> | | 49 | # include <sys/systm.h> |
50 | # if !defined(__SVR4) && !defined(__svr4__) | | 50 | # if !defined(__SVR4) && !defined(__svr4__) |
51 | # include <sys/mbuf.h> | | 51 | # include <sys/mbuf.h> |
52 | # endif | | 52 | # endif |
53 | #endif | | 53 | #endif |
54 | #if defined(__SVR4) || defined(__svr4__) | | 54 | #if defined(__SVR4) || defined(__svr4__) |
55 | # include <sys/filio.h> | | 55 | # include <sys/filio.h> |
56 | # include <sys/byteorder.h> | | 56 | # include <sys/byteorder.h> |
57 | # ifdef KERNEL | | 57 | # ifdef KERNEL |
58 | # include <sys/dditypes.h> | | 58 | # include <sys/dditypes.h> |
59 | # endif | | 59 | # endif |
60 | # include <sys/stream.h> | | 60 | # include <sys/stream.h> |
61 | # include <sys/kmem.h> | | 61 | # include <sys/kmem.h> |
62 | #endif | | 62 | #endif |
63 | #if _FreeBSD_version >= 300000 | | 63 | #if _FreeBSD_version >= 300000 |
64 | # include <sys/queue.h> | | 64 | # include <sys/queue.h> |
65 | #endif | | 65 | #endif |
66 | #include <net/if.h> | | 66 | #include <net/if.h> |
67 | #if _FreeBSD_version >= 300000 | | 67 | #if _FreeBSD_version >= 300000 |
68 | # include <net/if_var.h> | | 68 | # include <net/if_var.h> |
69 | #endif | | 69 | #endif |
70 | #ifdef sun | | 70 | #ifdef sun |
71 | # include <net/af.h> | | 71 | # include <net/af.h> |
72 | #endif | | 72 | #endif |
73 | #include <netinet/in.h> | | 73 | #include <netinet/in.h> |
74 | #include <netinet/in_systm.h> | | 74 | #include <netinet/in_systm.h> |
75 | #include <netinet/ip.h> | | 75 | #include <netinet/ip.h> |
76 | | | 76 | |
77 | #ifdef RFC1825 | | 77 | #ifdef RFC1825 |
78 | # include <vpn/md5.h> | | 78 | # include <vpn/md5.h> |
79 | # include <vpn/ipsec.h> | | 79 | # include <vpn/ipsec.h> |
80 | extern struct ifnet vpnif; | | 80 | extern struct ifnet vpnif; |
81 | #endif | | 81 | #endif |
82 | | | 82 | |
83 | #if !defined(linux) | | 83 | #if !defined(linux) |
84 | # include <netinet/ip_var.h> | | 84 | # include <netinet/ip_var.h> |
85 | #endif | | 85 | #endif |
86 | #include <netinet/tcp.h> | | 86 | #include <netinet/tcp.h> |
87 | #include <netinet/udp.h> | | 87 | #include <netinet/udp.h> |
88 | #include <netinet/ip_icmp.h> | | 88 | #include <netinet/ip_icmp.h> |
89 | #include "netinet/ip_compat.h" | | 89 | #include "netinet/ip_compat.h" |
90 | #include "netinet/ipl.h" | | 90 | #include "netinet/ipl.h" |
91 | #include "netinet/ip_fil.h" | | 91 | #include "netinet/ip_fil.h" |
92 | #include "netinet/ip_nat.h" | | 92 | #include "netinet/ip_nat.h" |
93 | #include "netinet/ip_frag.h" | | 93 | #include "netinet/ip_frag.h" |
94 | #include "netinet/ip_state.h" | | 94 | #include "netinet/ip_state.h" |
95 | #include "netinet/ip_proxy.h" | | 95 | #include "netinet/ip_proxy.h" |
96 | #include "netinet/ip_lookup.h" | | 96 | #include "netinet/ip_lookup.h" |
97 | #include "netinet/ip_dstlist.h" | | 97 | #include "netinet/ip_dstlist.h" |
98 | #include "netinet/ip_sync.h" | | 98 | #include "netinet/ip_sync.h" |
99 | #if FREEBSD_GE_REV(300000) | | 99 | #if FREEBSD_GE_REV(300000) |
100 | # include <sys/malloc.h> | | 100 | # include <sys/malloc.h> |
101 | #endif | | 101 | #endif |
102 | #ifdef HAS_SYS_MD5_H | | 102 | #ifdef HAS_SYS_MD5_H |
103 | # include <sys/md5.h> | | 103 | # include <sys/md5.h> |
104 | #else | | 104 | #else |
105 | # include "md5.h" | | 105 | # include "md5.h" |
106 | #endif | | 106 | #endif |
107 | /* END OF INCLUDES */ | | 107 | /* END OF INCLUDES */ |
108 | | | 108 | |
109 | #undef SOCKADDR_IN | | 109 | #undef SOCKADDR_IN |
110 | #define SOCKADDR_IN struct sockaddr_in | | 110 | #define SOCKADDR_IN struct sockaddr_in |
111 | | | 111 | |
112 | #if !defined(lint) | | 112 | #if !defined(lint) |
113 | #if defined(__NetBSD__) | | 113 | #if defined(__NetBSD__) |
114 | #include <sys/cdefs.h> | | 114 | #include <sys/cdefs.h> |
115 | __KERNEL_RCSID(0, "$NetBSD: ip_nat.c,v 1.23 2020/08/01 06:50:42 maxv Exp $"); | | 115 | __KERNEL_RCSID(0, "$NetBSD: ip_nat.c,v 1.24 2021/05/26 14:48:02 christos Exp $"); |
116 | #else | | 116 | #else |
117 | static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; | | 117 | static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; |
118 | static const char rcsid[] = "@(#)Id: ip_nat.c,v 1.1.1.2 2012/07/22 13:45:27 darrenr Exp"; | | 118 | static const char rcsid[] = "@(#)Id: ip_nat.c,v 1.1.1.2 2012/07/22 13:45:27 darrenr Exp"; |
119 | #endif | | 119 | #endif |
120 | #endif | | 120 | #endif |
121 | | | 121 | |
122 | | | 122 | |
123 | #define NATFSUM(n,v,f) ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \ | | 123 | #define NATFSUM(n,v,f) ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \ |
124 | (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3]) | | 124 | (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3]) |
125 | #define NBUMP(x) softn->(x)++ | | 125 | #define NBUMP(x) softn->(x)++ |
126 | #define NBUMPD(x, y) do { \ | | 126 | #define NBUMPD(x, y) do { \ |
127 | softn->x.y++; \ | | 127 | softn->x.y++; \ |
128 | DT(y); \ | | 128 | DT(y); \ |
129 | } while (0) | | 129 | } while (0) |
130 | #define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++ | | 130 | #define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++ |
131 | #define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \ | | 131 | #define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \ |
132 | DT(x); } while (0) | | 132 | DT(x); } while (0) |
133 | #define NBUMPSIDEX(y,x,z) \ | | 133 | #define NBUMPSIDEX(y,x,z) \ |
134 | do { softn->ipf_nat_stats.ns_side[y].x++; \ | | 134 | do { softn->ipf_nat_stats.ns_side[y].x++; \ |
135 | DT(z); } while (0) | | 135 | DT(z); } while (0) |
136 | #define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \ | | 136 | #define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \ |
137 | DT1(x, fr_info_t *, fin); } while (0) | | 137 | DT1(x, fr_info_t *, fin); } while (0) |
138 | | | 138 | |
139 | frentry_t ipfnatblock; | | 139 | frentry_t ipfnatblock; |
140 | | | 140 | |
141 | static const ipftuneable_t ipf_nat_tuneables[] = { | | 141 | static const ipftuneable_t ipf_nat_tuneables[] = { |
142 | /* nat */ | | 142 | /* nat */ |
143 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) }, | | 143 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) }, |
144 | "nat_lock", 0, 1, | | 144 | "nat_lock", 0, 1, |
145 | stsizeof(ipf_nat_softc_t, ipf_nat_lock), | | 145 | stsizeof(ipf_nat_softc_t, ipf_nat_lock), |
146 | IPFT_RDONLY, NULL, NULL }, | | 146 | IPFT_RDONLY, NULL, NULL }, |
147 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) }, | | 147 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) }, |
148 | "nat_table_size", 1, 0x7fffffff, | | 148 | "nat_table_size", 1, 0x7fffffff, |
149 | stsizeof(ipf_nat_softc_t, ipf_nat_table_sz), | | 149 | stsizeof(ipf_nat_softc_t, ipf_nat_table_sz), |
150 | 0, NULL, ipf_nat_rehash }, | | 150 | 0, NULL, ipf_nat_rehash }, |
151 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) }, | | 151 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) }, |
152 | "nat_table_max", 1, 0x7fffffff, | | 152 | "nat_table_max", 1, 0x7fffffff, |
153 | stsizeof(ipf_nat_softc_t, ipf_nat_table_max), | | 153 | stsizeof(ipf_nat_softc_t, ipf_nat_table_max), |
154 | 0, NULL, NULL }, | | 154 | 0, NULL, NULL }, |
155 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) }, | | 155 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) }, |
156 | "nat_rules_size", 1, 0x7fffffff, | | 156 | "nat_rules_size", 1, 0x7fffffff, |
157 | stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz), | | 157 | stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz), |
158 | 0, NULL, ipf_nat_rehash_rules }, | | 158 | 0, NULL, ipf_nat_rehash_rules }, |
159 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) }, | | 159 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) }, |
160 | "rdr_rules_size", 1, 0x7fffffff, | | 160 | "rdr_rules_size", 1, 0x7fffffff, |
161 | stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz), | | 161 | stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz), |
162 | 0, NULL, ipf_nat_rehash_rules }, | | 162 | 0, NULL, ipf_nat_rehash_rules }, |
163 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) }, | | 163 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) }, |
164 | "hostmap_size", 1, 0x7fffffff, | | 164 | "hostmap_size", 1, 0x7fffffff, |
165 | stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz), | | 165 | stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz), |
166 | 0, NULL, ipf_nat_hostmap_rehash }, | | 166 | 0, NULL, ipf_nat_hostmap_rehash }, |
167 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) }, | | 167 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) }, |
168 | "nat_maxbucket",1, 0x7fffffff, | | 168 | "nat_maxbucket",1, 0x7fffffff, |
169 | stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket), | | 169 | stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket), |
170 | 0, NULL, NULL }, | | 170 | 0, NULL, NULL }, |
171 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) }, | | 171 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) }, |
172 | "nat_logging", 0, 1, | | 172 | "nat_logging", 0, 1, |
173 | stsizeof(ipf_nat_softc_t, ipf_nat_logging), | | 173 | stsizeof(ipf_nat_softc_t, ipf_nat_logging), |
174 | 0, NULL, NULL }, | | 174 | 0, NULL, NULL }, |
175 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) }, | | 175 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) }, |
176 | "nat_doflush", 0, 1, | | 176 | "nat_doflush", 0, 1, |
177 | stsizeof(ipf_nat_softc_t, ipf_nat_doflush), | | 177 | stsizeof(ipf_nat_softc_t, ipf_nat_doflush), |
178 | 0, NULL, NULL }, | | 178 | 0, NULL, NULL }, |
179 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) }, | | 179 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) }, |
180 | "nat_table_wm_low", 1, 99, | | 180 | "nat_table_wm_low", 1, 99, |
181 | stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low), | | 181 | stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low), |
182 | 0, NULL, NULL }, | | 182 | 0, NULL, NULL }, |
183 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) }, | | 183 | { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) }, |
184 | "nat_table_wm_high", 2, 100, | | 184 | "nat_table_wm_high", 2, 100, |
185 | stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high), | | 185 | stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high), |
186 | 0, NULL, NULL }, | | 186 | 0, NULL, NULL }, |
187 | { { 0 }, | | 187 | { { 0 }, |
188 | NULL, 0, 0, | | 188 | NULL, 0, 0, |
189 | 0, | | 189 | 0, |
190 | 0, NULL, NULL } | | 190 | 0, NULL, NULL } |
191 | }; | | 191 | }; |
192 | | | 192 | |
193 | /* ======================================================================== */ | | 193 | /* ======================================================================== */ |
194 | /* How the NAT is organised and works. */ | | 194 | /* How the NAT is organised and works. */ |
195 | /* */ | | 195 | /* */ |
196 | /* Inside (interface y) NAT Outside (interface x) */ | | 196 | /* Inside (interface y) NAT Outside (interface x) */ |
197 | /* -------------------- -+- ------------------------------------- */ | | 197 | /* -------------------- -+- ------------------------------------- */ |
198 | /* Packet going | out, processsed by ipf_nat_checkout() for x */ | | 198 | /* Packet going | out, processsed by ipf_nat_checkout() for x */ |
199 | /* ------------> | ------------> */ | | 199 | /* ------------> | ------------> */ |
200 | /* src=10.1.1.1 | src=192.1.1.1 */ | | 200 | /* src=10.1.1.1 | src=192.1.1.1 */ |
201 | /* | */ | | 201 | /* | */ |
202 | /* | in, processed by ipf_nat_checkin() for x */ | | 202 | /* | in, processed by ipf_nat_checkin() for x */ |
203 | /* <------------ | <------------ */ | | 203 | /* <------------ | <------------ */ |
204 | /* dst=10.1.1.1 | dst=192.1.1.1 */ | | 204 | /* dst=10.1.1.1 | dst=192.1.1.1 */ |
205 | /* -------------------- -+- ------------------------------------- */ | | 205 | /* -------------------- -+- ------------------------------------- */ |
206 | /* ipf_nat_checkout() - changes ip_src and if required, sport */ | | 206 | /* ipf_nat_checkout() - changes ip_src and if required, sport */ |
207 | /* - creates a new mapping, if required. */ | | 207 | /* - creates a new mapping, if required. */ |
208 | /* ipf_nat_checkin() - changes ip_dst and if required, dport */ | | 208 | /* ipf_nat_checkin() - changes ip_dst and if required, dport */ |
209 | /* */ | | 209 | /* */ |
210 | /* In the NAT table, internal source is recorded as "in" and externally */ | | 210 | /* In the NAT table, internal source is recorded as "in" and externally */ |
211 | /* seen as "out". */ | | 211 | /* seen as "out". */ |
212 | /* ======================================================================== */ | | 212 | /* ======================================================================== */ |
213 | | | 213 | |
214 | | | 214 | |
215 | #if SOLARIS && !defined(INSTANCES) | | 215 | #if SOLARIS && !defined(INSTANCES) |
216 | extern int pfil_delayed_copy; | | 216 | extern int pfil_delayed_copy; |
217 | #endif | | 217 | #endif |
218 | | | 218 | |
219 | static int ipf_nat_flush_entry(ipf_main_softc_t *, void *); | | 219 | static int ipf_nat_flush_entry(ipf_main_softc_t *, void *); |
220 | static int ipf_nat_getent(ipf_main_softc_t *, void *, int); | | 220 | static int ipf_nat_getent(ipf_main_softc_t *, void *, int); |
221 | static int ipf_nat_getsz(ipf_main_softc_t *, void *, int); | | 221 | static int ipf_nat_getsz(ipf_main_softc_t *, void *, int); |
222 | static int ipf_nat_putent(ipf_main_softc_t *, void *, int); | | 222 | static int ipf_nat_putent(ipf_main_softc_t *, void *, int); |
223 | static void ipf_nat_addmap(ipf_nat_softc_t *, ipnat_t *); | | 223 | static void ipf_nat_addmap(ipf_nat_softc_t *, ipnat_t *); |
224 | static void ipf_nat_addrdr(ipf_nat_softc_t *, ipnat_t *); | | 224 | static void ipf_nat_addrdr(ipf_nat_softc_t *, ipnat_t *); |
225 | static int ipf_nat_builddivertmp(ipf_nat_softc_t *, ipnat_t *); | | 225 | static int ipf_nat_builddivertmp(ipf_nat_softc_t *, ipnat_t *); |
226 | static int ipf_nat_clearlist(ipf_main_softc_t *, ipf_nat_softc_t *); | | 226 | static int ipf_nat_clearlist(ipf_main_softc_t *, ipf_nat_softc_t *); |
227 | static int ipf_nat_cmp_rules(ipnat_t *, ipnat_t *); | | 227 | static int ipf_nat_cmp_rules(ipnat_t *, ipnat_t *); |
228 | static int ipf_nat_decap(fr_info_t *, nat_t *); | | 228 | static int ipf_nat_decap(fr_info_t *, nat_t *); |
229 | static void ipf_nat_delrule(ipf_main_softc_t *, ipf_nat_softc_t *, | | 229 | static void ipf_nat_delrule(ipf_main_softc_t *, ipf_nat_softc_t *, |
230 | ipnat_t *, int); | | 230 | ipnat_t *, int); |
231 | static int ipf_nat_extraflush(ipf_main_softc_t *, ipf_nat_softc_t *, int); | | 231 | static int ipf_nat_extraflush(ipf_main_softc_t *, ipf_nat_softc_t *, int); |
232 | static int ipf_nat_finalise(fr_info_t *, nat_t *); | | 232 | static int ipf_nat_finalise(fr_info_t *, nat_t *); |
233 | static int ipf_nat_flushtable(ipf_main_softc_t *, ipf_nat_softc_t *); | | 233 | static int ipf_nat_flushtable(ipf_main_softc_t *, ipf_nat_softc_t *); |
234 | static int ipf_nat_getnext(ipf_main_softc_t *, ipftoken_t *, | | 234 | static int ipf_nat_getnext(ipf_main_softc_t *, ipftoken_t *, |
235 | ipfgeniter_t *, ipfobj_t *); | | 235 | ipfgeniter_t *, ipfobj_t *); |
236 | static int ipf_nat_gettable(ipf_main_softc_t *, ipf_nat_softc_t *, char *); | | 236 | static int ipf_nat_gettable(ipf_main_softc_t *, ipf_nat_softc_t *, char *); |
237 | static hostmap_t *ipf_nat_hostmap(ipf_nat_softc_t *, ipnat_t *, | | 237 | static hostmap_t *ipf_nat_hostmap(ipf_nat_softc_t *, ipnat_t *, |
238 | struct in_addr, struct in_addr, | | 238 | struct in_addr, struct in_addr, |
239 | struct in_addr, u_32_t); | | 239 | struct in_addr, u_32_t); |
240 | static int ipf_nat_icmpquerytype(int); | | 240 | static int ipf_nat_icmpquerytype(int); |
241 | static int ipf_nat_iterator(ipf_main_softc_t *, ipftoken_t *, | | 241 | static int ipf_nat_iterator(ipf_main_softc_t *, ipftoken_t *, |
242 | ipfgeniter_t *, ipfobj_t *); | | 242 | ipfgeniter_t *, ipfobj_t *); |
243 | static int ipf_nat_match(fr_info_t *, ipnat_t *); | | 243 | static int ipf_nat_match(fr_info_t *, ipnat_t *); |
244 | static int ipf_nat_matcharray(nat_t *, int *, u_long); | | 244 | static int ipf_nat_matcharray(nat_t *, int *, u_long); |
245 | static int ipf_nat_matchflush(ipf_main_softc_t *, ipf_nat_softc_t *, | | 245 | static int ipf_nat_matchflush(ipf_main_softc_t *, ipf_nat_softc_t *, |
246 | void *); | | 246 | void *); |
247 | static void ipf_nat_mssclamp(tcphdr_t *, u_32_t, fr_info_t *, u_short *); | | 247 | static void ipf_nat_mssclamp(tcphdr_t *, u_32_t, fr_info_t *, u_short *); |
248 | static int ipf_nat_newmap(fr_info_t *, nat_t *, natinfo_t *); | | 248 | static int ipf_nat_newmap(fr_info_t *, nat_t *, natinfo_t *); |
249 | static int ipf_nat_newdivert(fr_info_t *, nat_t *, natinfo_t *); | | 249 | static int ipf_nat_newdivert(fr_info_t *, nat_t *, natinfo_t *); |
250 | static int ipf_nat_newrdr(fr_info_t *, nat_t *, natinfo_t *); | | 250 | static int ipf_nat_newrdr(fr_info_t *, nat_t *, natinfo_t *); |
251 | static int ipf_nat_newrewrite(fr_info_t *, nat_t *, natinfo_t *); | | 251 | static int ipf_nat_newrewrite(fr_info_t *, nat_t *, natinfo_t *); |
252 | static int ipf_nat_nextaddr(fr_info_t *, nat_addr_t *, u_32_t *, u_32_t *); | | 252 | static int ipf_nat_nextaddr(fr_info_t *, nat_addr_t *, u_32_t *, u_32_t *); |
253 | static int ipf_nat_nextaddrinit(ipf_main_softc_t *, char *, | | 253 | static int ipf_nat_nextaddrinit(ipf_main_softc_t *, char *, |
254 | nat_addr_t *, int, void *); | | 254 | nat_addr_t *, int, void *); |
255 | static int ipf_nat_resolverule(ipf_main_softc_t *, ipnat_t *); | | 255 | static int ipf_nat_resolverule(ipf_main_softc_t *, ipnat_t *); |
256 | static int ipf_nat_ruleaddrinit(ipf_main_softc_t *, | | 256 | static int ipf_nat_ruleaddrinit(ipf_main_softc_t *, |
257 | ipf_nat_softc_t *, ipnat_t *); | | 257 | ipf_nat_softc_t *, ipnat_t *); |
258 | static void ipf_nat_rule_fini(ipf_main_softc_t *, ipnat_t *); | | 258 | static void ipf_nat_rule_fini(ipf_main_softc_t *, ipnat_t *); |
259 | static int ipf_nat_rule_init(ipf_main_softc_t *, ipf_nat_softc_t *, | | 259 | static int ipf_nat_rule_init(ipf_main_softc_t *, ipf_nat_softc_t *, |
260 | ipnat_t *); | | 260 | ipnat_t *); |
261 | static int ipf_nat_siocaddnat(ipf_main_softc_t *, ipf_nat_softc_t *, | | 261 | static int ipf_nat_siocaddnat(ipf_main_softc_t *, ipf_nat_softc_t *, |
262 | ipnat_t *, int); | | 262 | ipnat_t *, int); |
263 | static void ipf_nat_siocdelnat(ipf_main_softc_t *, ipf_nat_softc_t *, | | 263 | static void ipf_nat_siocdelnat(ipf_main_softc_t *, ipf_nat_softc_t *, |
264 | ipnat_t *, int); | | 264 | ipnat_t *, int); |
265 | static void ipf_nat_tabmove(ipf_nat_softc_t *, nat_t *); | | 265 | static void ipf_nat_tabmove(ipf_nat_softc_t *, nat_t *); |
266 | | | 266 | |
267 | /* ------------------------------------------------------------------------ */ | | 267 | /* ------------------------------------------------------------------------ */ |
268 | /* Function: ipf_nat_main_load */ | | 268 | /* Function: ipf_nat_main_load */ |
269 | /* Returns: int - 0 == success, -1 == failure */ | | 269 | /* Returns: int - 0 == success, -1 == failure */ |
270 | /* Parameters: Nil */ | | 270 | /* Parameters: Nil */ |
271 | /* */ | | 271 | /* */ |
272 | /* The only global NAT structure that needs to be initialised is the filter */ | | 272 | /* The only global NAT structure that needs to be initialised is the filter */ |
273 | /* rule that is used with blocking packets. */ | | 273 | /* rule that is used with blocking packets. */ |
274 | /* ------------------------------------------------------------------------ */ | | 274 | /* ------------------------------------------------------------------------ */ |
275 | int | | 275 | int |
276 | ipf_nat_main_load(void) | | 276 | ipf_nat_main_load(void) |
277 | { | | 277 | { |
278 | bzero((char *)&ipfnatblock, sizeof(ipfnatblock)); | | 278 | bzero((char *)&ipfnatblock, sizeof(ipfnatblock)); |
279 | ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK; | | 279 | ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK; |
280 | ipfnatblock.fr_ref = 1; | | 280 | ipfnatblock.fr_ref = 1; |
281 | | | 281 | |
282 | return 0; | | 282 | return 0; |
283 | } | | 283 | } |
284 | | | 284 | |
285 | | | 285 | |
286 | /* ------------------------------------------------------------------------ */ | | 286 | /* ------------------------------------------------------------------------ */ |
287 | /* Function: ipf_nat_main_unload */ | | 287 | /* Function: ipf_nat_main_unload */ |
288 | /* Returns: int - 0 == success, -1 == failure */ | | 288 | /* Returns: int - 0 == success, -1 == failure */ |
289 | /* Parameters: Nil */ | | 289 | /* Parameters: Nil */ |
290 | /* */ | | 290 | /* */ |
291 | /* A null-op function that exists as a placeholder so that the flow in */ | | 291 | /* A null-op function that exists as a placeholder so that the flow in */ |
292 | /* other functions is obvious. */ | | 292 | /* other functions is obvious. */ |
293 | /* ------------------------------------------------------------------------ */ | | 293 | /* ------------------------------------------------------------------------ */ |
294 | int | | 294 | int |
295 | ipf_nat_main_unload(void) | | 295 | ipf_nat_main_unload(void) |
296 | { | | 296 | { |
297 | return 0; | | 297 | return 0; |
298 | } | | 298 | } |
299 | | | 299 | |
300 | | | 300 | |
301 | /* ------------------------------------------------------------------------ */ | | 301 | /* ------------------------------------------------------------------------ */ |
302 | /* Function: ipf_nat_soft_create */ | | 302 | /* Function: ipf_nat_soft_create */ |
303 | /* Returns: void * - NULL = failure, else pointer to NAT context */ | | 303 | /* Returns: void * - NULL = failure, else pointer to NAT context */ |
304 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 304 | /* Parameters: softc(I) - pointer to soft context main structure */ |
305 | /* */ | | 305 | /* */ |
306 | /* Allocate the initial soft context structure for NAT and populate it with */ | | 306 | /* Allocate the initial soft context structure for NAT and populate it with */ |
307 | /* some default values. Creating the tables is left until we call _init so */ | | 307 | /* some default values. Creating the tables is left until we call _init so */ |
308 | /* that sizes can be changed before we get under way. */ | | 308 | /* that sizes can be changed before we get under way. */ |
309 | /* ------------------------------------------------------------------------ */ | | 309 | /* ------------------------------------------------------------------------ */ |
310 | void * | | 310 | void * |
311 | ipf_nat_soft_create(ipf_main_softc_t *softc) | | 311 | ipf_nat_soft_create(ipf_main_softc_t *softc) |
312 | { | | 312 | { |
313 | ipf_nat_softc_t *softn; | | 313 | ipf_nat_softc_t *softn; |
314 | | | 314 | |
315 | KMALLOC(softn, ipf_nat_softc_t *); | | 315 | KMALLOC(softn, ipf_nat_softc_t *); |
316 | if (softn == NULL) | | 316 | if (softn == NULL) |
317 | return NULL; | | 317 | return NULL; |
318 | | | 318 | |
319 | bzero((char *)softn, sizeof(*softn)); | | 319 | bzero((char *)softn, sizeof(*softn)); |
320 | | | 320 | |
321 | softn->ipf_nat_tune = ipf_tune_array_copy(softn, | | 321 | softn->ipf_nat_tune = ipf_tune_array_copy(softn, |
322 | sizeof(ipf_nat_tuneables), | | 322 | sizeof(ipf_nat_tuneables), |
323 | ipf_nat_tuneables); | | 323 | ipf_nat_tuneables); |
324 | if (softn->ipf_nat_tune == NULL) { | | 324 | if (softn->ipf_nat_tune == NULL) { |
325 | ipf_nat_soft_destroy(softc, softn); | | 325 | ipf_nat_soft_destroy(softc, softn); |
326 | return NULL; | | 326 | return NULL; |
327 | } | | 327 | } |
328 | if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) { | | 328 | if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) { |
329 | ipf_nat_soft_destroy(softc, softn); | | 329 | ipf_nat_soft_destroy(softc, softn); |
330 | return NULL; | | 330 | return NULL; |
331 | } | | 331 | } |
332 | | | 332 | |
333 | softn->ipf_nat_list_tail = &softn->ipf_nat_list; | | 333 | softn->ipf_nat_list_tail = &softn->ipf_nat_list; |
334 | | | 334 | |
335 | softn->ipf_nat_table_max = NAT_TABLE_MAX; | | 335 | softn->ipf_nat_table_max = NAT_TABLE_MAX; |
336 | softn->ipf_nat_table_sz = NAT_TABLE_SZ; | | 336 | softn->ipf_nat_table_sz = NAT_TABLE_SZ; |
337 | softn->ipf_nat_maprules_sz = NAT_SIZE; | | 337 | softn->ipf_nat_maprules_sz = NAT_SIZE; |
338 | softn->ipf_nat_rdrrules_sz = RDR_SIZE; | | 338 | softn->ipf_nat_rdrrules_sz = RDR_SIZE; |
339 | softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE; | | 339 | softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE; |
340 | softn->ipf_nat_doflush = 0; | | 340 | softn->ipf_nat_doflush = 0; |
341 | #ifdef IPFILTER_LOG | | 341 | #ifdef IPFILTER_LOG |
342 | softn->ipf_nat_logging = 1; | | 342 | softn->ipf_nat_logging = 1; |
343 | #else | | 343 | #else |
344 | softn->ipf_nat_logging = 0; | | 344 | softn->ipf_nat_logging = 0; |
345 | #endif | | 345 | #endif |
346 | | | 346 | |
347 | softn->ipf_nat_defage = DEF_NAT_AGE; | | 347 | softn->ipf_nat_defage = DEF_NAT_AGE; |
348 | softn->ipf_nat_defipage = IPF_TTLVAL(60); | | 348 | softn->ipf_nat_defipage = IPF_TTLVAL(60); |
349 | softn->ipf_nat_deficmpage = IPF_TTLVAL(3); | | 349 | softn->ipf_nat_deficmpage = IPF_TTLVAL(3); |
350 | softn->ipf_nat_table_wm_high = 99; | | 350 | softn->ipf_nat_table_wm_high = 99; |
351 | softn->ipf_nat_table_wm_low = 90; | | 351 | softn->ipf_nat_table_wm_low = 90; |
352 | | | 352 | |
353 | return softn; | | 353 | return softn; |
354 | } | | 354 | } |
355 | | | 355 | |
356 | /* ------------------------------------------------------------------------ */ | | 356 | /* ------------------------------------------------------------------------ */ |
357 | /* Function: ipf_nat_soft_destroy */ | | 357 | /* Function: ipf_nat_soft_destroy */ |
358 | /* Returns: Nil */ | | 358 | /* Returns: Nil */ |
359 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 359 | /* Parameters: softc(I) - pointer to soft context main structure */ |
360 | /* */ | | 360 | /* */ |
361 | /* ------------------------------------------------------------------------ */ | | 361 | /* ------------------------------------------------------------------------ */ |
362 | void | | 362 | void |
363 | ipf_nat_soft_destroy(ipf_main_softc_t *softc, void *arg) | | 363 | ipf_nat_soft_destroy(ipf_main_softc_t *softc, void *arg) |
364 | { | | 364 | { |
365 | ipf_nat_softc_t *softn = arg; | | 365 | ipf_nat_softc_t *softn = arg; |
366 | | | 366 | |
367 | if (softn->ipf_nat_tune != NULL) { | | 367 | if (softn->ipf_nat_tune != NULL) { |
368 | ipf_tune_array_unlink(softc, softn->ipf_nat_tune); | | 368 | ipf_tune_array_unlink(softc, softn->ipf_nat_tune); |
369 | KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables)); | | 369 | KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables)); |
370 | softn->ipf_nat_tune = NULL; | | 370 | softn->ipf_nat_tune = NULL; |
371 | } | | 371 | } |
372 | | | 372 | |
373 | KFREE(softn); | | 373 | KFREE(softn); |
374 | } | | 374 | } |
375 | | | 375 | |
376 | | | 376 | |
377 | /* ------------------------------------------------------------------------ */ | | 377 | /* ------------------------------------------------------------------------ */ |
378 | /* Function: ipf_nat_init */ | | 378 | /* Function: ipf_nat_init */ |
379 | /* Returns: int - 0 == success, -1 == failure */ | | 379 | /* Returns: int - 0 == success, -1 == failure */ |
380 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 380 | /* Parameters: softc(I) - pointer to soft context main structure */ |
381 | /* */ | | 381 | /* */ |
382 | /* Initialise all of the NAT locks, tables and other structures. */ | | 382 | /* Initialise all of the NAT locks, tables and other structures. */ |
383 | /* ------------------------------------------------------------------------ */ | | 383 | /* ------------------------------------------------------------------------ */ |
384 | int | | 384 | int |
385 | ipf_nat_soft_init(ipf_main_softc_t *softc, void *arg) | | 385 | ipf_nat_soft_init(ipf_main_softc_t *softc, void *arg) |
386 | { | | 386 | { |
387 | ipf_nat_softc_t *softn = arg; | | 387 | ipf_nat_softc_t *softn = arg; |
388 | ipftq_t *tq; | | 388 | ipftq_t *tq; |
389 | int i; | | 389 | int i; |
390 | | | 390 | |
391 | KMALLOCS(softn->ipf_nat_table[0], nat_t **, \ | | 391 | KMALLOCS(softn->ipf_nat_table[0], nat_t **, \ |
392 | sizeof(nat_t *) * softn->ipf_nat_table_sz); | | 392 | sizeof(nat_t *) * softn->ipf_nat_table_sz); |
393 | | | 393 | |
394 | if (softn->ipf_nat_table[0] != NULL) { | | 394 | if (softn->ipf_nat_table[0] != NULL) { |
395 | bzero((char *)softn->ipf_nat_table[0], | | 395 | bzero((char *)softn->ipf_nat_table[0], |
396 | softn->ipf_nat_table_sz * sizeof(nat_t *)); | | 396 | softn->ipf_nat_table_sz * sizeof(nat_t *)); |
397 | } else { | | 397 | } else { |
398 | return -1; | | 398 | return -1; |
399 | } | | 399 | } |
400 | | | 400 | |
401 | KMALLOCS(softn->ipf_nat_table[1], nat_t **, \ | | 401 | KMALLOCS(softn->ipf_nat_table[1], nat_t **, \ |
402 | sizeof(nat_t *) * softn->ipf_nat_table_sz); | | 402 | sizeof(nat_t *) * softn->ipf_nat_table_sz); |
403 | | | 403 | |
404 | if (softn->ipf_nat_table[1] != NULL) { | | 404 | if (softn->ipf_nat_table[1] != NULL) { |
405 | bzero((char *)softn->ipf_nat_table[1], | | 405 | bzero((char *)softn->ipf_nat_table[1], |
406 | softn->ipf_nat_table_sz * sizeof(nat_t *)); | | 406 | softn->ipf_nat_table_sz * sizeof(nat_t *)); |
407 | } else { | | 407 | } else { |
408 | return -2; | | 408 | return -2; |
409 | } | | 409 | } |
410 | | | 410 | |
411 | KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \ | | 411 | KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \ |
412 | sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); | | 412 | sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); |
413 | | | 413 | |
414 | if (softn->ipf_nat_map_rules != NULL) { | | 414 | if (softn->ipf_nat_map_rules != NULL) { |
415 | bzero((char *)softn->ipf_nat_map_rules, | | 415 | bzero((char *)softn->ipf_nat_map_rules, |
416 | softn->ipf_nat_maprules_sz * sizeof(ipnat_t *)); | | 416 | softn->ipf_nat_maprules_sz * sizeof(ipnat_t *)); |
417 | } else { | | 417 | } else { |
418 | return -3; | | 418 | return -3; |
419 | } | | 419 | } |
420 | | | 420 | |
421 | KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \ | | 421 | KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \ |
422 | sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); | | 422 | sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); |
423 | | | 423 | |
424 | if (softn->ipf_nat_rdr_rules != NULL) { | | 424 | if (softn->ipf_nat_rdr_rules != NULL) { |
425 | bzero((char *)softn->ipf_nat_rdr_rules, | | 425 | bzero((char *)softn->ipf_nat_rdr_rules, |
426 | softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *)); | | 426 | softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *)); |
427 | } else { | | 427 | } else { |
428 | return -4; | | 428 | return -4; |
429 | } | | 429 | } |
430 | | | 430 | |
431 | KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \ | | 431 | KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \ |
432 | sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); | | 432 | sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); |
433 | | | 433 | |
434 | if (softn->ipf_hm_maptable != NULL) { | | 434 | if (softn->ipf_hm_maptable != NULL) { |
435 | bzero((char *)softn->ipf_hm_maptable, | | 435 | bzero((char *)softn->ipf_hm_maptable, |
436 | sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); | | 436 | sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); |
437 | } else { | | 437 | } else { |
438 | return -5; | | 438 | return -5; |
439 | } | | 439 | } |
440 | softn->ipf_hm_maplist = NULL; | | 440 | softn->ipf_hm_maplist = NULL; |
441 | | | 441 | |
442 | KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *, | | 442 | KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *, |
443 | softn->ipf_nat_table_sz * sizeof(u_int)); | | 443 | softn->ipf_nat_table_sz * sizeof(u_int)); |
444 | | | 444 | |
445 | if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) { | | 445 | if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) { |
446 | return -6; | | 446 | return -6; |
447 | } | | 447 | } |
448 | bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen, | | 448 | bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen, |
449 | softn->ipf_nat_table_sz * sizeof(u_int)); | | 449 | softn->ipf_nat_table_sz * sizeof(u_int)); |
450 | | | 450 | |
451 | KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *, | | 451 | KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *, |
452 | softn->ipf_nat_table_sz * sizeof(u_int)); | | 452 | softn->ipf_nat_table_sz * sizeof(u_int)); |
453 | | | 453 | |
454 | if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) { | | 454 | if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) { |
455 | return -7; | | 455 | return -7; |
456 | } | | 456 | } |
457 | | | 457 | |
458 | bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen, | | 458 | bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen, |
459 | softn->ipf_nat_table_sz * sizeof(u_int)); | | 459 | softn->ipf_nat_table_sz * sizeof(u_int)); |
460 | | | 460 | |
461 | if (softn->ipf_nat_maxbucket == 0) { | | 461 | if (softn->ipf_nat_maxbucket == 0) { |
462 | for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1) | | 462 | for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1) |
463 | softn->ipf_nat_maxbucket++; | | 463 | softn->ipf_nat_maxbucket++; |
464 | softn->ipf_nat_maxbucket *= 2; | | 464 | softn->ipf_nat_maxbucket *= 2; |
465 | } | | 465 | } |
466 | | | 466 | |
467 | ipf_sttab_init(softc, softn->ipf_nat_tcptq); | | 467 | ipf_sttab_init(softc, softn->ipf_nat_tcptq); |
468 | /* | | 468 | /* |
469 | * Increase this because we may have "keep state" following this too | | 469 | * Increase this because we may have "keep state" following this too |
470 | * and packet storms can occur if this is removed too quickly. | | 470 | * and packet storms can occur if this is removed too quickly. |
471 | */ | | 471 | */ |
472 | softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; | | 472 | softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; |
473 | softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next = | | 473 | softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next = |
474 | &softn->ipf_nat_udptq; | | 474 | &softn->ipf_nat_udptq; |
475 | | | 475 | |
476 | IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage, | | 476 | IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage, |
477 | "nat ipftq udp tab"); | | 477 | "nat ipftq udp tab"); |
478 | softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq; | | 478 | softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq; |
479 | | | 479 | |
480 | IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage, | | 480 | IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage, |
481 | "nat ipftq udpack tab"); | | 481 | "nat ipftq udpack tab"); |
482 | softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq; | | 482 | softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq; |
483 | | | 483 | |
484 | IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage, | | 484 | IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage, |
485 | "nat icmp ipftq tab"); | | 485 | "nat icmp ipftq tab"); |
486 | softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq; | | 486 | softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq; |
487 | | | 487 | |
488 | IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage, | | 488 | IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage, |
489 | "nat icmpack ipftq tab"); | | 489 | "nat icmpack ipftq tab"); |
490 | softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq; | | 490 | softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq; |
491 | | | 491 | |
492 | IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage, | | 492 | IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage, |
493 | "nat ip ipftq tab"); | | 493 | "nat ip ipftq tab"); |
494 | softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending; | | 494 | softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending; |
495 | | | 495 | |
496 | IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab"); | | 496 | IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab"); |
497 | softn->ipf_nat_pending.ifq_next = NULL; | | 497 | softn->ipf_nat_pending.ifq_next = NULL; |
498 | | | 498 | |
499 | for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) { | | 499 | for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) { |
500 | if (tq->ifq_ttl < softn->ipf_nat_deficmpage) | | 500 | if (tq->ifq_ttl < softn->ipf_nat_deficmpage) |
501 | tq->ifq_ttl = softn->ipf_nat_deficmpage; | | 501 | tq->ifq_ttl = softn->ipf_nat_deficmpage; |
502 | #ifdef LARGE_NAT | | 502 | #ifdef LARGE_NAT |
503 | else if (tq->ifq_ttl > softn->ipf_nat_defage) | | 503 | else if (tq->ifq_ttl > softn->ipf_nat_defage) |
504 | tq->ifq_ttl = softn->ipf_nat_defage; | | 504 | tq->ifq_ttl = softn->ipf_nat_defage; |
505 | #endif | | 505 | #endif |
506 | } | | 506 | } |
507 | | | 507 | |
508 | /* | | 508 | /* |
509 | * Increase this because we may have "keep state" following | | 509 | * Increase this because we may have "keep state" following |
510 | * this too and packet storms can occur if this is removed | | 510 | * this too and packet storms can occur if this is removed |
511 | * too quickly. | | 511 | * too quickly. |
512 | */ | | 512 | */ |
513 | softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; | | 513 | softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack; |
514 | | | 514 | |
515 | MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex"); | | 515 | MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex"); |
516 | MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex"); | | 516 | MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex"); |
517 | | | 517 | |
518 | softn->ipf_nat_inited = 1; | | 518 | softn->ipf_nat_inited = 1; |
519 | | | 519 | |
520 | return 0; | | 520 | return 0; |
521 | } | | 521 | } |
522 | | | 522 | |
523 | | | 523 | |
524 | /* ------------------------------------------------------------------------ */ | | 524 | /* ------------------------------------------------------------------------ */ |
525 | /* Function: ipf_nat_soft_fini */ | | 525 | /* Function: ipf_nat_soft_fini */ |
526 | /* Returns: Nil */ | | 526 | /* Returns: Nil */ |
527 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 527 | /* Parameters: softc(I) - pointer to soft context main structure */ |
528 | /* */ | | 528 | /* */ |
529 | /* Free all memory used by NAT structures allocated at runtime. */ | | 529 | /* Free all memory used by NAT structures allocated at runtime. */ |
530 | /* ------------------------------------------------------------------------ */ | | 530 | /* ------------------------------------------------------------------------ */ |
531 | int | | 531 | int |
532 | ipf_nat_soft_fini(ipf_main_softc_t *softc, void *arg) | | 532 | ipf_nat_soft_fini(ipf_main_softc_t *softc, void *arg) |
533 | { | | 533 | { |
534 | ipf_nat_softc_t *softn = arg; | | 534 | ipf_nat_softc_t *softn = arg; |
535 | ipftq_t *ifq, *ifqnext; | | 535 | ipftq_t *ifq, *ifqnext; |
536 | | | 536 | |
537 | (void) ipf_nat_clearlist(softc, softn); | | 537 | (void) ipf_nat_clearlist(softc, softn); |
538 | (void) ipf_nat_flushtable(softc, softn); | | 538 | (void) ipf_nat_flushtable(softc, softn); |
539 | | | 539 | |
540 | /* | | 540 | /* |
541 | * Proxy timeout queues are not cleaned here because although they | | 541 | * Proxy timeout queues are not cleaned here because although they |
542 | * exist on the NAT list, ipf_proxy_unload is called after unload | | 542 | * exist on the NAT list, ipf_proxy_unload is called after unload |
543 | * and the proxies actually are responsible for them being created. | | 543 | * and the proxies actually are responsible for them being created. |
544 | * Should the proxy timeouts have their own list? There's no real | | 544 | * Should the proxy timeouts have their own list? There's no real |
545 | * justification as this is the only complication. | | 545 | * justification as this is the only complication. |
546 | */ | | 546 | */ |
547 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { | | 547 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { |
548 | ifqnext = ifq->ifq_next; | | 548 | ifqnext = ifq->ifq_next; |
549 | if (ipf_deletetimeoutqueue(ifq) == 0) | | 549 | if (ipf_deletetimeoutqueue(ifq) == 0) |
550 | ipf_freetimeoutqueue(softc, ifq); | | 550 | ipf_freetimeoutqueue(softc, ifq); |
551 | } | | 551 | } |
552 | | | 552 | |
553 | if (softn->ipf_nat_table[0] != NULL) { | | 553 | if (softn->ipf_nat_table[0] != NULL) { |
554 | KFREES(softn->ipf_nat_table[0], | | 554 | KFREES(softn->ipf_nat_table[0], |
555 | sizeof(nat_t *) * softn->ipf_nat_table_sz); | | 555 | sizeof(nat_t *) * softn->ipf_nat_table_sz); |
556 | softn->ipf_nat_table[0] = NULL; | | 556 | softn->ipf_nat_table[0] = NULL; |
557 | } | | 557 | } |
558 | if (softn->ipf_nat_table[1] != NULL) { | | 558 | if (softn->ipf_nat_table[1] != NULL) { |
559 | KFREES(softn->ipf_nat_table[1], | | 559 | KFREES(softn->ipf_nat_table[1], |
560 | sizeof(nat_t *) * softn->ipf_nat_table_sz); | | 560 | sizeof(nat_t *) * softn->ipf_nat_table_sz); |
561 | softn->ipf_nat_table[1] = NULL; | | 561 | softn->ipf_nat_table[1] = NULL; |
562 | } | | 562 | } |
563 | if (softn->ipf_nat_map_rules != NULL) { | | 563 | if (softn->ipf_nat_map_rules != NULL) { |
564 | KFREES(softn->ipf_nat_map_rules, | | 564 | KFREES(softn->ipf_nat_map_rules, |
565 | sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); | | 565 | sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz); |
566 | softn->ipf_nat_map_rules = NULL; | | 566 | softn->ipf_nat_map_rules = NULL; |
567 | } | | 567 | } |
568 | if (softn->ipf_nat_rdr_rules != NULL) { | | 568 | if (softn->ipf_nat_rdr_rules != NULL) { |
569 | KFREES(softn->ipf_nat_rdr_rules, | | 569 | KFREES(softn->ipf_nat_rdr_rules, |
570 | sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); | | 570 | sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz); |
571 | softn->ipf_nat_rdr_rules = NULL; | | 571 | softn->ipf_nat_rdr_rules = NULL; |
572 | } | | 572 | } |
573 | if (softn->ipf_hm_maptable != NULL) { | | 573 | if (softn->ipf_hm_maptable != NULL) { |
574 | KFREES(softn->ipf_hm_maptable, | | 574 | KFREES(softn->ipf_hm_maptable, |
575 | sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); | | 575 | sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz); |
576 | softn->ipf_hm_maptable = NULL; | | 576 | softn->ipf_hm_maptable = NULL; |
577 | } | | 577 | } |
578 | if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { | | 578 | if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) { |
579 | KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, | | 579 | KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, |
580 | sizeof(u_int) * softn->ipf_nat_table_sz); | | 580 | sizeof(u_int) * softn->ipf_nat_table_sz); |
581 | softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL; | | 581 | softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL; |
582 | } | | 582 | } |
583 | if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { | | 583 | if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) { |
584 | KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, | | 584 | KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, |
585 | sizeof(u_int) * softn->ipf_nat_table_sz); | | 585 | sizeof(u_int) * softn->ipf_nat_table_sz); |
586 | softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL; | | 586 | softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL; |
587 | } | | 587 | } |
588 | | | 588 | |
589 | if (softn->ipf_nat_inited == 1) { | | 589 | if (softn->ipf_nat_inited == 1) { |
590 | softn->ipf_nat_inited = 0; | | 590 | softn->ipf_nat_inited = 0; |
591 | ipf_sttab_destroy(softn->ipf_nat_tcptq); | | 591 | ipf_sttab_destroy(softn->ipf_nat_tcptq); |
592 | | | 592 | |
593 | MUTEX_DESTROY(&softn->ipf_nat_new); | | 593 | MUTEX_DESTROY(&softn->ipf_nat_new); |
594 | MUTEX_DESTROY(&softn->ipf_nat_io); | | 594 | MUTEX_DESTROY(&softn->ipf_nat_io); |
595 | | | 595 | |
596 | MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock); | | 596 | MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock); |
597 | MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock); | | 597 | MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock); |
598 | MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock); | | 598 | MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock); |
599 | MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock); | | 599 | MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock); |
600 | MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock); | | 600 | MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock); |
601 | MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock); | | 601 | MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock); |
602 | } | | 602 | } |
603 | | | 603 | |
604 | return 0; | | 604 | return 0; |
605 | } | | 605 | } |
606 | | | 606 | |
607 | | | 607 | |
608 | /* ------------------------------------------------------------------------ */ | | 608 | /* ------------------------------------------------------------------------ */ |
609 | /* Function: ipf_nat_setlock */ | | 609 | /* Function: ipf_nat_setlock */ |
610 | /* Returns: Nil */ | | 610 | /* Returns: Nil */ |
611 | /* Parameters: arg(I) - pointer to soft state information */ | | 611 | /* Parameters: arg(I) - pointer to soft state information */ |
612 | /* tmp(I) - new lock value */ | | 612 | /* tmp(I) - new lock value */ |
613 | /* */ | | 613 | /* */ |
614 | /* Set the "lock status" of NAT to the value in tmp. */ | | 614 | /* Set the "lock status" of NAT to the value in tmp. */ |
615 | /* ------------------------------------------------------------------------ */ | | 615 | /* ------------------------------------------------------------------------ */ |
616 | void | | 616 | void |
617 | ipf_nat_setlock(void *arg, int tmp) | | 617 | ipf_nat_setlock(void *arg, int tmp) |
618 | { | | 618 | { |
619 | ipf_nat_softc_t *softn = arg; | | 619 | ipf_nat_softc_t *softn = arg; |
620 | | | 620 | |
621 | softn->ipf_nat_lock = tmp; | | 621 | softn->ipf_nat_lock = tmp; |
622 | } | | 622 | } |
623 | | | 623 | |
624 | | | 624 | |
625 | /* ------------------------------------------------------------------------ */ | | 625 | /* ------------------------------------------------------------------------ */ |
626 | /* Function: ipf_nat_addrdr */ | | 626 | /* Function: ipf_nat_addrdr */ |
627 | /* Returns: Nil */ | | 627 | /* Returns: Nil */ |
628 | /* Parameters: n(I) - pointer to NAT rule to add */ | | 628 | /* Parameters: n(I) - pointer to NAT rule to add */ |
629 | /* */ | | 629 | /* */ |
630 | /* Adds a redirect rule to the hash table of redirect rules and the list of */ | | 630 | /* Adds a redirect rule to the hash table of redirect rules and the list of */ |
631 | /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ | | 631 | /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ |
632 | /* use by redirect rules. */ | | 632 | /* use by redirect rules. */ |
633 | /* ------------------------------------------------------------------------ */ | | 633 | /* ------------------------------------------------------------------------ */ |
634 | static void | | 634 | static void |
635 | ipf_nat_addrdr(ipf_nat_softc_t *softn, ipnat_t *n) | | 635 | ipf_nat_addrdr(ipf_nat_softc_t *softn, ipnat_t *n) |
636 | { | | 636 | { |
637 | ipnat_t **np; | | 637 | ipnat_t **np; |
638 | u_32_t j; | | 638 | u_32_t j; |
639 | u_int hv; | | 639 | u_int hv; |
640 | u_int rhv; | | 640 | u_int rhv; |
641 | int k; | | 641 | int k; |
642 | | | 642 | |
643 | if (n->in_odstatype == FRI_NORMAL) { | | 643 | if (n->in_odstatype == FRI_NORMAL) { |
644 | k = count4bits(n->in_odstmsk); | | 644 | k = count4bits(n->in_odstmsk); |
645 | ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask); | | 645 | ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask); |
646 | j = (n->in_odstaddr & n->in_odstmsk); | | 646 | j = (n->in_odstaddr & n->in_odstmsk); |
647 | rhv = NAT_HASH_FN(j, 0, 0xffffffff); | | 647 | rhv = NAT_HASH_FN(j, 0, 0xffffffff); |
648 | } else { | | 648 | } else { |
649 | ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask); | | 649 | ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask); |
650 | j = 0; | | 650 | j = 0; |
651 | rhv = 0; | | 651 | rhv = 0; |
652 | } | | 652 | } |
653 | hv = rhv % softn->ipf_nat_rdrrules_sz; | | 653 | hv = rhv % softn->ipf_nat_rdrrules_sz; |
654 | np = softn->ipf_nat_rdr_rules + hv; | | 654 | np = softn->ipf_nat_rdr_rules + hv; |
655 | while (*np != NULL) | | 655 | while (*np != NULL) |
656 | np = &(*np)->in_rnext; | | 656 | np = &(*np)->in_rnext; |
657 | n->in_rnext = NULL; | | 657 | n->in_rnext = NULL; |
658 | n->in_prnext = np; | | 658 | n->in_prnext = np; |
659 | n->in_hv[0] = hv; | | 659 | n->in_hv[0] = hv; |
660 | n->in_use++; | | 660 | n->in_use++; |
661 | *np = n; | | 661 | *np = n; |
662 | } | | 662 | } |
663 | | | 663 | |
664 | | | 664 | |
665 | /* ------------------------------------------------------------------------ */ | | 665 | /* ------------------------------------------------------------------------ */ |
666 | /* Function: ipf_nat_addmap */ | | 666 | /* Function: ipf_nat_addmap */ |
667 | /* Returns: Nil */ | | 667 | /* Returns: Nil */ |
668 | /* Parameters: n(I) - pointer to NAT rule to add */ | | 668 | /* Parameters: n(I) - pointer to NAT rule to add */ |
669 | /* */ | | 669 | /* */ |
670 | /* Adds a NAT map rule to the hash table of rules and the list of loaded */ | | 670 | /* Adds a NAT map rule to the hash table of rules and the list of loaded */ |
671 | /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ | | 671 | /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ |
672 | /* redirect rules. */ | | 672 | /* redirect rules. */ |
673 | /* ------------------------------------------------------------------------ */ | | 673 | /* ------------------------------------------------------------------------ */ |
674 | static void | | 674 | static void |
675 | ipf_nat_addmap(ipf_nat_softc_t *softn, ipnat_t *n) | | 675 | ipf_nat_addmap(ipf_nat_softc_t *softn, ipnat_t *n) |
676 | { | | 676 | { |
677 | ipnat_t **np; | | 677 | ipnat_t **np; |
678 | u_32_t j; | | 678 | u_32_t j; |
679 | u_int hv; | | 679 | u_int hv; |
680 | u_int rhv; | | 680 | u_int rhv; |
681 | int k; | | 681 | int k; |
682 | | | 682 | |
683 | if (n->in_osrcatype == FRI_NORMAL) { | | 683 | if (n->in_osrcatype == FRI_NORMAL) { |
684 | k = count4bits(n->in_osrcmsk); | | 684 | k = count4bits(n->in_osrcmsk); |
685 | ipf_inet_mask_add(k, &softn->ipf_nat_map_mask); | | 685 | ipf_inet_mask_add(k, &softn->ipf_nat_map_mask); |
686 | j = (n->in_osrcaddr & n->in_osrcmsk); | | 686 | j = (n->in_osrcaddr & n->in_osrcmsk); |
687 | rhv = NAT_HASH_FN(j, 0, 0xffffffff); | | 687 | rhv = NAT_HASH_FN(j, 0, 0xffffffff); |
688 | } else { | | 688 | } else { |
689 | ipf_inet_mask_add(0, &softn->ipf_nat_map_mask); | | 689 | ipf_inet_mask_add(0, &softn->ipf_nat_map_mask); |
690 | j = 0; | | 690 | j = 0; |
691 | rhv = 0; | | 691 | rhv = 0; |
692 | } | | 692 | } |
693 | hv = rhv % softn->ipf_nat_maprules_sz; | | 693 | hv = rhv % softn->ipf_nat_maprules_sz; |
694 | np = softn->ipf_nat_map_rules + hv; | | 694 | np = softn->ipf_nat_map_rules + hv; |
695 | while (*np != NULL) | | 695 | while (*np != NULL) |
696 | np = &(*np)->in_mnext; | | 696 | np = &(*np)->in_mnext; |
697 | n->in_mnext = NULL; | | 697 | n->in_mnext = NULL; |
698 | n->in_pmnext = np; | | 698 | n->in_pmnext = np; |
699 | n->in_hv[1] = rhv; | | 699 | n->in_hv[1] = rhv; |
700 | n->in_use++; | | 700 | n->in_use++; |
701 | *np = n; | | 701 | *np = n; |
702 | } | | 702 | } |
703 | | | 703 | |
704 | | | 704 | |
705 | /* ------------------------------------------------------------------------ */ | | 705 | /* ------------------------------------------------------------------------ */ |
706 | /* Function: ipf_nat_delrdr */ | | 706 | /* Function: ipf_nat_delrdr */ |
707 | /* Returns: Nil */ | | 707 | /* Returns: Nil */ |
708 | /* Parameters: n(I) - pointer to NAT rule to delete */ | | 708 | /* Parameters: n(I) - pointer to NAT rule to delete */ |
709 | /* */ | | 709 | /* */ |
710 | /* Removes a redirect rule from the hash table of redirect rules. */ | | 710 | /* Removes a redirect rule from the hash table of redirect rules. */ |
711 | /* ------------------------------------------------------------------------ */ | | 711 | /* ------------------------------------------------------------------------ */ |
712 | void | | 712 | void |
713 | ipf_nat_delrdr(ipf_nat_softc_t *softn, ipnat_t *n) | | 713 | ipf_nat_delrdr(ipf_nat_softc_t *softn, ipnat_t *n) |
714 | { | | 714 | { |
715 | if (n->in_odstatype == FRI_NORMAL) { | | 715 | if (n->in_odstatype == FRI_NORMAL) { |
716 | int k = count4bits(n->in_odstmsk); | | 716 | int k = count4bits(n->in_odstmsk); |
717 | ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask); | | 717 | ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask); |
718 | } else { | | 718 | } else { |
719 | ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask); | | 719 | ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask); |
720 | } | | 720 | } |
721 | if (n->in_rnext) | | 721 | if (n->in_rnext) |
722 | n->in_rnext->in_prnext = n->in_prnext; | | 722 | n->in_rnext->in_prnext = n->in_prnext; |
723 | *n->in_prnext = n->in_rnext; | | 723 | *n->in_prnext = n->in_rnext; |
724 | n->in_use--; | | 724 | n->in_use--; |
725 | } | | 725 | } |
726 | | | 726 | |
727 | | | 727 | |
728 | /* ------------------------------------------------------------------------ */ | | 728 | /* ------------------------------------------------------------------------ */ |
729 | /* Function: ipf_nat_delmap */ | | 729 | /* Function: ipf_nat_delmap */ |
730 | /* Returns: Nil */ | | 730 | /* Returns: Nil */ |
731 | /* Parameters: n(I) - pointer to NAT rule to delete */ | | 731 | /* Parameters: n(I) - pointer to NAT rule to delete */ |
732 | /* */ | | 732 | /* */ |
733 | /* Removes a NAT map rule from the hash table of NAT map rules. */ | | 733 | /* Removes a NAT map rule from the hash table of NAT map rules. */ |
734 | /* ------------------------------------------------------------------------ */ | | 734 | /* ------------------------------------------------------------------------ */ |
735 | void | | 735 | void |
736 | ipf_nat_delmap(ipf_nat_softc_t *softn, ipnat_t *n) | | 736 | ipf_nat_delmap(ipf_nat_softc_t *softn, ipnat_t *n) |
737 | { | | 737 | { |
738 | if (n->in_osrcatype == FRI_NORMAL) { | | 738 | if (n->in_osrcatype == FRI_NORMAL) { |
739 | int k = count4bits(n->in_osrcmsk); | | 739 | int k = count4bits(n->in_osrcmsk); |
740 | ipf_inet_mask_del(k, &softn->ipf_nat_map_mask); | | 740 | ipf_inet_mask_del(k, &softn->ipf_nat_map_mask); |
741 | } else { | | 741 | } else { |
742 | ipf_inet_mask_del(0, &softn->ipf_nat_map_mask); | | 742 | ipf_inet_mask_del(0, &softn->ipf_nat_map_mask); |
743 | } | | 743 | } |
744 | if (n->in_mnext != NULL) | | 744 | if (n->in_mnext != NULL) |
745 | n->in_mnext->in_pmnext = n->in_pmnext; | | 745 | n->in_mnext->in_pmnext = n->in_pmnext; |
746 | *n->in_pmnext = n->in_mnext; | | 746 | *n->in_pmnext = n->in_mnext; |
747 | n->in_use--; | | 747 | n->in_use--; |
748 | } | | 748 | } |
749 | | | 749 | |
750 | | | 750 | |
751 | /* ------------------------------------------------------------------------ */ | | 751 | /* ------------------------------------------------------------------------ */ |
752 | /* Function: ipf_nat_hostmap */ | | 752 | /* Function: ipf_nat_hostmap */ |
753 | /* Returns: struct hostmap* - NULL if no hostmap could be created, */ | | 753 | /* Returns: struct hostmap* - NULL if no hostmap could be created, */ |
754 | /* else a pointer to the hostmapping to use */ | | 754 | /* else a pointer to the hostmapping to use */ |
755 | /* Parameters: np(I) - pointer to NAT rule */ | | 755 | /* Parameters: np(I) - pointer to NAT rule */ |
756 | /* real(I) - real IP address */ | | 756 | /* real(I) - real IP address */ |
757 | /* map(I) - mapped IP address */ | | 757 | /* map(I) - mapped IP address */ |
758 | /* port(I) - destination port number */ | | 758 | /* port(I) - destination port number */ |
759 | /* Write Locks: ipf_nat */ | | 759 | /* Write Locks: ipf_nat */ |
760 | /* */ | | 760 | /* */ |
761 | /* Check if an ip address has already been allocated for a given mapping */ | | 761 | /* Check if an ip address has already been allocated for a given mapping */ |
762 | /* that is not doing port based translation. If is not yet allocated, then */ | | 762 | /* that is not doing port based translation. If is not yet allocated, then */ |
763 | /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ | | 763 | /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ |
764 | /* ------------------------------------------------------------------------ */ | | 764 | /* ------------------------------------------------------------------------ */ |
765 | static struct hostmap * | | 765 | static struct hostmap * |
766 | ipf_nat_hostmap(ipf_nat_softc_t *softn, ipnat_t *np, struct in_addr src, | | 766 | ipf_nat_hostmap(ipf_nat_softc_t *softn, ipnat_t *np, struct in_addr src, |
767 | struct in_addr dst, struct in_addr map, u_32_t port) | | 767 | struct in_addr dst, struct in_addr map, u_32_t port) |
768 | { | | 768 | { |
769 | hostmap_t *hm; | | 769 | hostmap_t *hm; |
770 | u_int hv, rhv; | | 770 | u_int hv, rhv; |
771 | | | 771 | |
772 | hv = (src.s_addr ^ dst.s_addr); | | 772 | hv = (src.s_addr ^ dst.s_addr); |
773 | hv += src.s_addr; | | 773 | hv += src.s_addr; |
774 | hv += dst.s_addr; | | 774 | hv += dst.s_addr; |
775 | rhv = hv; | | 775 | rhv = hv; |
776 | hv %= softn->ipf_nat_hostmap_sz; | | 776 | hv %= softn->ipf_nat_hostmap_sz; |
777 | for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext) | | 777 | for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext) |
778 | if ((hm->hm_osrcip.s_addr == src.s_addr) && | | 778 | if ((hm->hm_osrcip.s_addr == src.s_addr) && |
779 | (hm->hm_odstip.s_addr == dst.s_addr) && | | 779 | (hm->hm_odstip.s_addr == dst.s_addr) && |
780 | ((np == NULL) || (np == hm->hm_ipnat)) && | | 780 | ((np == NULL) || (np == hm->hm_ipnat)) && |
781 | ((port == 0) || (port == hm->hm_port))) { | | 781 | ((port == 0) || (port == hm->hm_port))) { |
782 | softn->ipf_nat_stats.ns_hm_addref++; | | 782 | softn->ipf_nat_stats.ns_hm_addref++; |
783 | hm->hm_ref++; | | 783 | hm->hm_ref++; |
784 | return hm; | | 784 | return hm; |
785 | } | | 785 | } |
786 | | | 786 | |
787 | if (np == NULL) { | | 787 | if (np == NULL) { |
788 | softn->ipf_nat_stats.ns_hm_nullnp++; | | 788 | softn->ipf_nat_stats.ns_hm_nullnp++; |
789 | return NULL; | | 789 | return NULL; |
790 | } | | 790 | } |
791 | | | 791 | |
792 | KMALLOC(hm, hostmap_t *); | | 792 | KMALLOC(hm, hostmap_t *); |
793 | if (hm) { | | 793 | if (hm) { |
794 | hm->hm_next = softn->ipf_hm_maplist; | | 794 | hm->hm_next = softn->ipf_hm_maplist; |
795 | hm->hm_pnext = &softn->ipf_hm_maplist; | | 795 | hm->hm_pnext = &softn->ipf_hm_maplist; |
796 | if (softn->ipf_hm_maplist != NULL) | | 796 | if (softn->ipf_hm_maplist != NULL) |
797 | softn->ipf_hm_maplist->hm_pnext = &hm->hm_next; | | 797 | softn->ipf_hm_maplist->hm_pnext = &hm->hm_next; |
798 | softn->ipf_hm_maplist = hm; | | 798 | softn->ipf_hm_maplist = hm; |
799 | hm->hm_hnext = softn->ipf_hm_maptable[hv]; | | 799 | hm->hm_hnext = softn->ipf_hm_maptable[hv]; |
800 | hm->hm_phnext = softn->ipf_hm_maptable + hv; | | 800 | hm->hm_phnext = softn->ipf_hm_maptable + hv; |
801 | if (softn->ipf_hm_maptable[hv] != NULL) | | 801 | if (softn->ipf_hm_maptable[hv] != NULL) |
802 | softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; | | 802 | softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; |
803 | softn->ipf_hm_maptable[hv] = hm; | | 803 | softn->ipf_hm_maptable[hv] = hm; |
804 | hm->hm_ipnat = np; | | 804 | hm->hm_ipnat = np; |
805 | np->in_use++; | | 805 | np->in_use++; |
806 | hm->hm_osrcip = src; | | 806 | hm->hm_osrcip = src; |
807 | hm->hm_odstip = dst; | | 807 | hm->hm_odstip = dst; |
808 | hm->hm_nsrcip = map; | | 808 | hm->hm_nsrcip = map; |
809 | hm->hm_ndstip.s_addr = 0; | | 809 | hm->hm_ndstip.s_addr = 0; |
810 | hm->hm_ref = 1; | | 810 | hm->hm_ref = 1; |
811 | hm->hm_port = port; | | 811 | hm->hm_port = port; |
812 | hm->hm_hv = rhv; | | 812 | hm->hm_hv = rhv; |
813 | hm->hm_v = 4; | | 813 | hm->hm_v = 4; |
814 | softn->ipf_nat_stats.ns_hm_new++; | | 814 | softn->ipf_nat_stats.ns_hm_new++; |
815 | } else { | | 815 | } else { |
816 | softn->ipf_nat_stats.ns_hm_newfail++; | | 816 | softn->ipf_nat_stats.ns_hm_newfail++; |
817 | } | | 817 | } |
818 | return hm; | | 818 | return hm; |
819 | } | | 819 | } |
820 | | | 820 | |
821 | | | 821 | |
822 | /* ------------------------------------------------------------------------ */ | | 822 | /* ------------------------------------------------------------------------ */ |
823 | /* Function: ipf_nat_hostmapdel */ | | 823 | /* Function: ipf_nat_hostmapdel */ |
824 | /* Returns: Nil */ | | 824 | /* Returns: Nil */ |
825 | /* Parameters: hmp(I) - pointer to hostmap structure pointer */ | | 825 | /* Parameters: hmp(I) - pointer to hostmap structure pointer */ |
826 | /* Write Locks: ipf_nat */ | | 826 | /* Write Locks: ipf_nat */ |
827 | /* */ | | 827 | /* */ |
828 | /* Decrement the references to this hostmap structure by one. If this */ | | 828 | /* Decrement the references to this hostmap structure by one. If this */ |
829 | /* reaches zero then remove it and free it. */ | | 829 | /* reaches zero then remove it and free it. */ |
830 | /* ------------------------------------------------------------------------ */ | | 830 | /* ------------------------------------------------------------------------ */ |
831 | void | | 831 | void |
832 | ipf_nat_hostmapdel(ipf_main_softc_t *softc, struct hostmap **hmp) | | 832 | ipf_nat_hostmapdel(ipf_main_softc_t *softc, struct hostmap **hmp) |
833 | { | | 833 | { |
834 | struct hostmap *hm; | | 834 | struct hostmap *hm; |
835 | | | 835 | |
836 | hm = *hmp; | | 836 | hm = *hmp; |
837 | *hmp = NULL; | | 837 | *hmp = NULL; |
838 | | | 838 | |
839 | hm->hm_ref--; | | 839 | hm->hm_ref--; |
840 | if (hm->hm_ref == 0) { | | 840 | if (hm->hm_ref == 0) { |
841 | ipf_nat_rule_deref(softc, &hm->hm_ipnat); | | 841 | ipf_nat_rule_deref(softc, &hm->hm_ipnat); |
842 | if (hm->hm_hnext) | | 842 | if (hm->hm_hnext) |
843 | hm->hm_hnext->hm_phnext = hm->hm_phnext; | | 843 | hm->hm_hnext->hm_phnext = hm->hm_phnext; |
844 | *hm->hm_phnext = hm->hm_hnext; | | 844 | *hm->hm_phnext = hm->hm_hnext; |
845 | if (hm->hm_next) | | 845 | if (hm->hm_next) |
846 | hm->hm_next->hm_pnext = hm->hm_pnext; | | 846 | hm->hm_next->hm_pnext = hm->hm_pnext; |
847 | *hm->hm_pnext = hm->hm_next; | | 847 | *hm->hm_pnext = hm->hm_next; |
848 | KFREE(hm); | | 848 | KFREE(hm); |
849 | } | | 849 | } |
850 | } | | 850 | } |
851 | | | 851 | |
852 | | | 852 | |
853 | /* ------------------------------------------------------------------------ */ | | 853 | /* ------------------------------------------------------------------------ */ |
854 | /* Function: ipf_fix_outcksum */ | | 854 | /* Function: ipf_fix_outcksum */ |
855 | /* Returns: Nil */ | | 855 | /* Returns: Nil */ |
856 | /* Parameters: fin(I) - pointer to packet information */ | | 856 | /* Parameters: fin(I) - pointer to packet information */ |
857 | /* sp(I) - location of 16bit checksum to update */ | | 857 | /* sp(I) - location of 16bit checksum to update */ |
858 | /* n((I) - amount to adjust checksum by */ | | 858 | /* n((I) - amount to adjust checksum by */ |
859 | /* */ | | 859 | /* */ |
860 | /* Adjusts the 16bit checksum by "n" for packets going out. */ | | 860 | /* Adjusts the 16bit checksum by "n" for packets going out. */ |
861 | /* ------------------------------------------------------------------------ */ | | 861 | /* ------------------------------------------------------------------------ */ |
862 | void | | 862 | void |
863 | ipf_fix_outcksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) | | 863 | ipf_fix_outcksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) |
864 | { | | 864 | { |
865 | u_short sumshort; | | 865 | u_short sumshort; |
866 | u_32_t sum1; | | 866 | u_32_t sum1; |
867 | | | 867 | |
868 | if (n == 0) | | 868 | if (n == 0) |
869 | return; | | 869 | return; |
870 | | | 870 | |
871 | if (cksum == 4) { | | 871 | if (cksum == 4) { |
872 | *sp = 0; | | 872 | *sp = 0; |
873 | return; | | 873 | return; |
874 | } | | 874 | } |
875 | if (cksum == 2) { | | 875 | if (cksum == 2) { |
876 | sum1 = partial; | | 876 | sum1 = partial; |
877 | sum1 = (sum1 & 0xffff) + (sum1 >> 16); | | 877 | sum1 = (sum1 & 0xffff) + (sum1 >> 16); |
878 | *sp = htons(sum1); | | 878 | *sp = htons(sum1); |
879 | return; | | 879 | return; |
880 | } | | 880 | } |
881 | sum1 = (~ntohs(*sp)) & 0xffff; | | 881 | sum1 = (~ntohs(*sp)) & 0xffff; |
882 | sum1 += (n); | | 882 | sum1 += (n); |
883 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); | | 883 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); |
884 | /* Again */ | | 884 | /* Again */ |
885 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); | | 885 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); |
886 | sumshort = ~(u_short)sum1; | | 886 | sumshort = ~(u_short)sum1; |
887 | *(sp) = htons(sumshort); | | 887 | *(sp) = htons(sumshort); |
888 | } | | 888 | } |
889 | | | 889 | |
890 | | | 890 | |
891 | /* ------------------------------------------------------------------------ */ | | 891 | /* ------------------------------------------------------------------------ */ |
892 | /* Function: ipf_fix_incksum */ | | 892 | /* Function: ipf_fix_incksum */ |
893 | /* Returns: Nil */ | | 893 | /* Returns: Nil */ |
894 | /* Parameters: fin(I) - pointer to packet information */ | | 894 | /* Parameters: fin(I) - pointer to packet information */ |
895 | /* sp(I) - location of 16bit checksum to update */ | | 895 | /* sp(I) - location of 16bit checksum to update */ |
896 | /* n((I) - amount to adjust checksum by */ | | 896 | /* n((I) - amount to adjust checksum by */ |
897 | /* */ | | 897 | /* */ |
898 | /* Adjusts the 16bit checksum by "n" for packets going in. */ | | 898 | /* Adjusts the 16bit checksum by "n" for packets going in. */ |
899 | /* ------------------------------------------------------------------------ */ | | 899 | /* ------------------------------------------------------------------------ */ |
900 | void | | 900 | void |
901 | ipf_fix_incksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) | | 901 | ipf_fix_incksum(int cksum, u_short *sp, u_32_t n, u_32_t partial) |
902 | { | | 902 | { |
903 | u_short sumshort; | | 903 | u_short sumshort; |
904 | u_32_t sum1; | | 904 | u_32_t sum1; |
905 | | | 905 | |
906 | if (n == 0) | | 906 | if (n == 0) |
907 | return; | | 907 | return; |
908 | | | 908 | |
909 | if (cksum == 4) { | | 909 | if (cksum == 4) { |
910 | *sp = 0; | | 910 | *sp = 0; |
911 | return; | | 911 | return; |
912 | } | | 912 | } |
913 | if (cksum == 2) { | | 913 | if (cksum == 2) { |
914 | sum1 = partial; | | 914 | sum1 = partial; |
915 | sum1 = (sum1 & 0xffff) + (sum1 >> 16); | | 915 | sum1 = (sum1 & 0xffff) + (sum1 >> 16); |
916 | *sp = htons(sum1); | | 916 | *sp = htons(sum1); |
917 | return; | | 917 | return; |
918 | } | | 918 | } |
919 | | | 919 | |
920 | sum1 = (~ntohs(*sp)) & 0xffff; | | 920 | sum1 = (~ntohs(*sp)) & 0xffff; |
921 | sum1 += ~(n) & 0xffff; | | 921 | sum1 += ~(n) & 0xffff; |
922 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); | | 922 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); |
923 | /* Again */ | | 923 | /* Again */ |
924 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); | | 924 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); |
925 | sumshort = ~(u_short)sum1; | | 925 | sumshort = ~(u_short)sum1; |
926 | *(sp) = htons(sumshort); | | 926 | *(sp) = htons(sumshort); |
927 | } | | 927 | } |
928 | | | 928 | |
929 | | | 929 | |
930 | /* ------------------------------------------------------------------------ */ | | 930 | /* ------------------------------------------------------------------------ */ |
931 | /* Function: ipf_fix_datacksum */ | | 931 | /* Function: ipf_fix_datacksum */ |
932 | /* Returns: Nil */ | | 932 | /* Returns: Nil */ |
933 | /* Parameters: sp(I) - location of 16bit checksum to update */ | | 933 | /* Parameters: sp(I) - location of 16bit checksum to update */ |
934 | /* n((I) - amount to adjust checksum by */ | | 934 | /* n((I) - amount to adjust checksum by */ |
935 | /* */ | | 935 | /* */ |
936 | /* Fix_datacksum is used *only* for the adjustments of checksums in the */ | | 936 | /* Fix_datacksum is used *only* for the adjustments of checksums in the */ |
937 | /* data section of an IP packet. */ | | 937 | /* data section of an IP packet. */ |
938 | /* */ | | 938 | /* */ |
939 | /* The only situation in which you need to do this is when NAT'ing an */ | | 939 | /* The only situation in which you need to do this is when NAT'ing an */ |
940 | /* ICMP error message. Such a message, contains in its body the IP header */ | | 940 | /* ICMP error message. Such a message, contains in its body the IP header */ |
941 | /* of the original IP packet, that causes the error. */ | | 941 | /* of the original IP packet, that causes the error. */ |
942 | /* */ | | 942 | /* */ |
943 | /* You can't use fix_incksum or fix_outcksum in that case, because for the */ | | 943 | /* You can't use fix_incksum or fix_outcksum in that case, because for the */ |
944 | /* kernel the data section of the ICMP error is just data, and no special */ | | 944 | /* kernel the data section of the ICMP error is just data, and no special */ |
945 | /* processing like hardware cksum or ntohs processing have been done by the */ | | 945 | /* processing like hardware cksum or ntohs processing have been done by the */ |
946 | /* kernel on the data section. */ | | 946 | /* kernel on the data section. */ |
947 | /* ------------------------------------------------------------------------ */ | | 947 | /* ------------------------------------------------------------------------ */ |
948 | void | | 948 | void |
949 | ipf_fix_datacksum(u_short *sp, u_32_t n) | | 949 | ipf_fix_datacksum(u_short *sp, u_32_t n) |
950 | { | | 950 | { |
951 | u_short sumshort; | | 951 | u_short sumshort; |
952 | u_32_t sum1; | | 952 | u_32_t sum1; |
953 | | | 953 | |
954 | if (n == 0) | | 954 | if (n == 0) |
955 | return; | | 955 | return; |
956 | | | 956 | |
957 | sum1 = (~ntohs(*sp)) & 0xffff; | | 957 | sum1 = (~ntohs(*sp)) & 0xffff; |
958 | sum1 += (n); | | 958 | sum1 += (n); |
959 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); | | 959 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); |
960 | /* Again */ | | 960 | /* Again */ |
961 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); | | 961 | sum1 = (sum1 >> 16) + (sum1 & 0xffff); |
962 | sumshort = ~(u_short)sum1; | | 962 | sumshort = ~(u_short)sum1; |
963 | *(sp) = htons(sumshort); | | 963 | *(sp) = htons(sumshort); |
964 | } | | 964 | } |
965 | | | 965 | |
966 | | | 966 | |
967 | /* ------------------------------------------------------------------------ */ | | 967 | /* ------------------------------------------------------------------------ */ |
968 | /* Function: ipf_nat_ioctl */ | | 968 | /* Function: ipf_nat_ioctl */ |
969 | /* Returns: int - 0 == success, != 0 == failure */ | | 969 | /* Returns: int - 0 == success, != 0 == failure */ |
970 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 970 | /* Parameters: softc(I) - pointer to soft context main structure */ |
971 | /* data(I) - pointer to ioctl data */ | | 971 | /* data(I) - pointer to ioctl data */ |
972 | /* cmd(I) - ioctl command integer */ | | 972 | /* cmd(I) - ioctl command integer */ |
973 | /* mode(I) - file mode bits used with open */ | | 973 | /* mode(I) - file mode bits used with open */ |
974 | /* uid(I) - uid of calling process */ | | 974 | /* uid(I) - uid of calling process */ |
975 | /* ctx(I) - pointer used as key for finding context */ | | 975 | /* ctx(I) - pointer used as key for finding context */ |
976 | /* */ | | 976 | /* */ |
977 | /* Processes an ioctl call made to operate on the IP Filter NAT device. */ | | 977 | /* Processes an ioctl call made to operate on the IP Filter NAT device. */ |
978 | /* ------------------------------------------------------------------------ */ | | 978 | /* ------------------------------------------------------------------------ */ |
979 | int | | 979 | int |
980 | ipf_nat_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, | | 980 | ipf_nat_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, |
981 | int uid, void *ctx) | | 981 | int uid, void *ctx) |
982 | { | | 982 | { |
983 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 983 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
984 | int error = 0, ret, arg, getlock; | | 984 | int error = 0, ret, arg, getlock; |
985 | ipnat_t *nat, *nt, *n; | | 985 | ipnat_t *nat, *nt, *n; |
986 | ipnat_t *natd = NULL; | | 986 | ipnat_t *natd = NULL; |
987 | SPL_INT(s); | | 987 | SPL_INT(s); |
988 | | | 988 | |
989 | #if BSD_GE_YEAR(199306) && defined(_KERNEL) | | 989 | #if BSD_GE_YEAR(199306) && defined(_KERNEL) |
990 | # if NETBSD_GE_REV(399002000) | | 990 | # if NETBSD_GE_REV(399002000) |
991 | if ((mode & FWRITE) && | | 991 | if ((mode & FWRITE) && |
992 | kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL, | | 992 | kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL, |
993 | KAUTH_REQ_NETWORK_FIREWALL_FW, | | 993 | KAUTH_REQ_NETWORK_FIREWALL_FW, |
994 | NULL, NULL, NULL)) | | 994 | NULL, NULL, NULL)) |
995 | # else | | 995 | # else |
996 | # if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034) | | 996 | # if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034) |
997 | if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE)) | | 997 | if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE)) |
998 | # else | | 998 | # else |
999 | if ((securelevel >= 3) && (mode & FWRITE)) | | 999 | if ((securelevel >= 3) && (mode & FWRITE)) |
1000 | # endif | | 1000 | # endif |
1001 | # endif | | 1001 | # endif |
1002 | { | | 1002 | { |
1003 | IPFERROR(60001); | | 1003 | IPFERROR(60001); |
1004 | return EPERM; | | 1004 | return EPERM; |
1005 | } | | 1005 | } |
1006 | #endif | | 1006 | #endif |
1007 | | | 1007 | |
1008 | #if defined(__osf__) && defined(_KERNEL) | | 1008 | #if defined(__osf__) && defined(_KERNEL) |
1009 | getlock = 0; | | 1009 | getlock = 0; |
1010 | #else | | 1010 | #else |
1011 | getlock = (mode & NAT_LOCKHELD) ? 0 : 1; | | 1011 | getlock = (mode & NAT_LOCKHELD) ? 0 : 1; |
1012 | #endif | | 1012 | #endif |
1013 | | | 1013 | |
1014 | n = NULL; | | 1014 | n = NULL; |
1015 | nt = NULL; | | 1015 | nt = NULL; |
1016 | nat = NULL; | | 1016 | nat = NULL; |
1017 | | | 1017 | |
1018 | if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) || | | 1018 | if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) || |
1019 | (cmd == (ioctlcmd_t)SIOCPURGENAT)) { | | 1019 | (cmd == (ioctlcmd_t)SIOCPURGENAT)) { |
1020 | KMALLOC(natd, ipnat_t *); | | 1020 | KMALLOC(natd, ipnat_t *); |
1021 | if (natd == NULL) { | | 1021 | if (natd == NULL) { |
1022 | error = ENOMEM; | | 1022 | error = ENOMEM; |
1023 | goto done; | | 1023 | goto done; |
1024 | } | | 1024 | } |
1025 | if (mode & NAT_SYSSPACE) { | | 1025 | if (mode & NAT_SYSSPACE) { |
1026 | bcopy(data, natd, sizeof(*natd)); | | 1026 | bcopy(data, natd, sizeof(*natd)); |
1027 | nat = natd; | | 1027 | nat = natd; |
1028 | error = 0; | | 1028 | error = 0; |
1029 | } else { | | 1029 | } else { |
1030 | bzero(natd, sizeof(*natd)); | | 1030 | bzero(natd, sizeof(*natd)); |
1031 | error = ipf_inobj(softc, data, NULL, natd, | | 1031 | error = ipf_inobj(softc, data, NULL, natd, |
1032 | IPFOBJ_IPNAT); | | 1032 | IPFOBJ_IPNAT); |
1033 | if (error != 0) | | 1033 | if (error != 0) |
1034 | goto done; | | 1034 | goto done; |
1035 | | | 1035 | |
1036 | if (natd->in_size < sizeof(ipnat_t)) { | | 1036 | if (natd->in_size < sizeof(ipnat_t)) { |
1037 | error = EINVAL; | | 1037 | error = EINVAL; |
1038 | goto done; | | 1038 | goto done; |
1039 | } | | 1039 | } |
1040 | KMALLOCS(nt, ipnat_t *, natd->in_size); | | 1040 | KMALLOCS(nt, ipnat_t *, natd->in_size); |
1041 | if (nt == NULL) { | | 1041 | if (nt == NULL) { |
1042 | IPFERROR(60070); | | 1042 | IPFERROR(60070); |
1043 | error = ENOMEM; | | 1043 | error = ENOMEM; |
1044 | goto done; | | 1044 | goto done; |
1045 | } | | 1045 | } |
1046 | bzero(nt, natd->in_size); | | 1046 | bzero(nt, natd->in_size); |
1047 | error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT, | | 1047 | error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT, |
1048 | natd->in_size); | | 1048 | natd->in_size); |
1049 | if (error) | | 1049 | if (error) |
1050 | goto done; | | 1050 | goto done; |
1051 | nat = nt; | | 1051 | nat = nt; |
1052 | } | | 1052 | } |
1053 | | | 1053 | |
1054 | /* | | 1054 | /* |
1055 | * For add/delete, look to see if the NAT entry is | | 1055 | * For add/delete, look to see if the NAT entry is |
1056 | * already present | | 1056 | * already present |
1057 | */ | | 1057 | */ |
1058 | nat->in_flags &= IPN_USERFLAGS; | | 1058 | nat->in_flags &= IPN_USERFLAGS; |
1059 | if ((nat->in_redir & NAT_MAPBLK) == 0) { | | 1059 | if ((nat->in_redir & NAT_MAPBLK) == 0) { |
1060 | if (nat->in_osrcatype == FRI_NORMAL || | | 1060 | if (nat->in_osrcatype == FRI_NORMAL || |
1061 | nat->in_osrcatype == FRI_NONE) | | 1061 | nat->in_osrcatype == FRI_NONE) |
1062 | nat->in_osrcaddr &= nat->in_osrcmsk; | | 1062 | nat->in_osrcaddr &= nat->in_osrcmsk; |
1063 | if (nat->in_odstatype == FRI_NORMAL || | | 1063 | if (nat->in_odstatype == FRI_NORMAL || |
1064 | nat->in_odstatype == FRI_NONE) | | 1064 | nat->in_odstatype == FRI_NONE) |
1065 | nat->in_odstaddr &= nat->in_odstmsk; | | 1065 | nat->in_odstaddr &= nat->in_odstmsk; |
1066 | if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) { | | 1066 | if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) { |
1067 | if (nat->in_nsrcatype == FRI_NORMAL) | | 1067 | if (nat->in_nsrcatype == FRI_NORMAL) |
1068 | nat->in_nsrcaddr &= nat->in_nsrcmsk; | | 1068 | nat->in_nsrcaddr &= nat->in_nsrcmsk; |
1069 | if (nat->in_ndstatype == FRI_NORMAL) | | 1069 | if (nat->in_ndstatype == FRI_NORMAL) |
1070 | nat->in_ndstaddr &= nat->in_ndstmsk; | | 1070 | nat->in_ndstaddr &= nat->in_ndstmsk; |
1071 | } | | 1071 | } |
1072 | } | | 1072 | } |
1073 | | | 1073 | |
1074 | error = ipf_nat_rule_init(softc, softn, nat); | | 1074 | error = ipf_nat_rule_init(softc, softn, nat); |
1075 | if (error != 0) | | 1075 | if (error != 0) |
1076 | goto done; | | 1076 | goto done; |
1077 | | | 1077 | |
1078 | MUTEX_ENTER(&softn->ipf_nat_io); | | 1078 | MUTEX_ENTER(&softn->ipf_nat_io); |
1079 | for (n = softn->ipf_nat_list; n != NULL; n = n->in_next) | | 1079 | for (n = softn->ipf_nat_list; n != NULL; n = n->in_next) |
1080 | if (ipf_nat_cmp_rules(nat, n) == 0) | | 1080 | if (ipf_nat_cmp_rules(nat, n) == 0) |
1081 | break; | | 1081 | break; |
1082 | } | | 1082 | } |
1083 | | | 1083 | |
1084 | switch (cmd) | | 1084 | switch (cmd) |
1085 | { | | 1085 | { |
1086 | #ifdef IPFILTER_LOG | | 1086 | #ifdef IPFILTER_LOG |
1087 | case SIOCIPFFB : | | 1087 | case SIOCIPFFB : |
1088 | { | | 1088 | { |
1089 | int tmp; | | 1089 | int tmp; |
1090 | | | 1090 | |
1091 | if (!(mode & FWRITE)) { | | 1091 | if (!(mode & FWRITE)) { |
1092 | IPFERROR(60002); | | 1092 | IPFERROR(60002); |
1093 | error = EPERM; | | 1093 | error = EPERM; |
1094 | } else { | | 1094 | } else { |
1095 | tmp = ipf_log_clear(softc, IPL_LOGNAT); | | 1095 | tmp = ipf_log_clear(softc, IPL_LOGNAT); |
1096 | error = BCOPYOUT(&tmp, data, sizeof(tmp)); | | 1096 | error = BCOPYOUT(&tmp, data, sizeof(tmp)); |
1097 | if (error != 0) { | | 1097 | if (error != 0) { |
1098 | IPFERROR(60057); | | 1098 | IPFERROR(60057); |
1099 | error = EFAULT; | | 1099 | error = EFAULT; |
1100 | } | | 1100 | } |
1101 | } | | 1101 | } |
1102 | break; | | 1102 | break; |
1103 | } | | 1103 | } |
1104 | | | 1104 | |
1105 | case SIOCSETLG : | | 1105 | case SIOCSETLG : |
1106 | if (!(mode & FWRITE)) { | | 1106 | if (!(mode & FWRITE)) { |
1107 | IPFERROR(60003); | | 1107 | IPFERROR(60003); |
1108 | error = EPERM; | | 1108 | error = EPERM; |
1109 | } else { | | 1109 | } else { |
1110 | error = BCOPYIN(data, &softn->ipf_nat_logging, | | 1110 | error = BCOPYIN(data, &softn->ipf_nat_logging, |
1111 | sizeof(softn->ipf_nat_logging)); | | 1111 | sizeof(softn->ipf_nat_logging)); |
1112 | if (error != 0) | | 1112 | if (error != 0) |
1113 | error = EFAULT; | | 1113 | error = EFAULT; |
1114 | } | | 1114 | } |
| @@ -5182,1999 +5182,1999 @@ ipf_nat_out(fr_info_t *fin, nat_t *nat, | | | @@ -5182,1999 +5182,1999 @@ ipf_nat_out(fr_info_t *fin, nat_t *nat, |
5182 | tcp->th_dport = nat->nat_ndport; | | 5182 | tcp->th_dport = nat->nat_ndport; |
5183 | fin->fin_data[1] = ntohs(nat->nat_ndport); | | 5183 | fin->fin_data[1] = ntohs(nat->nat_ndport); |
5184 | break; | | 5184 | break; |
5185 | | | 5185 | |
5186 | case NAT_INBOUND : | | 5186 | case NAT_INBOUND : |
5187 | tcp->th_sport = nat->nat_odport; | | 5187 | tcp->th_sport = nat->nat_odport; |
5188 | fin->fin_data[0] = ntohs(nat->nat_odport); | | 5188 | fin->fin_data[0] = ntohs(nat->nat_odport); |
5189 | tcp->th_dport = nat->nat_osport; | | 5189 | tcp->th_dport = nat->nat_osport; |
5190 | fin->fin_data[1] = ntohs(nat->nat_osport); | | 5190 | fin->fin_data[1] = ntohs(nat->nat_osport); |
5191 | break; | | 5191 | break; |
5192 | } | | 5192 | } |
5193 | } | | 5193 | } |
5194 | | | 5194 | |
5195 | if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { | | 5195 | if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { |
5196 | icmp = fin->fin_dp; | | 5196 | icmp = fin->fin_dp; |
5197 | | | 5197 | |
5198 | switch (nat->nat_dir) | | 5198 | switch (nat->nat_dir) |
5199 | { | | 5199 | { |
5200 | case NAT_OUTBOUND : | | 5200 | case NAT_OUTBOUND : |
5201 | icmp->icmp_id = nat->nat_nicmpid; | | 5201 | icmp->icmp_id = nat->nat_nicmpid; |
5202 | break; | | 5202 | break; |
5203 | case NAT_INBOUND : | | 5203 | case NAT_INBOUND : |
5204 | icmp->icmp_id = nat->nat_oicmpid; | | 5204 | icmp->icmp_id = nat->nat_oicmpid; |
5205 | break; | | 5205 | break; |
5206 | } | | 5206 | } |
5207 | } | | 5207 | } |
5208 | | | 5208 | |
5209 | csump = ipf_nat_proto(fin, nat, nflags); | | 5209 | csump = ipf_nat_proto(fin, nat, nflags); |
5210 | | | 5210 | |
5211 | /* | | 5211 | /* |
5212 | * The above comments do not hold for layer 4 (or higher) | | 5212 | * The above comments do not hold for layer 4 (or higher) |
5213 | * checksums... | | 5213 | * checksums... |
5214 | */ | | 5214 | */ |
5215 | if (csump != NULL) { | | 5215 | if (csump != NULL) { |
5216 | if (nat->nat_dir == NAT_OUTBOUND) | | 5216 | if (nat->nat_dir == NAT_OUTBOUND) |
5217 | ipf_fix_outcksum(fin->fin_cksum, csump, | | 5217 | ipf_fix_outcksum(fin->fin_cksum, csump, |
5218 | nat->nat_sumd[0], | | 5218 | nat->nat_sumd[0], |
5219 | nat->nat_sumd[1] + | | 5219 | nat->nat_sumd[1] + |
5220 | fin->fin_dlen); | | 5220 | fin->fin_dlen); |
5221 | else | | 5221 | else |
5222 | ipf_fix_incksum(fin->fin_cksum, csump, | | 5222 | ipf_fix_incksum(fin->fin_cksum, csump, |
5223 | nat->nat_sumd[0], | | 5223 | nat->nat_sumd[0], |
5224 | nat->nat_sumd[1] + | | 5224 | nat->nat_sumd[1] + |
5225 | fin->fin_dlen); | | 5225 | fin->fin_dlen); |
5226 | } | | 5226 | } |
5227 | } | | 5227 | } |
5228 | | | 5228 | |
5229 | ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); | | 5229 | ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); |
5230 | /* ------------------------------------------------------------- */ | | 5230 | /* ------------------------------------------------------------- */ |
5231 | /* A few quick notes: */ | | 5231 | /* A few quick notes: */ |
5232 | /* Following are test conditions prior to calling the */ | | 5232 | /* Following are test conditions prior to calling the */ |
5233 | /* ipf_proxy_check routine. */ | | 5233 | /* ipf_proxy_check routine. */ |
5234 | /* */ | | 5234 | /* */ |
5235 | /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ | | 5235 | /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ |
5236 | /* with a redirect rule, we attempt to match the packet's */ | | 5236 | /* with a redirect rule, we attempt to match the packet's */ |
5237 | /* source port against in_dport, otherwise we'd compare the */ | | 5237 | /* source port against in_dport, otherwise we'd compare the */ |
5238 | /* packet's destination. */ | | 5238 | /* packet's destination. */ |
5239 | /* ------------------------------------------------------------- */ | | 5239 | /* ------------------------------------------------------------- */ |
5240 | if ((np != NULL) && (np->in_apr != NULL)) { | | 5240 | if ((np != NULL) && (np->in_apr != NULL)) { |
5241 | i = ipf_proxy_check(fin, nat); | | 5241 | i = ipf_proxy_check(fin, nat); |
5242 | if (i == 0) { | | 5242 | if (i == 0) { |
5243 | i = 1; | | 5243 | i = 1; |
5244 | } else if (i == -1) { | | 5244 | } else if (i == -1) { |
5245 | NBUMPSIDED(1, ns_ipf_proxy_fail); | | 5245 | NBUMPSIDED(1, ns_ipf_proxy_fail); |
5246 | } | | 5246 | } |
5247 | } else { | | 5247 | } else { |
5248 | i = 1; | | 5248 | i = 1; |
5249 | } | | 5249 | } |
5250 | fin->fin_flx |= FI_NATED; | | 5250 | fin->fin_flx |= FI_NATED; |
5251 | return i; | | 5251 | return i; |
5252 | } | | 5252 | } |
5253 | | | 5253 | |
5254 | | | 5254 | |
5255 | /* ------------------------------------------------------------------------ */ | | 5255 | /* ------------------------------------------------------------------------ */ |
5256 | /* Function: ipf_nat_checkin */ | | 5256 | /* Function: ipf_nat_checkin */ |
5257 | /* Returns: int - -1 == packet failed NAT checks so block it, */ | | 5257 | /* Returns: int - -1 == packet failed NAT checks so block it, */ |
5258 | /* 0 == no packet translation occurred, */ | | 5258 | /* 0 == no packet translation occurred, */ |
5259 | /* 1 == packet was successfully translated. */ | | 5259 | /* 1 == packet was successfully translated. */ |
5260 | /* Parameters: fin(I) - pointer to packet information */ | | 5260 | /* Parameters: fin(I) - pointer to packet information */ |
5261 | /* passp(I) - pointer to filtering result flags */ | | 5261 | /* passp(I) - pointer to filtering result flags */ |
5262 | /* */ | | 5262 | /* */ |
5263 | /* Check to see if an incoming packet should be changed. ICMP packets are */ | | 5263 | /* Check to see if an incoming packet should be changed. ICMP packets are */ |
5264 | /* first checked to see if they match an existing entry (if an error), */ | | 5264 | /* first checked to see if they match an existing entry (if an error), */ |
5265 | /* otherwise a search of the current NAT table is made. If neither results */ | | 5265 | /* otherwise a search of the current NAT table is made. If neither results */ |
5266 | /* in a match then a search for a matching NAT rule is made. Create a new */ | | 5266 | /* in a match then a search for a matching NAT rule is made. Create a new */ |
5267 | /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ | | 5267 | /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ |
5268 | /* packet header(s) as required. */ | | 5268 | /* packet header(s) as required. */ |
5269 | /* ------------------------------------------------------------------------ */ | | 5269 | /* ------------------------------------------------------------------------ */ |
5270 | int | | 5270 | int |
5271 | ipf_nat_checkin(fr_info_t *fin, u_32_t *passp) | | 5271 | ipf_nat_checkin(fr_info_t *fin, u_32_t *passp) |
5272 | { | | 5272 | { |
5273 | ipf_main_softc_t *softc; | | 5273 | ipf_main_softc_t *softc; |
5274 | ipf_nat_softc_t *softn; | | 5274 | ipf_nat_softc_t *softn; |
5275 | u_int nflags, natadd; | | 5275 | u_int nflags, natadd; |
5276 | ipnat_t *np, *npnext; | | 5276 | ipnat_t *np, *npnext; |
5277 | int rval, natfailed; | | 5277 | int rval, natfailed; |
5278 | struct ifnet *ifp; | | 5278 | struct ifnet *ifp; |
5279 | struct in_addr in; | | 5279 | struct in_addr in; |
5280 | icmphdr_t *icmp; | | 5280 | icmphdr_t *icmp; |
5281 | tcphdr_t *tcp; | | 5281 | tcphdr_t *tcp; |
5282 | u_short dport; | | 5282 | u_short dport; |
5283 | nat_t *nat; | | 5283 | nat_t *nat; |
5284 | u_32_t iph; | | 5284 | u_32_t iph; |
5285 | | | 5285 | |
5286 | softc = fin->fin_main_soft; | | 5286 | softc = fin->fin_main_soft; |
5287 | softn = softc->ipf_nat_soft; | | 5287 | softn = softc->ipf_nat_soft; |
5288 | | | 5288 | |
5289 | if (softn->ipf_nat_lock != 0) | | 5289 | if (softn->ipf_nat_lock != 0) |
5290 | return 0; | | 5290 | return 0; |
5291 | if (softn->ipf_nat_stats.ns_rules == 0 && | | 5291 | if (softn->ipf_nat_stats.ns_rules == 0 && |
5292 | softn->ipf_nat_instances == NULL) | | 5292 | softn->ipf_nat_instances == NULL) |
5293 | return 0; | | 5293 | return 0; |
5294 | | | 5294 | |
5295 | tcp = NULL; | | 5295 | tcp = NULL; |
5296 | icmp = NULL; | | 5296 | icmp = NULL; |
5297 | dport = 0; | | 5297 | dport = 0; |
5298 | natadd = 1; | | 5298 | natadd = 1; |
5299 | nflags = 0; | | 5299 | nflags = 0; |
5300 | natfailed = 0; | | 5300 | natfailed = 0; |
5301 | ifp = fin->fin_ifp; | | 5301 | ifp = fin->fin_ifp; |
5302 | | | 5302 | |
5303 | if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { | | 5303 | if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { |
5304 | switch (fin->fin_p) | | 5304 | switch (fin->fin_p) |
5305 | { | | 5305 | { |
5306 | case IPPROTO_TCP : | | 5306 | case IPPROTO_TCP : |
5307 | nflags = IPN_TCP; | | 5307 | nflags = IPN_TCP; |
5308 | break; | | 5308 | break; |
5309 | case IPPROTO_UDP : | | 5309 | case IPPROTO_UDP : |
5310 | nflags = IPN_UDP; | | 5310 | nflags = IPN_UDP; |
5311 | break; | | 5311 | break; |
5312 | case IPPROTO_ICMP : | | 5312 | case IPPROTO_ICMP : |
5313 | icmp = fin->fin_dp; | | 5313 | icmp = fin->fin_dp; |
5314 | | | 5314 | |
5315 | /* | | 5315 | /* |
5316 | * This is an incoming packet, so the destination is | | 5316 | * This is an incoming packet, so the destination is |
5317 | * the icmp_id and the source port equals 0 | | 5317 | * the icmp_id and the source port equals 0 |
5318 | */ | | 5318 | */ |
5319 | if ((fin->fin_flx & FI_ICMPQUERY) != 0) { | | 5319 | if ((fin->fin_flx & FI_ICMPQUERY) != 0) { |
5320 | nflags = IPN_ICMPQUERY; | | 5320 | nflags = IPN_ICMPQUERY; |
5321 | dport = icmp->icmp_id; | | 5321 | dport = icmp->icmp_id; |
5322 | } break; | | 5322 | } break; |
5323 | default : | | 5323 | default : |
5324 | break; | | 5324 | break; |
5325 | } | | 5325 | } |
5326 | | | 5326 | |
5327 | if ((nflags & IPN_TCPUDP)) { | | 5327 | if ((nflags & IPN_TCPUDP)) { |
5328 | tcp = fin->fin_dp; | | 5328 | tcp = fin->fin_dp; |
5329 | dport = fin->fin_data[1]; | | 5329 | dport = fin->fin_data[1]; |
5330 | } | | 5330 | } |
5331 | } | | 5331 | } |
5332 | | | 5332 | |
5333 | in = fin->fin_dst; | | 5333 | in = fin->fin_dst; |
5334 | | | 5334 | |
5335 | READ_ENTER(&softc->ipf_nat); | | 5335 | READ_ENTER(&softc->ipf_nat); |
5336 | | | 5336 | |
5337 | if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && | | 5337 | if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && |
5338 | (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND))) | | 5338 | (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND))) |
5339 | /*EMPTY*/; | | 5339 | /*EMPTY*/; |
5340 | else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) | | 5340 | else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin))) |
5341 | natadd = 0; | | 5341 | natadd = 0; |
5342 | else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH, | | 5342 | else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH, |
5343 | (u_int)fin->fin_p, | | 5343 | (u_int)fin->fin_p, |
5344 | fin->fin_src, in))) { | | 5344 | fin->fin_src, in))) { |
5345 | nflags = nat->nat_flags; | | 5345 | nflags = nat->nat_flags; |
5346 | } else if (fin->fin_off == 0) { | | 5346 | } else if (fin->fin_off == 0) { |
5347 | u_32_t hv, msk, rmsk = 0; | | 5347 | u_32_t hv, msk, rmsk = 0; |
5348 | | | 5348 | |
5349 | /* | | 5349 | /* |
5350 | * If there is no current entry in the nat table for this IP#, | | 5350 | * If there is no current entry in the nat table for this IP#, |
5351 | * create one for it (if there is a matching rule). | | 5351 | * create one for it (if there is a matching rule). |
5352 | */ | | 5352 | */ |
5353 | maskloop: | | 5353 | maskloop: |
5354 | msk = softn->ipf_nat_rdr_active_masks[rmsk]; | | 5354 | msk = softn->ipf_nat_rdr_active_masks[rmsk]; |
5355 | iph = in.s_addr & msk; | | 5355 | iph = in.s_addr & msk; |
5356 | hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz); | | 5356 | hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz); |
5357 | retry_roundrobin: | | 5357 | retry_roundrobin: |
5358 | /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */ | | 5358 | /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */ |
5359 | for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) { | | 5359 | for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) { |
5360 | npnext = np->in_rnext; | | 5360 | npnext = np->in_rnext; |
5361 | if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) | | 5361 | if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) |
5362 | continue; | | 5362 | continue; |
5363 | if (np->in_v[0] != 4) | | 5363 | if (np->in_v[0] != 4) |
5364 | continue; | | 5364 | continue; |
5365 | if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p)) | | 5365 | if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p)) |
5366 | continue; | | 5366 | continue; |
5367 | if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) | | 5367 | if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) |
5368 | continue; | | 5368 | continue; |
5369 | if (np->in_flags & IPN_FILTER) { | | 5369 | if (np->in_flags & IPN_FILTER) { |
5370 | switch (ipf_nat_match(fin, np)) | | 5370 | switch (ipf_nat_match(fin, np)) |
5371 | { | | 5371 | { |
5372 | case 0 : | | 5372 | case 0 : |
5373 | continue; | | 5373 | continue; |
5374 | case -1 : | | 5374 | case -1 : |
5375 | rval = -1; | | 5375 | rval = -1; |
5376 | goto inmatchfail; | | 5376 | goto inmatchfail; |
5377 | case 1 : | | 5377 | case 1 : |
5378 | default : | | 5378 | default : |
5379 | break; | | 5379 | break; |
5380 | } | | 5380 | } |
5381 | } else { | | 5381 | } else { |
5382 | if ((in.s_addr & np->in_odstmsk) != | | 5382 | if ((in.s_addr & np->in_odstmsk) != |
5383 | np->in_odstaddr) | | 5383 | np->in_odstaddr) |
5384 | continue; | | 5384 | continue; |
5385 | if (np->in_odport && | | 5385 | if (np->in_odport && |
5386 | ((np->in_dtop < dport) || | | 5386 | ((np->in_dtop < dport) || |
5387 | (dport < np->in_odport))) | | 5387 | (dport < np->in_odport))) |
5388 | continue; | | 5388 | continue; |
5389 | } | | 5389 | } |
5390 | | | 5390 | |
5391 | if (np->in_plabel != -1) { | | 5391 | if (np->in_plabel != -1) { |
5392 | if (!ipf_proxy_ok(fin, tcp, np)) { | | 5392 | if (!ipf_proxy_ok(fin, tcp, np)) { |
5393 | continue; | | 5393 | continue; |
5394 | } | | 5394 | } |
5395 | } | | 5395 | } |
5396 | | | 5396 | |
5397 | if (np->in_flags & IPN_NO) { | | 5397 | if (np->in_flags & IPN_NO) { |
5398 | np->in_hits++; | | 5398 | np->in_hits++; |
5399 | break; | | 5399 | break; |
5400 | } | | 5400 | } |
5401 | | | 5401 | |
5402 | MUTEX_ENTER(&softn->ipf_nat_new); | | 5402 | MUTEX_ENTER(&softn->ipf_nat_new); |
5403 | /* | | 5403 | /* |
5404 | * If we've matched a round-robin rule but it has | | 5404 | * If we've matched a round-robin rule but it has |
5405 | * moved in the list since we got it, start over as | | 5405 | * moved in the list since we got it, start over as |
5406 | * this is now no longer correct. | | 5406 | * this is now no longer correct. |
5407 | */ | | 5407 | */ |
5408 | if (npnext != np->in_rnext) { | | 5408 | if (npnext != np->in_rnext) { |
5409 | if ((np->in_flags & IPN_ROUNDR) != 0) { | | 5409 | if ((np->in_flags & IPN_ROUNDR) != 0) { |
5410 | MUTEX_EXIT(&softn->ipf_nat_new); | | 5410 | MUTEX_EXIT(&softn->ipf_nat_new); |
5411 | goto retry_roundrobin; | | 5411 | goto retry_roundrobin; |
5412 | } | | 5412 | } |
5413 | npnext = np->in_rnext; | | 5413 | npnext = np->in_rnext; |
5414 | } | | 5414 | } |
5415 | | | 5415 | |
5416 | nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND); | | 5416 | nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND); |
5417 | MUTEX_EXIT(&softn->ipf_nat_new); | | 5417 | MUTEX_EXIT(&softn->ipf_nat_new); |
5418 | if (nat != NULL) { | | 5418 | if (nat != NULL) { |
5419 | natfailed = 0; | | 5419 | natfailed = 0; |
5420 | break; | | 5420 | break; |
5421 | } | | 5421 | } |
5422 | natfailed = -1; | | 5422 | natfailed = -1; |
5423 | } | | 5423 | } |
5424 | if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) { | | 5424 | if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) { |
5425 | rmsk++; | | 5425 | rmsk++; |
5426 | goto maskloop; | | 5426 | goto maskloop; |
5427 | } | | 5427 | } |
5428 | } | | 5428 | } |
5429 | | | 5429 | |
5430 | if (nat != NULL) { | | 5430 | if (nat != NULL) { |
5431 | rval = ipf_nat_in(fin, nat, natadd, nflags); | | 5431 | rval = ipf_nat_in(fin, nat, natadd, nflags); |
5432 | if (rval == 1) { | | 5432 | if (rval == 1) { |
5433 | MUTEX_ENTER(&nat->nat_lock); | | 5433 | MUTEX_ENTER(&nat->nat_lock); |
5434 | ipf_nat_update(fin, nat); | | 5434 | ipf_nat_update(fin, nat); |
5435 | nat->nat_bytes[0] += fin->fin_plen; | | 5435 | nat->nat_bytes[0] += fin->fin_plen; |
5436 | nat->nat_pkts[0]++; | | 5436 | nat->nat_pkts[0]++; |
5437 | fin->fin_pktnum = nat->nat_pkts[0]; | | 5437 | fin->fin_pktnum = nat->nat_pkts[0]; |
5438 | MUTEX_EXIT(&nat->nat_lock); | | 5438 | MUTEX_EXIT(&nat->nat_lock); |
5439 | } | | 5439 | } |
5440 | } else | | 5440 | } else |
5441 | rval = natfailed; | | 5441 | rval = natfailed; |
5442 | inmatchfail: | | 5442 | inmatchfail: |
5443 | RWLOCK_EXIT(&softc->ipf_nat); | | 5443 | RWLOCK_EXIT(&softc->ipf_nat); |
5444 | | | 5444 | |
5445 | switch (rval) | | 5445 | switch (rval) |
5446 | { | | 5446 | { |
5447 | case -1 : | | 5447 | case -1 : |
5448 | if (passp != NULL) { | | 5448 | if (passp != NULL) { |
5449 | DT1(frb_natv4in, fr_info_t *, fin); | | 5449 | DT1(frb_natv4in, fr_info_t *, fin); |
5450 | NBUMPSIDED(0, ns_drop); | | 5450 | NBUMPSIDED(0, ns_drop); |
5451 | *passp = FR_BLOCK; | | 5451 | *passp = FR_BLOCK; |
5452 | fin->fin_reason = FRB_NATV4; | | 5452 | fin->fin_reason = FRB_NATV4; |
5453 | } | | 5453 | } |
5454 | fin->fin_flx |= FI_BADNAT; | | 5454 | fin->fin_flx |= FI_BADNAT; |
5455 | NBUMPSIDED(0, ns_badnat); | | 5455 | NBUMPSIDED(0, ns_badnat); |
5456 | break; | | 5456 | break; |
5457 | case 0 : | | 5457 | case 0 : |
5458 | NBUMPSIDE(0, ns_ignored); | | 5458 | NBUMPSIDE(0, ns_ignored); |
5459 | break; | | 5459 | break; |
5460 | case 1 : | | 5460 | case 1 : |
5461 | NBUMPSIDE(0, ns_translated); | | 5461 | NBUMPSIDE(0, ns_translated); |
5462 | break; | | 5462 | break; |
5463 | } | | 5463 | } |
5464 | return rval; | | 5464 | return rval; |
5465 | } | | 5465 | } |
5466 | | | 5466 | |
5467 | | | 5467 | |
5468 | /* ------------------------------------------------------------------------ */ | | 5468 | /* ------------------------------------------------------------------------ */ |
5469 | /* Function: ipf_nat_in */ | | 5469 | /* Function: ipf_nat_in */ |
5470 | /* Returns: int - -1 == packet failed NAT checks so block it, */ | | 5470 | /* Returns: int - -1 == packet failed NAT checks so block it, */ |
5471 | /* 1 == packet was successfully translated. */ | | 5471 | /* 1 == packet was successfully translated. */ |
5472 | /* Parameters: fin(I) - pointer to packet information */ | | 5472 | /* Parameters: fin(I) - pointer to packet information */ |
5473 | /* nat(I) - pointer to NAT structure */ | | 5473 | /* nat(I) - pointer to NAT structure */ |
5474 | /* natadd(I) - flag indicating if it is safe to add frag cache */ | | 5474 | /* natadd(I) - flag indicating if it is safe to add frag cache */ |
5475 | /* nflags(I) - NAT flags set for this packet */ | | 5475 | /* nflags(I) - NAT flags set for this packet */ |
5476 | /* Locks Held: ipf_nat(READ) */ | | 5476 | /* Locks Held: ipf_nat(READ) */ |
5477 | /* */ | | 5477 | /* */ |
5478 | /* Translate a packet coming "in" on an interface. */ | | 5478 | /* Translate a packet coming "in" on an interface. */ |
5479 | /* ------------------------------------------------------------------------ */ | | 5479 | /* ------------------------------------------------------------------------ */ |
5480 | int | | 5480 | int |
5481 | ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) | | 5481 | ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags) |
5482 | { | | 5482 | { |
5483 | ipf_main_softc_t *softc = fin->fin_main_soft; | | 5483 | ipf_main_softc_t *softc = fin->fin_main_soft; |
5484 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 5484 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
5485 | u_32_t sumd, ipsumd, sum1, sum2; | | 5485 | u_32_t sumd, ipsumd, sum1, sum2; |
5486 | icmphdr_t *icmp; | | 5486 | icmphdr_t *icmp; |
5487 | tcphdr_t *tcp; | | 5487 | tcphdr_t *tcp; |
5488 | ipnat_t *np; | | 5488 | ipnat_t *np; |
5489 | int skip; | | 5489 | int skip; |
5490 | int i; | | 5490 | int i; |
5491 | | | 5491 | |
5492 | tcp = NULL; | | 5492 | tcp = NULL; |
5493 | np = nat->nat_ptr; | | 5493 | np = nat->nat_ptr; |
5494 | fin->fin_fr = nat->nat_fr; | | 5494 | fin->fin_fr = nat->nat_fr; |
5495 | | | 5495 | |
5496 | if (np != NULL) { | | 5496 | if (np != NULL) { |
5497 | if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) | | 5497 | if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) |
5498 | (void) ipf_frag_natnew(softc, fin, 0, nat); | | 5498 | (void) ipf_frag_natnew(softc, fin, 0, nat); |
5499 | | | 5499 | |
5500 | /* ------------------------------------------------------------- */ | | 5500 | /* ------------------------------------------------------------- */ |
5501 | /* A few quick notes: */ | | 5501 | /* A few quick notes: */ |
5502 | /* Following are test conditions prior to calling the */ | | 5502 | /* Following are test conditions prior to calling the */ |
5503 | /* ipf_proxy_check routine. */ | | 5503 | /* ipf_proxy_check routine. */ |
5504 | /* */ | | 5504 | /* */ |
5505 | /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ | | 5505 | /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ |
5506 | /* with a map rule, we attempt to match the packet's */ | | 5506 | /* with a map rule, we attempt to match the packet's */ |
5507 | /* source port against in_dport, otherwise we'd compare the */ | | 5507 | /* source port against in_dport, otherwise we'd compare the */ |
5508 | /* packet's destination. */ | | 5508 | /* packet's destination. */ |
5509 | /* ------------------------------------------------------------- */ | | 5509 | /* ------------------------------------------------------------- */ |
5510 | if (np->in_apr != NULL) { | | 5510 | if (np->in_apr != NULL) { |
5511 | i = ipf_proxy_check(fin, nat); | | 5511 | i = ipf_proxy_check(fin, nat); |
5512 | if (i == -1) { | | 5512 | if (i == -1) { |
5513 | NBUMPSIDED(0, ns_ipf_proxy_fail); | | 5513 | NBUMPSIDED(0, ns_ipf_proxy_fail); |
5514 | return -1; | | 5514 | return -1; |
5515 | } | | 5515 | } |
5516 | } | | 5516 | } |
5517 | } | | 5517 | } |
5518 | | | 5518 | |
5519 | ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); | | 5519 | ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync); |
5520 | | | 5520 | |
5521 | ipsumd = nat->nat_ipsumd; | | 5521 | ipsumd = nat->nat_ipsumd; |
5522 | /* | | 5522 | /* |
5523 | * Fix up checksums, not by recalculating them, but | | 5523 | * Fix up checksums, not by recalculating them, but |
5524 | * simply computing adjustments. | | 5524 | * simply computing adjustments. |
5525 | * Why only do this for some platforms on inbound packets ? | | 5525 | * Why only do this for some platforms on inbound packets ? |
5526 | * Because for those that it is done, IP processing is yet to happen | | 5526 | * Because for those that it is done, IP processing is yet to happen |
5527 | * and so the IPv4 header checksum has not yet been evaluated. | | 5527 | * and so the IPv4 header checksum has not yet been evaluated. |
5528 | * Perhaps it should always be done for the benefit of things like | | 5528 | * Perhaps it should always be done for the benefit of things like |
5529 | * fast forwarding (so that it doesn't need to be recomputed) but with | | 5529 | * fast forwarding (so that it doesn't need to be recomputed) but with |
5530 | * header checksum offloading, perhaps it is a moot point. | | 5530 | * header checksum offloading, perhaps it is a moot point. |
5531 | */ | | 5531 | */ |
5532 | | | 5532 | |
5533 | switch (nat->nat_dir) | | 5533 | switch (nat->nat_dir) |
5534 | { | | 5534 | { |
5535 | case NAT_INBOUND : | | 5535 | case NAT_INBOUND : |
5536 | if ((fin->fin_flx & FI_ICMPERR) == 0) { | | 5536 | if ((fin->fin_flx & FI_ICMPERR) == 0) { |
5537 | fin->fin_ip->ip_src = nat->nat_nsrcip; | | 5537 | fin->fin_ip->ip_src = nat->nat_nsrcip; |
5538 | fin->fin_saddr = nat->nat_nsrcaddr; | | 5538 | fin->fin_saddr = nat->nat_nsrcaddr; |
5539 | } else { | | 5539 | } else { |
5540 | sum1 = nat->nat_osrcaddr; | | 5540 | sum1 = nat->nat_osrcaddr; |
5541 | sum2 = nat->nat_nsrcaddr; | | 5541 | sum2 = nat->nat_nsrcaddr; |
5542 | CALC_SUMD(sum1, sum2, sumd); | | 5542 | CALC_SUMD(sum1, sum2, sumd); |
5543 | ipsumd -= sumd; | | 5543 | ipsumd -= sumd; |
5544 | } | | 5544 | } |
5545 | fin->fin_ip->ip_dst = nat->nat_ndstip; | | 5545 | fin->fin_ip->ip_dst = nat->nat_ndstip; |
5546 | fin->fin_daddr = nat->nat_ndstaddr; | | 5546 | fin->fin_daddr = nat->nat_ndstaddr; |
5547 | #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ | | 5547 | #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ |
5548 | defined(__osf__) || defined(linux) | | 5548 | defined(__osf__) || defined(linux) |
5549 | ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); | | 5549 | ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); |
5550 | #endif | | 5550 | #endif |
5551 | break; | | 5551 | break; |
5552 | | | 5552 | |
5553 | case NAT_OUTBOUND : | | 5553 | case NAT_OUTBOUND : |
5554 | if ((fin->fin_flx & FI_ICMPERR) == 0) { | | 5554 | if ((fin->fin_flx & FI_ICMPERR) == 0) { |
5555 | fin->fin_ip->ip_src = nat->nat_odstip; | | 5555 | fin->fin_ip->ip_src = nat->nat_odstip; |
5556 | fin->fin_saddr = nat->nat_odstaddr; | | 5556 | fin->fin_saddr = nat->nat_odstaddr; |
5557 | } else { | | 5557 | } else { |
5558 | sum1 = nat->nat_odstaddr; | | 5558 | sum1 = nat->nat_odstaddr; |
5559 | sum2 = nat->nat_ndstaddr; | | 5559 | sum2 = nat->nat_ndstaddr; |
5560 | CALC_SUMD(sum1, sum2, sumd); | | 5560 | CALC_SUMD(sum1, sum2, sumd); |
5561 | ipsumd -= sumd; | | 5561 | ipsumd -= sumd; |
5562 | } | | 5562 | } |
5563 | fin->fin_ip->ip_dst = nat->nat_osrcip; | | 5563 | fin->fin_ip->ip_dst = nat->nat_osrcip; |
5564 | fin->fin_daddr = nat->nat_osrcaddr; | | 5564 | fin->fin_daddr = nat->nat_osrcaddr; |
5565 | #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ | | 5565 | #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ |
5566 | defined(__osf__) || defined(linux) | | 5566 | defined(__osf__) || defined(linux) |
5567 | ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); | | 5567 | ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0); |
5568 | #endif | | 5568 | #endif |
5569 | break; | | 5569 | break; |
5570 | | | 5570 | |
5571 | case NAT_DIVERTIN : | | 5571 | case NAT_DIVERTIN : |
5572 | { | | 5572 | { |
5573 | udphdr_t *uh; | | 5573 | udphdr_t *uh; |
5574 | ip_t *ip; | | 5574 | ip_t *ip; |
5575 | mb_t *m; | | 5575 | mb_t *m; |
5576 | | | 5576 | |
5577 | m = M_DUP(np->in_divmp); | | 5577 | m = M_DUP(np->in_divmp); |
5578 | if (m == NULL) { | | 5578 | if (m == NULL) { |
5579 | NBUMPSIDED(0, ns_divert_dup); | | 5579 | NBUMPSIDED(0, ns_divert_dup); |
5580 | return -1; | | 5580 | return -1; |
5581 | } | | 5581 | } |
5582 | | | 5582 | |
5583 | ip = MTOD(m, ip_t *); | | 5583 | ip = MTOD(m, ip_t *); |
5584 | ip->ip_id = htons(ipf_nextipid(fin)); | | 5584 | ip->ip_id = htons(ipf_nextipid(fin)); |
5585 | sum1 = ntohs(ip->ip_len); | | 5585 | sum1 = ntohs(ip->ip_len); |
5586 | ip->ip_len = ntohs(ip->ip_len); | | 5586 | ip->ip_len = ntohs(ip->ip_len); |
5587 | ip->ip_len += fin->fin_plen; | | 5587 | ip->ip_len += fin->fin_plen; |
5588 | ip->ip_len = htons(ip->ip_len); | | 5588 | ip->ip_len = htons(ip->ip_len); |
5589 | | | 5589 | |
5590 | uh = (udphdr_t *)(ip + 1); | | 5590 | uh = (udphdr_t *)(ip + 1); |
5591 | uh->uh_ulen += fin->fin_plen; | | 5591 | uh->uh_ulen += fin->fin_plen; |
5592 | uh->uh_ulen = htons(uh->uh_ulen); | | 5592 | uh->uh_ulen = htons(uh->uh_ulen); |
5593 | | | 5593 | |
5594 | sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len); | | 5594 | sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len); |
5595 | sum2 += ntohs(ip->ip_off) & IP_DF; | | 5595 | sum2 += ntohs(ip->ip_off) & IP_DF; |
5596 | CALC_SUMD(sum1, sum2, sumd); | | 5596 | CALC_SUMD(sum1, sum2, sumd); |
5597 | | | 5597 | |
5598 | #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ | | 5598 | #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ |
5599 | defined(__osf__) || defined(linux) | | 5599 | defined(__osf__) || defined(linux) |
5600 | ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); | | 5600 | ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); |
5601 | #endif | | 5601 | #endif |
5602 | PREP_MB_T(fin, m); | | 5602 | PREP_MB_T(fin, m); |
5603 | | | 5603 | |
5604 | fin->fin_ip = ip; | | 5604 | fin->fin_ip = ip; |
5605 | fin->fin_plen += sizeof(ip_t) + 8; /* UDP + new IPv4 hdr */ | | 5605 | fin->fin_plen += sizeof(ip_t) + 8; /* UDP + new IPv4 hdr */ |
5606 | fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + old IPv4 hdr */ | | 5606 | fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + old IPv4 hdr */ |
5607 | | | 5607 | |
5608 | nflags &= ~IPN_TCPUDPICMP; | | 5608 | nflags &= ~IPN_TCPUDPICMP; |
5609 | | | 5609 | |
5610 | break; | | 5610 | break; |
5611 | } | | 5611 | } |
5612 | | | 5612 | |
5613 | case NAT_DIVERTOUT : | | 5613 | case NAT_DIVERTOUT : |
5614 | { | | 5614 | { |
5615 | mb_t *m; | | 5615 | mb_t *m; |
5616 | | | 5616 | |
5617 | skip = ipf_nat_decap(fin, nat); | | 5617 | skip = ipf_nat_decap(fin, nat); |
5618 | if (skip <= 0) { | | 5618 | if (skip <= 0) { |
5619 | NBUMPSIDED(0, ns_decap_fail); | | 5619 | NBUMPSIDED(0, ns_decap_fail); |
5620 | return -1; | | 5620 | return -1; |
5621 | } | | 5621 | } |
5622 | | | 5622 | |
5623 | m = fin->fin_m; | | 5623 | m = fin->fin_m; |
5624 | | | 5624 | |
5625 | #if defined(MENTAT) && defined(_KERNEL) | | 5625 | #if defined(MENTAT) && defined(_KERNEL) |
5626 | m->b_rptr += skip; | | 5626 | m->b_rptr += skip; |
5627 | #else | | 5627 | #else |
5628 | m->m_data += skip; | | 5628 | m->m_data += skip; |
5629 | m->m_len -= skip; | | 5629 | m->m_len -= skip; |
5630 | | | 5630 | |
5631 | # ifdef M_PKTHDR | | 5631 | # ifdef M_PKTHDR |
5632 | if (m->m_flags & M_PKTHDR) | | 5632 | if (m->m_flags & M_PKTHDR) |
5633 | m->m_pkthdr.len -= skip; | | 5633 | m->m_pkthdr.len -= skip; |
5634 | # endif | | 5634 | # endif |
5635 | #endif | | 5635 | #endif |
5636 | | | 5636 | |
5637 | ipf_nat_update(fin, nat); | | 5637 | ipf_nat_update(fin, nat); |
5638 | nflags &= ~IPN_TCPUDPICMP; | | 5638 | nflags &= ~IPN_TCPUDPICMP; |
5639 | fin->fin_flx |= FI_NATED; | | 5639 | fin->fin_flx |= FI_NATED; |
5640 | if (np != NULL && np->in_tag.ipt_num[0] != 0) | | 5640 | if (np != NULL && np->in_tag.ipt_num[0] != 0) |
5641 | fin->fin_nattag = &np->in_tag; | | 5641 | fin->fin_nattag = &np->in_tag; |
5642 | return 1; | | 5642 | return 1; |
5643 | /* NOTREACHED */ | | 5643 | /* NOTREACHED */ |
5644 | } | | 5644 | } |
5645 | } | | 5645 | } |
5646 | if (nflags & IPN_TCPUDP) | | 5646 | if (nflags & IPN_TCPUDP) |
5647 | tcp = fin->fin_dp; | | 5647 | tcp = fin->fin_dp; |
5648 | | | 5648 | |
5649 | if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { | | 5649 | if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { |
5650 | u_short *csump; | | 5650 | u_short *csump; |
5651 | | | 5651 | |
5652 | if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) { | | 5652 | if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) { |
5653 | switch (nat->nat_dir) | | 5653 | switch (nat->nat_dir) |
5654 | { | | 5654 | { |
5655 | case NAT_INBOUND : | | 5655 | case NAT_INBOUND : |
5656 | tcp->th_sport = nat->nat_nsport; | | 5656 | tcp->th_sport = nat->nat_nsport; |
5657 | fin->fin_data[0] = ntohs(nat->nat_nsport); | | 5657 | fin->fin_data[0] = ntohs(nat->nat_nsport); |
5658 | tcp->th_dport = nat->nat_ndport; | | 5658 | tcp->th_dport = nat->nat_ndport; |
5659 | fin->fin_data[1] = ntohs(nat->nat_ndport); | | 5659 | fin->fin_data[1] = ntohs(nat->nat_ndport); |
5660 | break; | | 5660 | break; |
5661 | | | 5661 | |
5662 | case NAT_OUTBOUND : | | 5662 | case NAT_OUTBOUND : |
5663 | tcp->th_sport = nat->nat_odport; | | 5663 | tcp->th_sport = nat->nat_odport; |
5664 | fin->fin_data[0] = ntohs(nat->nat_odport); | | 5664 | fin->fin_data[0] = ntohs(nat->nat_odport); |
5665 | tcp->th_dport = nat->nat_osport; | | 5665 | tcp->th_dport = nat->nat_osport; |
5666 | fin->fin_data[1] = ntohs(nat->nat_osport); | | 5666 | fin->fin_data[1] = ntohs(nat->nat_osport); |
5667 | break; | | 5667 | break; |
5668 | } | | 5668 | } |
5669 | } | | 5669 | } |
5670 | | | 5670 | |
5671 | | | 5671 | |
5672 | if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { | | 5672 | if ((nat->nat_oicmpid != 0) && (nflags & IPN_ICMPQUERY)) { |
5673 | icmp = fin->fin_dp; | | 5673 | icmp = fin->fin_dp; |
5674 | | | 5674 | |
5675 | switch (nat->nat_dir) | | 5675 | switch (nat->nat_dir) |
5676 | { | | 5676 | { |
5677 | case NAT_INBOUND : | | 5677 | case NAT_INBOUND : |
5678 | icmp->icmp_id = nat->nat_nicmpid; | | 5678 | icmp->icmp_id = nat->nat_nicmpid; |
5679 | break; | | 5679 | break; |
5680 | case NAT_OUTBOUND : | | 5680 | case NAT_OUTBOUND : |
5681 | icmp->icmp_id = nat->nat_oicmpid; | | 5681 | icmp->icmp_id = nat->nat_oicmpid; |
5682 | break; | | 5682 | break; |
5683 | } | | 5683 | } |
5684 | } | | 5684 | } |
5685 | | | 5685 | |
5686 | csump = ipf_nat_proto(fin, nat, nflags); | | 5686 | csump = ipf_nat_proto(fin, nat, nflags); |
5687 | | | 5687 | |
5688 | /* | | 5688 | /* |
5689 | * The above comments do not hold for layer 4 (or higher) | | 5689 | * The above comments do not hold for layer 4 (or higher) |
5690 | * checksums... | | 5690 | * checksums... |
5691 | */ | | 5691 | */ |
5692 | if (csump != NULL) { | | 5692 | if (csump != NULL) { |
5693 | if (nat->nat_dir == NAT_OUTBOUND) | | 5693 | if (nat->nat_dir == NAT_OUTBOUND) |
5694 | ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0); | | 5694 | ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0); |
5695 | else | | 5695 | else |
5696 | ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0); | | 5696 | ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0); |
5697 | } | | 5697 | } |
5698 | } | | 5698 | } |
5699 | | | 5699 | |
5700 | fin->fin_flx |= FI_NATED; | | 5700 | fin->fin_flx |= FI_NATED; |
5701 | if (np != NULL && np->in_tag.ipt_num[0] != 0) | | 5701 | if (np != NULL && np->in_tag.ipt_num[0] != 0) |
5702 | fin->fin_nattag = &np->in_tag; | | 5702 | fin->fin_nattag = &np->in_tag; |
5703 | return 1; | | 5703 | return 1; |
5704 | } | | 5704 | } |
5705 | | | 5705 | |
5706 | | | 5706 | |
5707 | /* ------------------------------------------------------------------------ */ | | 5707 | /* ------------------------------------------------------------------------ */ |
5708 | /* Function: ipf_nat_proto */ | | 5708 | /* Function: ipf_nat_proto */ |
5709 | /* Returns: u_short* - pointer to transport header checksum to update, */ | | 5709 | /* Returns: u_short* - pointer to transport header checksum to update, */ |
5710 | /* NULL if the transport protocol is not recognised */ | | 5710 | /* NULL if the transport protocol is not recognised */ |
5711 | /* as needing a checksum update. */ | | 5711 | /* as needing a checksum update. */ |
5712 | /* Parameters: fin(I) - pointer to packet information */ | | 5712 | /* Parameters: fin(I) - pointer to packet information */ |
5713 | /* nat(I) - pointer to NAT structure */ | | 5713 | /* nat(I) - pointer to NAT structure */ |
5714 | /* nflags(I) - NAT flags set for this packet */ | | 5714 | /* nflags(I) - NAT flags set for this packet */ |
5715 | /* */ | | 5715 | /* */ |
5716 | /* Return the pointer to the checksum field for each protocol so understood.*/ | | 5716 | /* Return the pointer to the checksum field for each protocol so understood.*/ |
5717 | /* If support for making other changes to a protocol header is required, */ | | 5717 | /* If support for making other changes to a protocol header is required, */ |
5718 | /* that is not strictly 'address' translation, such as clamping the MSS in */ | | 5718 | /* that is not strictly 'address' translation, such as clamping the MSS in */ |
5719 | /* TCP down to a specific value, then do it from here. */ | | 5719 | /* TCP down to a specific value, then do it from here. */ |
5720 | /* ------------------------------------------------------------------------ */ | | 5720 | /* ------------------------------------------------------------------------ */ |
5721 | u_short * | | 5721 | u_short * |
5722 | ipf_nat_proto(fr_info_t *fin, nat_t *nat, u_int nflags) | | 5722 | ipf_nat_proto(fr_info_t *fin, nat_t *nat, u_int nflags) |
5723 | { | | 5723 | { |
5724 | icmphdr_t *icmp; | | 5724 | icmphdr_t *icmp; |
5725 | u_short *csump; | | 5725 | u_short *csump; |
5726 | tcphdr_t *tcp; | | 5726 | tcphdr_t *tcp; |
5727 | udphdr_t *udp; | | 5727 | udphdr_t *udp; |
5728 | | | 5728 | |
5729 | csump = NULL; | | 5729 | csump = NULL; |
5730 | if (fin->fin_out == 0) { | | 5730 | if (fin->fin_out == 0) { |
5731 | fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND); | | 5731 | fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND); |
5732 | } else { | | 5732 | } else { |
5733 | fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0); | | 5733 | fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0); |
5734 | } | | 5734 | } |
5735 | | | 5735 | |
5736 | switch (fin->fin_p) | | 5736 | switch (fin->fin_p) |
5737 | { | | 5737 | { |
5738 | case IPPROTO_TCP : | | 5738 | case IPPROTO_TCP : |
5739 | tcp = fin->fin_dp; | | 5739 | tcp = fin->fin_dp; |
5740 | | | 5740 | |
5741 | if ((nflags & IPN_TCP) != 0) | | 5741 | if ((nflags & IPN_TCP) != 0) |
5742 | csump = &tcp->th_sum; | | 5742 | csump = &tcp->th_sum; |
5743 | | | 5743 | |
5744 | /* | | 5744 | /* |
5745 | * Do a MSS CLAMPING on a SYN packet, | | 5745 | * Do a MSS CLAMPING on a SYN packet, |
5746 | * only deal IPv4 for now. | | 5746 | * only deal IPv4 for now. |
5747 | */ | | 5747 | */ |
5748 | if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) | | 5748 | if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) |
5749 | ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); | | 5749 | ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); |
5750 | | | 5750 | |
5751 | break; | | 5751 | break; |
5752 | | | 5752 | |
5753 | case IPPROTO_UDP : | | 5753 | case IPPROTO_UDP : |
5754 | udp = fin->fin_dp; | | 5754 | udp = fin->fin_dp; |
5755 | | | 5755 | |
5756 | if ((nflags & IPN_UDP) != 0) { | | 5756 | if ((nflags & IPN_UDP) != 0) { |
5757 | if (udp->uh_sum != 0) | | 5757 | if (udp->uh_sum != 0) |
5758 | csump = &udp->uh_sum; | | 5758 | csump = &udp->uh_sum; |
5759 | } | | 5759 | } |
5760 | break; | | 5760 | break; |
5761 | | | 5761 | |
5762 | case IPPROTO_ICMP : | | 5762 | case IPPROTO_ICMP : |
5763 | icmp = fin->fin_dp; | | 5763 | icmp = fin->fin_dp; |
5764 | | | 5764 | |
5765 | if ((nflags & IPN_ICMPQUERY) != 0) { | | 5765 | if ((nflags & IPN_ICMPQUERY) != 0) { |
5766 | if (icmp->icmp_cksum != 0) | | 5766 | if (icmp->icmp_cksum != 0) |
5767 | csump = &icmp->icmp_cksum; | | 5767 | csump = &icmp->icmp_cksum; |
5768 | } | | 5768 | } |
5769 | break; | | 5769 | break; |
5770 | | | 5770 | |
5771 | #ifdef USE_INET6 | | 5771 | #ifdef USE_INET6 |
5772 | case IPPROTO_ICMPV6 : | | 5772 | case IPPROTO_ICMPV6 : |
5773 | { | | 5773 | { |
5774 | struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp; | | 5774 | struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp; |
5775 | | | 5775 | |
5776 | icmp6 = fin->fin_dp; | | 5776 | icmp6 = fin->fin_dp; |
5777 | | | 5777 | |
5778 | if ((nflags & IPN_ICMPQUERY) != 0) { | | 5778 | if ((nflags & IPN_ICMPQUERY) != 0) { |
5779 | if (icmp6->icmp6_cksum != 0) | | 5779 | if (icmp6->icmp6_cksum != 0) |
5780 | csump = &icmp6->icmp6_cksum; | | 5780 | csump = &icmp6->icmp6_cksum; |
5781 | } | | 5781 | } |
5782 | break; | | 5782 | break; |
5783 | } | | 5783 | } |
5784 | #endif | | 5784 | #endif |
5785 | } | | 5785 | } |
5786 | return csump; | | 5786 | return csump; |
5787 | } | | 5787 | } |
5788 | | | 5788 | |
5789 | | | 5789 | |
5790 | /* ------------------------------------------------------------------------ */ | | 5790 | /* ------------------------------------------------------------------------ */ |
5791 | /* Function: ipf_nat_expire */ | | 5791 | /* Function: ipf_nat_expire */ |
5792 | /* Returns: Nil */ | | 5792 | /* Returns: Nil */ |
5793 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 5793 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5794 | /* */ | | 5794 | /* */ |
5795 | /* Check all of the timeout queues for entries at the top which need to be */ | | 5795 | /* Check all of the timeout queues for entries at the top which need to be */ |
5796 | /* expired. */ | | 5796 | /* expired. */ |
5797 | /* ------------------------------------------------------------------------ */ | | 5797 | /* ------------------------------------------------------------------------ */ |
5798 | void | | 5798 | void |
5799 | ipf_nat_expire(ipf_main_softc_t *softc) | | 5799 | ipf_nat_expire(ipf_main_softc_t *softc) |
5800 | { | | 5800 | { |
5801 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 5801 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
5802 | ipftq_t *ifq, *ifqnext; | | 5802 | ipftq_t *ifq, *ifqnext; |
5803 | ipftqent_t *tqe, *tqn; | | 5803 | ipftqent_t *tqe, *tqn; |
5804 | int i; | | 5804 | int i; |
5805 | SPL_INT(s); | | 5805 | SPL_INT(s); |
5806 | | | 5806 | |
5807 | SPL_NET(s); | | 5807 | SPL_NET(s); |
5808 | WRITE_ENTER(&softc->ipf_nat); | | 5808 | WRITE_ENTER(&softc->ipf_nat); |
5809 | for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL; | | 5809 | for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL; |
5810 | ifq = ifq->ifq_next) { | | 5810 | ifq = ifq->ifq_next) { |
5811 | for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { | | 5811 | for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { |
5812 | if (tqe->tqe_die > softc->ipf_ticks) | | 5812 | if (tqe->tqe_die > softc->ipf_ticks) |
5813 | break; | | 5813 | break; |
5814 | tqn = tqe->tqe_next; | | 5814 | tqn = tqe->tqe_next; |
5815 | ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); | | 5815 | ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); |
5816 | } | | 5816 | } |
5817 | } | | 5817 | } |
5818 | | | 5818 | |
5819 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) { | | 5819 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) { |
5820 | for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { | | 5820 | for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { |
5821 | if (tqe->tqe_die > softc->ipf_ticks) | | 5821 | if (tqe->tqe_die > softc->ipf_ticks) |
5822 | break; | | 5822 | break; |
5823 | tqn = tqe->tqe_next; | | 5823 | tqn = tqe->tqe_next; |
5824 | ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); | | 5824 | ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE); |
5825 | } | | 5825 | } |
5826 | } | | 5826 | } |
5827 | | | 5827 | |
5828 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { | | 5828 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) { |
5829 | ifqnext = ifq->ifq_next; | | 5829 | ifqnext = ifq->ifq_next; |
5830 | | | 5830 | |
5831 | if (((ifq->ifq_flags & IFQF_DELETE) != 0) && | | 5831 | if (((ifq->ifq_flags & IFQF_DELETE) != 0) && |
5832 | (ifq->ifq_ref == 0)) { | | 5832 | (ifq->ifq_ref == 0)) { |
5833 | ipf_freetimeoutqueue(softc, ifq); | | 5833 | ipf_freetimeoutqueue(softc, ifq); |
5834 | } | | 5834 | } |
5835 | } | | 5835 | } |
5836 | | | 5836 | |
5837 | if (softn->ipf_nat_doflush != 0) { | | 5837 | if (softn->ipf_nat_doflush != 0) { |
5838 | ipf_nat_extraflush(softc, softn, 2); | | 5838 | ipf_nat_extraflush(softc, softn, 2); |
5839 | softn->ipf_nat_doflush = 0; | | 5839 | softn->ipf_nat_doflush = 0; |
5840 | } | | 5840 | } |
5841 | | | 5841 | |
5842 | RWLOCK_EXIT(&softc->ipf_nat); | | 5842 | RWLOCK_EXIT(&softc->ipf_nat); |
5843 | SPL_X(s); | | 5843 | SPL_X(s); |
5844 | } | | 5844 | } |
5845 | | | 5845 | |
5846 | | | 5846 | |
5847 | /* ------------------------------------------------------------------------ */ | | 5847 | /* ------------------------------------------------------------------------ */ |
5848 | /* Function: ipf_nat_sync */ | | 5848 | /* Function: ipf_nat_sync */ |
5849 | /* Returns: Nil */ | | 5849 | /* Returns: Nil */ |
5850 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 5850 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5851 | /* ifp(I) - pointer to network interface */ | | 5851 | /* ifp(I) - pointer to network interface */ |
5852 | /* */ | | 5852 | /* */ |
5853 | /* Walk through all of the currently active NAT sessions, looking for those */ | | 5853 | /* Walk through all of the currently active NAT sessions, looking for those */ |
5854 | /* which need to have their translated address updated. */ | | 5854 | /* which need to have their translated address updated. */ |
5855 | /* ------------------------------------------------------------------------ */ | | 5855 | /* ------------------------------------------------------------------------ */ |
5856 | void | | 5856 | void |
5857 | ipf_nat_sync(ipf_main_softc_t *softc, void *ifp) | | 5857 | ipf_nat_sync(ipf_main_softc_t *softc, void *ifp) |
5858 | { | | 5858 | { |
5859 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 5859 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
5860 | u_32_t sum1, sum2, sumd; | | 5860 | u_32_t sum1, sum2, sumd; |
5861 | i6addr_t in; | | 5861 | i6addr_t in; |
5862 | ipnat_t *n; | | 5862 | ipnat_t *n; |
5863 | nat_t *nat; | | 5863 | nat_t *nat; |
5864 | void *ifp2; | | 5864 | void *ifp2; |
5865 | int idx; | | 5865 | int idx; |
5866 | SPL_INT(s); | | 5866 | SPL_INT(s); |
5867 | | | 5867 | |
5868 | if (softc->ipf_running <= 0) | | 5868 | if (softc->ipf_running <= 0) |
5869 | return; | | 5869 | return; |
5870 | | | 5870 | |
5871 | /* | | 5871 | /* |
5872 | * Change IP addresses for NAT sessions for any protocol except TCP | | 5872 | * Change IP addresses for NAT sessions for any protocol except TCP |
5873 | * since it will break the TCP connection anyway. The only rules | | 5873 | * since it will break the TCP connection anyway. The only rules |
5874 | * which will get changed are those which are "map ... -> 0/32", | | 5874 | * which will get changed are those which are "map ... -> 0/32", |
5875 | * where the rule specifies the address is taken from the interface. | | 5875 | * where the rule specifies the address is taken from the interface. |
5876 | */ | | 5876 | */ |
5877 | SPL_NET(s); | | 5877 | SPL_NET(s); |
5878 | WRITE_ENTER(&softc->ipf_nat); | | 5878 | WRITE_ENTER(&softc->ipf_nat); |
5879 | | | 5879 | |
5880 | if (softc->ipf_running <= 0) { | | 5880 | if (softc->ipf_running <= 0) { |
5881 | RWLOCK_EXIT(&softc->ipf_nat); | | 5881 | RWLOCK_EXIT(&softc->ipf_nat); |
5882 | return; | | 5882 | return; |
5883 | } | | 5883 | } |
5884 | | | 5884 | |
5885 | for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) { | | 5885 | for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) { |
5886 | if ((nat->nat_flags & IPN_TCP) != 0) | | 5886 | if ((nat->nat_flags & IPN_TCP) != 0) |
5887 | continue; | | 5887 | continue; |
5888 | | | 5888 | |
5889 | n = nat->nat_ptr; | | 5889 | n = nat->nat_ptr; |
5890 | if (n != NULL) { | | 5890 | if (n != NULL) { |
5891 | if (n->in_v[1] == 4) { | | 5891 | if (n->in_v[1] == 4) { |
5892 | if (n->in_redir & NAT_MAP) { | | 5892 | if (n->in_redir & NAT_MAP) { |
5893 | if ((n->in_nsrcaddr != 0) || | | 5893 | if ((n->in_nsrcaddr != 0) || |
5894 | (n->in_nsrcmsk != 0xffffffff)) | | 5894 | (n->in_nsrcmsk != 0xffffffff)) |
5895 | continue; | | 5895 | continue; |
5896 | } else if (n->in_redir & NAT_REDIRECT) { | | 5896 | } else if (n->in_redir & NAT_REDIRECT) { |
5897 | if ((n->in_ndstaddr != 0) || | | 5897 | if ((n->in_ndstaddr != 0) || |
5898 | (n->in_ndstmsk != 0xffffffff)) | | 5898 | (n->in_ndstmsk != 0xffffffff)) |
5899 | continue; | | 5899 | continue; |
5900 | } | | 5900 | } |
5901 | } | | 5901 | } |
5902 | #ifdef USE_INET6 | | 5902 | #ifdef USE_INET6 |
5903 | if (n->in_v[1] == 4) { | | 5903 | if (n->in_v[1] == 4) { |
5904 | if (n->in_redir & NAT_MAP) { | | 5904 | if (n->in_redir & NAT_MAP) { |
5905 | if (!IP6_ISZERO(&n->in_nsrcaddr) || | | 5905 | if (!IP6_ISZERO(&n->in_nsrcaddr) || |
5906 | !IP6_ISONES(&n->in_nsrcmsk)) | | 5906 | !IP6_ISONES(&n->in_nsrcmsk)) |
5907 | continue; | | 5907 | continue; |
5908 | } else if (n->in_redir & NAT_REDIRECT) { | | 5908 | } else if (n->in_redir & NAT_REDIRECT) { |
5909 | if (!IP6_ISZERO(&n->in_ndstaddr) || | | 5909 | if (!IP6_ISZERO(&n->in_ndstaddr) || |
5910 | !IP6_ISONES(&n->in_ndstmsk)) | | 5910 | !IP6_ISONES(&n->in_ndstmsk)) |
5911 | continue; | | 5911 | continue; |
5912 | } | | 5912 | } |
5913 | } | | 5913 | } |
5914 | #endif | | 5914 | #endif |
5915 | } | | 5915 | } |
5916 | | | 5916 | |
5917 | if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || | | 5917 | if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || |
5918 | (ifp == nat->nat_ifps[1]))) { | | 5918 | (ifp == nat->nat_ifps[1]))) { |
5919 | nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], | | 5919 | nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], |
5920 | nat->nat_v[0]); | | 5920 | nat->nat_v[0]); |
5921 | if ((nat->nat_ifps[0] != NULL) && | | 5921 | if ((nat->nat_ifps[0] != NULL) && |
5922 | (nat->nat_ifps[0] != (void *)-1)) { | | 5922 | (nat->nat_ifps[0] != (void *)-1)) { |
5923 | nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); | | 5923 | nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]); |
5924 | } | | 5924 | } |
5925 | if (nat->nat_ifnames[1][0] != '\0') { | | 5925 | if (nat->nat_ifnames[1][0] != '\0') { |
5926 | nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], | | 5926 | nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], |
5927 | nat->nat_v[1]); | | 5927 | nat->nat_v[1]); |
5928 | } else { | | 5928 | } else { |
5929 | nat->nat_ifps[1] = nat->nat_ifps[0]; | | 5929 | nat->nat_ifps[1] = nat->nat_ifps[0]; |
5930 | } | | 5930 | } |
5931 | if ((nat->nat_ifps[1] != NULL) && | | 5931 | if ((nat->nat_ifps[1] != NULL) && |
5932 | (nat->nat_ifps[1] != (void *)-1)) { | | 5932 | (nat->nat_ifps[1] != (void *)-1)) { |
5933 | nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); | | 5933 | nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]); |
5934 | } | | 5934 | } |
5935 | ifp2 = nat->nat_ifps[0]; | | 5935 | ifp2 = nat->nat_ifps[0]; |
5936 | if (ifp2 == NULL) | | 5936 | if (ifp2 == NULL) |
5937 | continue; | | 5937 | continue; |
5938 | | | 5938 | |
5939 | /* | | 5939 | /* |
5940 | * Change the map-to address to be the same as the | | 5940 | * Change the map-to address to be the same as the |
5941 | * new one. | | 5941 | * new one. |
5942 | */ | | 5942 | */ |
5943 | sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); | | 5943 | sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); |
5944 | if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2, | | 5944 | if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2, |
5945 | &in, NULL) != -1) { | | 5945 | &in, NULL) != -1) { |
5946 | if (nat->nat_v[0] == 4) | | 5946 | if (nat->nat_v[0] == 4) |
5947 | nat->nat_nsrcip = in.in4; | | 5947 | nat->nat_nsrcip = in.in4; |
5948 | } | | 5948 | } |
5949 | sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); | | 5949 | sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6); |
5950 | | | 5950 | |
5951 | if (sum1 == sum2) | | 5951 | if (sum1 == sum2) |
5952 | continue; | | 5952 | continue; |
5953 | /* | | 5953 | /* |
5954 | * Readjust the checksum adjustment to take into | | 5954 | * Readjust the checksum adjustment to take into |
5955 | * account the new IP#. | | 5955 | * account the new IP#. |
5956 | */ | | 5956 | */ |
5957 | CALC_SUMD(sum1, sum2, sumd); | | 5957 | CALC_SUMD(sum1, sum2, sumd); |
5958 | /* XXX - dont change for TCP when solaris does | | 5958 | /* XXX - dont change for TCP when solaris does |
5959 | * hardware checksumming. | | 5959 | * hardware checksumming. |
5960 | */ | | 5960 | */ |
5961 | sumd += nat->nat_sumd[0]; | | 5961 | sumd += nat->nat_sumd[0]; |
5962 | nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); | | 5962 | nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); |
5963 | nat->nat_sumd[1] = nat->nat_sumd[0]; | | 5963 | nat->nat_sumd[1] = nat->nat_sumd[0]; |
5964 | } | | 5964 | } |
5965 | } | | 5965 | } |
5966 | | | 5966 | |
5967 | for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) { | | 5967 | for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) { |
5968 | char *base = n->in_names; | | 5968 | char *base = n->in_names; |
5969 | | | 5969 | |
5970 | if ((ifp == NULL) || (n->in_ifps[0] == ifp)) | | 5970 | if ((ifp == NULL) || (n->in_ifps[0] == ifp)) |
5971 | n->in_ifps[0] = ipf_resolvenic(softc, | | 5971 | n->in_ifps[0] = ipf_resolvenic(softc, |
5972 | base + n->in_ifnames[0], | | 5972 | base + n->in_ifnames[0], |
5973 | n->in_v[0]); | | 5973 | n->in_v[0]); |
5974 | if ((ifp == NULL) || (n->in_ifps[1] == ifp)) | | 5974 | if ((ifp == NULL) || (n->in_ifps[1] == ifp)) |
5975 | n->in_ifps[1] = ipf_resolvenic(softc, | | 5975 | n->in_ifps[1] = ipf_resolvenic(softc, |
5976 | base + n->in_ifnames[1], | | 5976 | base + n->in_ifnames[1], |
5977 | n->in_v[1]); | | 5977 | n->in_v[1]); |
5978 | | | 5978 | |
5979 | if (n->in_redir & NAT_REDIRECT) | | 5979 | if (n->in_redir & NAT_REDIRECT) |
5980 | idx = 1; | | 5980 | idx = 1; |
5981 | else | | 5981 | else |
5982 | idx = 0; | | 5982 | idx = 0; |
5983 | | | 5983 | |
5984 | if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) && | | 5984 | if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) && |
5985 | (n->in_ifps[idx] != NULL && | | 5985 | (n->in_ifps[idx] != NULL && |
5986 | n->in_ifps[idx] != (void *)-1)) { | | 5986 | n->in_ifps[idx] != (void *)-1)) { |
5987 | | | 5987 | |
5988 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, | | 5988 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, |
5989 | 0, n->in_ifps[idx]); | | 5989 | 0, n->in_ifps[idx]); |
5990 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, | | 5990 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, |
5991 | 0, n->in_ifps[idx]); | | 5991 | 0, n->in_ifps[idx]); |
5992 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, | | 5992 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, |
5993 | 0, n->in_ifps[idx]); | | 5993 | 0, n->in_ifps[idx]); |
5994 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, | | 5994 | ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, |
5995 | 0, n->in_ifps[idx]); | | 5995 | 0, n->in_ifps[idx]); |
5996 | } | | 5996 | } |
5997 | } | | 5997 | } |
5998 | RWLOCK_EXIT(&softc->ipf_nat); | | 5998 | RWLOCK_EXIT(&softc->ipf_nat); |
5999 | SPL_X(s); | | 5999 | SPL_X(s); |
6000 | } | | 6000 | } |
6001 | | | 6001 | |
6002 | | | 6002 | |
6003 | /* ------------------------------------------------------------------------ */ | | 6003 | /* ------------------------------------------------------------------------ */ |
6004 | /* Function: ipf_nat_icmpquerytype */ | | 6004 | /* Function: ipf_nat_icmpquerytype */ |
6005 | /* Returns: int - 1 == success, 0 == failure */ | | 6005 | /* Returns: int - 1 == success, 0 == failure */ |
6006 | /* Parameters: icmptype(I) - ICMP type number */ | | 6006 | /* Parameters: icmptype(I) - ICMP type number */ |
6007 | /* */ | | 6007 | /* */ |
6008 | /* Tests to see if the ICMP type number passed is a query/response type or */ | | 6008 | /* Tests to see if the ICMP type number passed is a query/response type or */ |
6009 | /* not. */ | | 6009 | /* not. */ |
6010 | /* ------------------------------------------------------------------------ */ | | 6010 | /* ------------------------------------------------------------------------ */ |
6011 | static int | | 6011 | static int |
6012 | ipf_nat_icmpquerytype(int icmptype) | | 6012 | ipf_nat_icmpquerytype(int icmptype) |
6013 | { | | 6013 | { |
6014 | | | 6014 | |
6015 | /* | | 6015 | /* |
6016 | * For the ICMP query NAT code, it is essential that both the query | | 6016 | * For the ICMP query NAT code, it is essential that both the query |
6017 | * and the reply match on the NAT rule. Because the NAT structure | | 6017 | * and the reply match on the NAT rule. Because the NAT structure |
6018 | * does not keep track of the icmptype, and a single NAT structure | | 6018 | * does not keep track of the icmptype, and a single NAT structure |
6019 | * is used for all icmp types with the same src, dest and id, we | | 6019 | * is used for all icmp types with the same src, dest and id, we |
6020 | * simply define the replies as queries as well. The funny thing is, | | 6020 | * simply define the replies as queries as well. The funny thing is, |
6021 | * although it seems silly to call a reply a query, this is exactly | | 6021 | * although it seems silly to call a reply a query, this is exactly |
6022 | * as it is defined in the IPv4 specification | | 6022 | * as it is defined in the IPv4 specification |
6023 | */ | | 6023 | */ |
6024 | switch (icmptype) | | 6024 | switch (icmptype) |
6025 | { | | 6025 | { |
6026 | case ICMP_ECHOREPLY: | | 6026 | case ICMP_ECHOREPLY: |
6027 | case ICMP_ECHO: | | 6027 | case ICMP_ECHO: |
6028 | /* route advertisement/sollicitation is currently unsupported: */ | | 6028 | /* route advertisement/sollicitation is currently unsupported: */ |
6029 | /* it would require rewriting the ICMP data section */ | | 6029 | /* it would require rewriting the ICMP data section */ |
6030 | case ICMP_TSTAMP: | | 6030 | case ICMP_TSTAMP: |
6031 | case ICMP_TSTAMPREPLY: | | 6031 | case ICMP_TSTAMPREPLY: |
6032 | case ICMP_IREQ: | | 6032 | case ICMP_IREQ: |
6033 | case ICMP_IREQREPLY: | | 6033 | case ICMP_IREQREPLY: |
6034 | case ICMP_MASKREQ: | | 6034 | case ICMP_MASKREQ: |
6035 | case ICMP_MASKREPLY: | | 6035 | case ICMP_MASKREPLY: |
6036 | return 1; | | 6036 | return 1; |
6037 | default: | | 6037 | default: |
6038 | return 0; | | 6038 | return 0; |
6039 | } | | 6039 | } |
6040 | } | | 6040 | } |
6041 | | | 6041 | |
6042 | | | 6042 | |
6043 | /* ------------------------------------------------------------------------ */ | | 6043 | /* ------------------------------------------------------------------------ */ |
6044 | /* Function: nat_log */ | | 6044 | /* Function: nat_log */ |
6045 | /* Returns: Nil */ | | 6045 | /* Returns: Nil */ |
6046 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6046 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6047 | /* softn(I) - pointer to NAT context structure */ | | 6047 | /* softn(I) - pointer to NAT context structure */ |
6048 | /* nat(I) - pointer to NAT structure */ | | 6048 | /* nat(I) - pointer to NAT structure */ |
6049 | /* action(I) - action related to NAT structure being performed */ | | 6049 | /* action(I) - action related to NAT structure being performed */ |
6050 | /* */ | | 6050 | /* */ |
6051 | /* Creates a NAT log entry. */ | | 6051 | /* Creates a NAT log entry. */ |
6052 | /* ------------------------------------------------------------------------ */ | | 6052 | /* ------------------------------------------------------------------------ */ |
6053 | void | | 6053 | void |
6054 | ipf_nat_log(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, struct nat *nat, | | 6054 | ipf_nat_log(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, struct nat *nat, |
6055 | u_int action) | | 6055 | u_int action) |
6056 | { | | 6056 | { |
6057 | #ifdef IPFILTER_LOG | | 6057 | #ifdef IPFILTER_LOG |
6058 | # ifndef LARGE_NAT | | 6058 | # ifndef LARGE_NAT |
6059 | struct ipnat *np; | | 6059 | struct ipnat *np; |
6060 | int rulen; | | 6060 | int rulen; |
6061 | # endif | | 6061 | # endif |
6062 | struct natlog natl; | | 6062 | struct natlog natl; |
6063 | void *items[1]; | | 6063 | void *items[1]; |
6064 | size_t sizes[1]; | | 6064 | size_t sizes[1]; |
6065 | int types[1]; | | 6065 | int types[1]; |
6066 | | | 6066 | |
6067 | bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip, | | 6067 | bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip, |
6068 | sizeof(natl.nl_osrcip)); | | 6068 | sizeof(natl.nl_osrcip)); |
6069 | bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip, | | 6069 | bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip, |
6070 | sizeof(natl.nl_nsrcip)); | | 6070 | sizeof(natl.nl_nsrcip)); |
6071 | bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip, | | 6071 | bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip, |
6072 | sizeof(natl.nl_odstip)); | | 6072 | sizeof(natl.nl_odstip)); |
6073 | bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip, | | 6073 | bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip, |
6074 | sizeof(natl.nl_ndstip)); | | 6074 | sizeof(natl.nl_ndstip)); |
6075 | | | 6075 | |
6076 | natl.nl_bytes[0] = nat->nat_bytes[0]; | | 6076 | natl.nl_bytes[0] = nat->nat_bytes[0]; |
6077 | natl.nl_bytes[1] = nat->nat_bytes[1]; | | 6077 | natl.nl_bytes[1] = nat->nat_bytes[1]; |
6078 | natl.nl_pkts[0] = nat->nat_pkts[0]; | | 6078 | natl.nl_pkts[0] = nat->nat_pkts[0]; |
6079 | natl.nl_pkts[1] = nat->nat_pkts[1]; | | 6079 | natl.nl_pkts[1] = nat->nat_pkts[1]; |
6080 | natl.nl_odstport = nat->nat_odport; | | 6080 | natl.nl_odstport = nat->nat_odport; |
6081 | natl.nl_osrcport = nat->nat_osport; | | 6081 | natl.nl_osrcport = nat->nat_osport; |
6082 | natl.nl_nsrcport = nat->nat_nsport; | | 6082 | natl.nl_nsrcport = nat->nat_nsport; |
6083 | natl.nl_ndstport = nat->nat_ndport; | | 6083 | natl.nl_ndstport = nat->nat_ndport; |
6084 | natl.nl_p[0] = nat->nat_pr[0]; | | 6084 | natl.nl_p[0] = nat->nat_pr[0]; |
6085 | natl.nl_p[1] = nat->nat_pr[1]; | | 6085 | natl.nl_p[1] = nat->nat_pr[1]; |
6086 | natl.nl_v[0] = nat->nat_v[0]; | | 6086 | natl.nl_v[0] = nat->nat_v[0]; |
6087 | natl.nl_v[1] = nat->nat_v[1]; | | 6087 | natl.nl_v[1] = nat->nat_v[1]; |
6088 | natl.nl_type = nat->nat_redir; | | 6088 | natl.nl_type = nat->nat_redir; |
6089 | natl.nl_action = action; | | 6089 | natl.nl_action = action; |
6090 | natl.nl_rule = -1; | | 6090 | natl.nl_rule = -1; |
6091 | | | 6091 | |
6092 | bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0], | | 6092 | bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0], |
6093 | sizeof(nat->nat_ifnames[0])); | | 6093 | sizeof(nat->nat_ifnames[0])); |
6094 | bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1], | | 6094 | bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1], |
6095 | sizeof(nat->nat_ifnames[1])); | | 6095 | sizeof(nat->nat_ifnames[1])); |
6096 | | | 6096 | |
6097 | # ifndef LARGE_NAT | | 6097 | # ifndef LARGE_NAT |
6098 | if (nat->nat_ptr != NULL) { | | 6098 | if (nat->nat_ptr != NULL) { |
6099 | for (rulen = 0, np = softn->ipf_nat_list; np != NULL; | | 6099 | for (rulen = 0, np = softn->ipf_nat_list; np != NULL; |
6100 | np = np->in_next, rulen++) | | 6100 | np = np->in_next, rulen++) |
6101 | if (np == nat->nat_ptr) { | | 6101 | if (np == nat->nat_ptr) { |
6102 | natl.nl_rule = rulen; | | 6102 | natl.nl_rule = rulen; |
6103 | break; | | 6103 | break; |
6104 | } | | 6104 | } |
6105 | } | | 6105 | } |
6106 | # endif | | 6106 | # endif |
6107 | items[0] = &natl; | | 6107 | items[0] = &natl; |
6108 | sizes[0] = sizeof(natl); | | 6108 | sizes[0] = sizeof(natl); |
6109 | types[0] = 0; | | 6109 | types[0] = 0; |
6110 | | | 6110 | |
6111 | (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1); | | 6111 | (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1); |
6112 | #endif | | 6112 | #endif |
6113 | } | | 6113 | } |
6114 | | | 6114 | |
6115 | | | 6115 | |
6116 | #if defined(__OpenBSD__) | | 6116 | #if defined(__OpenBSD__) |
6117 | /* ------------------------------------------------------------------------ */ | | 6117 | /* ------------------------------------------------------------------------ */ |
6118 | /* Function: ipf_nat_ifdetach */ | | 6118 | /* Function: ipf_nat_ifdetach */ |
6119 | /* Returns: Nil */ | | 6119 | /* Returns: Nil */ |
6120 | /* Parameters: ifp(I) - pointer to network interface */ | | 6120 | /* Parameters: ifp(I) - pointer to network interface */ |
6121 | /* */ | | 6121 | /* */ |
6122 | /* Compatibility interface for OpenBSD to trigger the correct updating of */ | | 6122 | /* Compatibility interface for OpenBSD to trigger the correct updating of */ |
6123 | /* interface references within IPFilter. */ | | 6123 | /* interface references within IPFilter. */ |
6124 | /* ------------------------------------------------------------------------ */ | | 6124 | /* ------------------------------------------------------------------------ */ |
6125 | void | | 6125 | void |
6126 | ipf_nat_ifdetach(ifp) | | 6126 | ipf_nat_ifdetach(ifp) |
6127 | void *ifp; | | 6127 | void *ifp; |
6128 | { | | 6128 | { |
6129 | ipf_main_softc_t *softc; | | 6129 | ipf_main_softc_t *softc; |
6130 | | | 6130 | |
6131 | softc = ipf_get_softc(0); | | 6131 | softc = ipf_get_softc(0); |
6132 | | | 6132 | |
6133 | ipf_sync(ifp); | | 6133 | ipf_sync(ifp); |
6134 | return; | | 6134 | return; |
6135 | } | | 6135 | } |
6136 | #endif | | 6136 | #endif |
6137 | | | 6137 | |
6138 | | | 6138 | |
6139 | /* ------------------------------------------------------------------------ */ | | 6139 | /* ------------------------------------------------------------------------ */ |
6140 | /* Function: ipf_nat_rule_deref */ | | 6140 | /* Function: ipf_nat_rule_deref */ |
6141 | /* Returns: Nil */ | | 6141 | /* Returns: Nil */ |
6142 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6142 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6143 | /* inp(I) - pointer to pointer to NAT rule */ | | 6143 | /* inp(I) - pointer to pointer to NAT rule */ |
6144 | /* Write Locks: ipf_nat */ | | 6144 | /* Write Locks: ipf_nat */ |
6145 | /* */ | | 6145 | /* */ |
6146 | /* Dropping the refernce count for a rule means that whatever held the */ | | 6146 | /* Dropping the refernce count for a rule means that whatever held the */ |
6147 | /* pointer to this rule (*inp) is no longer interested in it and when the */ | | 6147 | /* pointer to this rule (*inp) is no longer interested in it and when the */ |
6148 | /* reference count drops to zero, any resources allocated for the rule can */ | | 6148 | /* reference count drops to zero, any resources allocated for the rule can */ |
6149 | /* be released and the rule itself free'd. */ | | 6149 | /* be released and the rule itself free'd. */ |
6150 | /* ------------------------------------------------------------------------ */ | | 6150 | /* ------------------------------------------------------------------------ */ |
6151 | void | | 6151 | void |
6152 | ipf_nat_rule_deref(ipf_main_softc_t *softc, ipnat_t **inp) | | 6152 | ipf_nat_rule_deref(ipf_main_softc_t *softc, ipnat_t **inp) |
6153 | { | | 6153 | { |
6154 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 6154 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
6155 | ipnat_t *n; | | 6155 | ipnat_t *n; |
6156 | | | 6156 | |
6157 | n = *inp; | | 6157 | n = *inp; |
6158 | *inp = NULL; | | 6158 | *inp = NULL; |
6159 | n->in_use--; | | 6159 | n->in_use--; |
6160 | if (n->in_use > 0) | | 6160 | if (n->in_use > 0) |
6161 | return; | | 6161 | return; |
6162 | | | 6162 | |
6163 | if (n->in_apr != NULL) | | 6163 | if (n->in_apr != NULL) |
6164 | ipf_proxy_deref(n->in_apr); | | 6164 | ipf_proxy_deref(n->in_apr); |
6165 | | | 6165 | |
6166 | ipf_nat_rule_fini(softc, n); | | 6166 | ipf_nat_rule_fini(softc, n); |
6167 | | | 6167 | |
6168 | if (n->in_redir & NAT_REDIRECT) { | | 6168 | if (n->in_redir & NAT_REDIRECT) { |
6169 | if ((n->in_flags & IPN_PROXYRULE) == 0) { | | 6169 | if ((n->in_flags & IPN_PROXYRULE) == 0) { |
6170 | ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr); | | 6170 | ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr); |
6171 | } | | 6171 | } |
6172 | } | | 6172 | } |
6173 | if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { | | 6173 | if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { |
6174 | if ((n->in_flags & IPN_PROXYRULE) == 0) { | | 6174 | if ((n->in_flags & IPN_PROXYRULE) == 0) { |
6175 | ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map); | | 6175 | ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map); |
6176 | } | | 6176 | } |
6177 | } | | 6177 | } |
6178 | | | 6178 | |
6179 | if (n->in_tqehead[0] != NULL) { | | 6179 | if (n->in_tqehead[0] != NULL) { |
6180 | if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) { | | 6180 | if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) { |
6181 | ipf_freetimeoutqueue(softc, n->in_tqehead[1]); | | 6181 | ipf_freetimeoutqueue(softc, n->in_tqehead[0]); |
6182 | } | | 6182 | } |
6183 | } | | 6183 | } |
6184 | | | 6184 | |
6185 | if (n->in_tqehead[1] != NULL) { | | 6185 | if (n->in_tqehead[1] != NULL) { |
6186 | if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) { | | 6186 | if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) { |
6187 | ipf_freetimeoutqueue(softc, n->in_tqehead[1]); | | 6187 | ipf_freetimeoutqueue(softc, n->in_tqehead[1]); |
6188 | } | | 6188 | } |
6189 | } | | 6189 | } |
6190 | | | 6190 | |
6191 | if ((n->in_flags & IPN_PROXYRULE) == 0) { | | 6191 | if ((n->in_flags & IPN_PROXYRULE) == 0) { |
6192 | ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules); | | 6192 | ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules); |
6193 | } | | 6193 | } |
6194 | | | 6194 | |
6195 | MUTEX_DESTROY(&n->in_lock); | | 6195 | MUTEX_DESTROY(&n->in_lock); |
6196 | | | 6196 | |
6197 | KFREES(n, n->in_size); | | 6197 | KFREES(n, n->in_size); |
6198 | | | 6198 | |
6199 | #if SOLARIS && !defined(INSTANCES) | | 6199 | #if SOLARIS && !defined(INSTANCES) |
6200 | if (softn->ipf_nat_stats.ns_rules == 0) | | 6200 | if (softn->ipf_nat_stats.ns_rules == 0) |
6201 | pfil_delayed_copy = 1; | | 6201 | pfil_delayed_copy = 1; |
6202 | #endif | | 6202 | #endif |
6203 | } | | 6203 | } |
6204 | | | 6204 | |
6205 | | | 6205 | |
6206 | /* ------------------------------------------------------------------------ */ | | 6206 | /* ------------------------------------------------------------------------ */ |
6207 | /* Function: ipf_nat_deref */ | | 6207 | /* Function: ipf_nat_deref */ |
6208 | /* Returns: Nil */ | | 6208 | /* Returns: Nil */ |
6209 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6209 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6210 | /* natp(I) - pointer to pointer to NAT table entry */ | | 6210 | /* natp(I) - pointer to pointer to NAT table entry */ |
6211 | /* */ | | 6211 | /* */ |
6212 | /* Decrement the reference counter for this NAT table entry and free it if */ | | 6212 | /* Decrement the reference counter for this NAT table entry and free it if */ |
6213 | /* there are no more things using it. */ | | 6213 | /* there are no more things using it. */ |
6214 | /* */ | | 6214 | /* */ |
6215 | /* IF nat_ref == 1 when this function is called, then we have an orphan nat */ | | 6215 | /* IF nat_ref == 1 when this function is called, then we have an orphan nat */ |
6216 | /* structure *because* it only gets called on paths _after_ nat_ref has been*/ | | 6216 | /* structure *because* it only gets called on paths _after_ nat_ref has been*/ |
6217 | /* incremented. If nat_ref == 1 then we shouldn't decrement it here */ | | 6217 | /* incremented. If nat_ref == 1 then we shouldn't decrement it here */ |
6218 | /* because nat_delete() will do that and send nat_ref to -1. */ | | 6218 | /* because nat_delete() will do that and send nat_ref to -1. */ |
6219 | /* */ | | 6219 | /* */ |
6220 | /* Holding the lock on nat_lock is required to serialise nat_delete() being */ | | 6220 | /* Holding the lock on nat_lock is required to serialise nat_delete() being */ |
6221 | /* called from a NAT flush ioctl with a deref happening because of a packet.*/ | | 6221 | /* called from a NAT flush ioctl with a deref happening because of a packet.*/ |
6222 | /* ------------------------------------------------------------------------ */ | | 6222 | /* ------------------------------------------------------------------------ */ |
6223 | void | | 6223 | void |
6224 | ipf_nat_deref(ipf_main_softc_t *softc, nat_t **natp) | | 6224 | ipf_nat_deref(ipf_main_softc_t *softc, nat_t **natp) |
6225 | { | | 6225 | { |
6226 | nat_t *nat; | | 6226 | nat_t *nat; |
6227 | | | 6227 | |
6228 | nat = *natp; | | 6228 | nat = *natp; |
6229 | *natp = NULL; | | 6229 | *natp = NULL; |
6230 | | | 6230 | |
6231 | MUTEX_ENTER(&nat->nat_lock); | | 6231 | MUTEX_ENTER(&nat->nat_lock); |
6232 | if (nat->nat_ref > 1) { | | 6232 | if (nat->nat_ref > 1) { |
6233 | nat->nat_ref--; | | 6233 | nat->nat_ref--; |
6234 | ASSERT(nat->nat_ref >= 0); | | 6234 | ASSERT(nat->nat_ref >= 0); |
6235 | MUTEX_EXIT(&nat->nat_lock); | | 6235 | MUTEX_EXIT(&nat->nat_lock); |
6236 | return; | | 6236 | return; |
6237 | } | | 6237 | } |
6238 | MUTEX_EXIT(&nat->nat_lock); | | 6238 | MUTEX_EXIT(&nat->nat_lock); |
6239 | | | 6239 | |
6240 | WRITE_ENTER(&softc->ipf_nat); | | 6240 | WRITE_ENTER(&softc->ipf_nat); |
6241 | ipf_nat_delete(softc, nat, NL_EXPIRE); | | 6241 | ipf_nat_delete(softc, nat, NL_EXPIRE); |
6242 | RWLOCK_EXIT(&softc->ipf_nat); | | 6242 | RWLOCK_EXIT(&softc->ipf_nat); |
6243 | } | | 6243 | } |
6244 | | | 6244 | |
6245 | | | 6245 | |
6246 | /* ------------------------------------------------------------------------ */ | | 6246 | /* ------------------------------------------------------------------------ */ |
6247 | /* Function: ipf_nat_clone */ | | 6247 | /* Function: ipf_nat_clone */ |
6248 | /* Returns: ipstate_t* - NULL == cloning failed, */ | | 6248 | /* Returns: ipstate_t* - NULL == cloning failed, */ |
6249 | /* else pointer to new state structure */ | | 6249 | /* else pointer to new state structure */ |
6250 | /* Parameters: fin(I) - pointer to packet information */ | | 6250 | /* Parameters: fin(I) - pointer to packet information */ |
6251 | /* is(I) - pointer to master state structure */ | | 6251 | /* is(I) - pointer to master state structure */ |
6252 | /* Write Lock: ipf_nat */ | | 6252 | /* Write Lock: ipf_nat */ |
6253 | /* */ | | 6253 | /* */ |
6254 | /* Create a "duplcate" state table entry from the master. */ | | 6254 | /* Create a "duplcate" state table entry from the master. */ |
6255 | /* ------------------------------------------------------------------------ */ | | 6255 | /* ------------------------------------------------------------------------ */ |
6256 | nat_t * | | 6256 | nat_t * |
6257 | ipf_nat_clone(fr_info_t *fin, nat_t *nat) | | 6257 | ipf_nat_clone(fr_info_t *fin, nat_t *nat) |
6258 | { | | 6258 | { |
6259 | ipf_main_softc_t *softc = fin->fin_main_soft; | | 6259 | ipf_main_softc_t *softc = fin->fin_main_soft; |
6260 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 6260 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
6261 | frentry_t *fr; | | 6261 | frentry_t *fr; |
6262 | nat_t *clone; | | 6262 | nat_t *clone; |
6263 | ipnat_t *np; | | 6263 | ipnat_t *np; |
6264 | | | 6264 | |
6265 | KMALLOC(clone, nat_t *); | | 6265 | KMALLOC(clone, nat_t *); |
6266 | if (clone == NULL) { | | 6266 | if (clone == NULL) { |
6267 | NBUMPSIDED(fin->fin_out, ns_clone_nomem); | | 6267 | NBUMPSIDED(fin->fin_out, ns_clone_nomem); |
6268 | return NULL; | | 6268 | return NULL; |
6269 | } | | 6269 | } |
6270 | bcopy((char *)nat, (char *)clone, sizeof(*clone)); | | 6270 | bcopy((char *)nat, (char *)clone, sizeof(*clone)); |
6271 | | | 6271 | |
6272 | MUTEX_NUKE(&clone->nat_lock); | | 6272 | MUTEX_NUKE(&clone->nat_lock); |
6273 | | | 6273 | |
6274 | clone->nat_rev = fin->fin_rev; | | 6274 | clone->nat_rev = fin->fin_rev; |
6275 | clone->nat_aps = NULL; | | 6275 | clone->nat_aps = NULL; |
6276 | /* | | 6276 | /* |
6277 | * Initialize all these so that ipf_nat_delete() doesn't cause a crash. | | 6277 | * Initialize all these so that ipf_nat_delete() doesn't cause a crash. |
6278 | */ | | 6278 | */ |
6279 | clone->nat_tqe.tqe_pnext = NULL; | | 6279 | clone->nat_tqe.tqe_pnext = NULL; |
6280 | clone->nat_tqe.tqe_next = NULL; | | 6280 | clone->nat_tqe.tqe_next = NULL; |
6281 | clone->nat_tqe.tqe_ifq = NULL; | | 6281 | clone->nat_tqe.tqe_ifq = NULL; |
6282 | clone->nat_tqe.tqe_parent = clone; | | 6282 | clone->nat_tqe.tqe_parent = clone; |
6283 | | | 6283 | |
6284 | clone->nat_flags &= ~SI_CLONE; | | 6284 | clone->nat_flags &= ~SI_CLONE; |
6285 | clone->nat_flags |= SI_CLONED; | | 6285 | clone->nat_flags |= SI_CLONED; |
6286 | | | 6286 | |
6287 | if (clone->nat_hm) | | 6287 | if (clone->nat_hm) |
6288 | clone->nat_hm->hm_ref++; | | 6288 | clone->nat_hm->hm_ref++; |
6289 | | | 6289 | |
6290 | if (ipf_nat_insert(softc, softn, clone) == -1) { | | 6290 | if (ipf_nat_insert(softc, softn, clone) == -1) { |
6291 | KFREE(clone); | | 6291 | KFREE(clone); |
6292 | NBUMPSIDED(fin->fin_out, ns_insert_fail); | | 6292 | NBUMPSIDED(fin->fin_out, ns_insert_fail); |
6293 | return NULL; | | 6293 | return NULL; |
6294 | } | | 6294 | } |
6295 | | | 6295 | |
6296 | np = clone->nat_ptr; | | 6296 | np = clone->nat_ptr; |
6297 | if (np != NULL) { | | 6297 | if (np != NULL) { |
6298 | if (softn->ipf_nat_logging) | | 6298 | if (softn->ipf_nat_logging) |
6299 | ipf_nat_log(softc, softn, clone, NL_CLONE); | | 6299 | ipf_nat_log(softc, softn, clone, NL_CLONE); |
6300 | np->in_use++; | | 6300 | np->in_use++; |
6301 | } | | 6301 | } |
6302 | fr = clone->nat_fr; | | 6302 | fr = clone->nat_fr; |
6303 | if (fr != NULL) { | | 6303 | if (fr != NULL) { |
6304 | MUTEX_ENTER(&fr->fr_lock); | | 6304 | MUTEX_ENTER(&fr->fr_lock); |
6305 | fr->fr_ref++; | | 6305 | fr->fr_ref++; |
6306 | MUTEX_EXIT(&fr->fr_lock); | | 6306 | MUTEX_EXIT(&fr->fr_lock); |
6307 | } | | 6307 | } |
6308 | | | 6308 | |
6309 | | | 6309 | |
6310 | /* | | 6310 | /* |
6311 | * Because the clone is created outside the normal loop of things and | | 6311 | * Because the clone is created outside the normal loop of things and |
6312 | * TCP has special needs in terms of state, initialise the timeout | | 6312 | * TCP has special needs in terms of state, initialise the timeout |
6313 | * state of the new NAT from here. | | 6313 | * state of the new NAT from here. |
6314 | */ | | 6314 | */ |
6315 | if (clone->nat_pr[0] == IPPROTO_TCP) { | | 6315 | if (clone->nat_pr[0] == IPPROTO_TCP) { |
6316 | (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq, | | 6316 | (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq, |
6317 | clone->nat_flags, 2); | | 6317 | clone->nat_flags, 2); |
6318 | } | | 6318 | } |
6319 | clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone); | | 6319 | clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone); |
6320 | if (softn->ipf_nat_logging) | | 6320 | if (softn->ipf_nat_logging) |
6321 | ipf_nat_log(softc, softn, clone, NL_CLONE); | | 6321 | ipf_nat_log(softc, softn, clone, NL_CLONE); |
6322 | return clone; | | 6322 | return clone; |
6323 | } | | 6323 | } |
6324 | | | 6324 | |
6325 | | | 6325 | |
6326 | /* ------------------------------------------------------------------------ */ | | 6326 | /* ------------------------------------------------------------------------ */ |
6327 | /* Function: ipf_nat_wildok */ | | 6327 | /* Function: ipf_nat_wildok */ |
6328 | /* Returns: int - 1 == packet's ports match wildcards */ | | 6328 | /* Returns: int - 1 == packet's ports match wildcards */ |
6329 | /* 0 == packet's ports don't match wildcards */ | | 6329 | /* 0 == packet's ports don't match wildcards */ |
6330 | /* Parameters: nat(I) - NAT entry */ | | 6330 | /* Parameters: nat(I) - NAT entry */ |
6331 | /* sport(I) - source port */ | | 6331 | /* sport(I) - source port */ |
6332 | /* dport(I) - destination port */ | | 6332 | /* dport(I) - destination port */ |
6333 | /* flags(I) - wildcard flags */ | | 6333 | /* flags(I) - wildcard flags */ |
6334 | /* dir(I) - packet direction */ | | 6334 | /* dir(I) - packet direction */ |
6335 | /* */ | | 6335 | /* */ |
6336 | /* Use NAT entry and packet direction to determine which combination of */ | | 6336 | /* Use NAT entry and packet direction to determine which combination of */ |
6337 | /* wildcard flags should be used. */ | | 6337 | /* wildcard flags should be used. */ |
6338 | /* ------------------------------------------------------------------------ */ | | 6338 | /* ------------------------------------------------------------------------ */ |
6339 | int | | 6339 | int |
6340 | ipf_nat_wildok(nat_t *nat, int sport, int dport, int flags, int dir) | | 6340 | ipf_nat_wildok(nat_t *nat, int sport, int dport, int flags, int dir) |
6341 | { | | 6341 | { |
6342 | /* | | 6342 | /* |
6343 | * When called by dir is set to | | 6343 | * When called by dir is set to |
6344 | * nat_inlookup NAT_INBOUND (0) | | 6344 | * nat_inlookup NAT_INBOUND (0) |
6345 | * nat_outlookup NAT_OUTBOUND (1) | | 6345 | * nat_outlookup NAT_OUTBOUND (1) |
6346 | * | | 6346 | * |
6347 | * We simply combine the packet's direction in dir with the original | | 6347 | * We simply combine the packet's direction in dir with the original |
6348 | * "intended" direction of that NAT entry in nat->nat_dir to decide | | 6348 | * "intended" direction of that NAT entry in nat->nat_dir to decide |
6349 | * which combination of wildcard flags to allow. | | 6349 | * which combination of wildcard flags to allow. |
6350 | */ | | 6350 | */ |
6351 | switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))) | | 6351 | switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))) |
6352 | { | | 6352 | { |
6353 | case 3: /* outbound packet / outbound entry */ | | 6353 | case 3: /* outbound packet / outbound entry */ |
6354 | if (((nat->nat_osport == sport) || | | 6354 | if (((nat->nat_osport == sport) || |
6355 | (flags & SI_W_SPORT)) && | | 6355 | (flags & SI_W_SPORT)) && |
6356 | ((nat->nat_odport == dport) || | | 6356 | ((nat->nat_odport == dport) || |
6357 | (flags & SI_W_DPORT))) | | 6357 | (flags & SI_W_DPORT))) |
6358 | return 1; | | 6358 | return 1; |
6359 | break; | | 6359 | break; |
6360 | case 2: /* outbound packet / inbound entry */ | | 6360 | case 2: /* outbound packet / inbound entry */ |
6361 | if (((nat->nat_osport == dport) || | | 6361 | if (((nat->nat_osport == dport) || |
6362 | (flags & SI_W_SPORT)) && | | 6362 | (flags & SI_W_SPORT)) && |
6363 | ((nat->nat_odport == sport) || | | 6363 | ((nat->nat_odport == sport) || |
6364 | (flags & SI_W_DPORT))) | | 6364 | (flags & SI_W_DPORT))) |
6365 | return 1; | | 6365 | return 1; |
6366 | break; | | 6366 | break; |
6367 | case 1: /* inbound packet / outbound entry */ | | 6367 | case 1: /* inbound packet / outbound entry */ |
6368 | if (((nat->nat_osport == dport) || | | 6368 | if (((nat->nat_osport == dport) || |
6369 | (flags & SI_W_SPORT)) && | | 6369 | (flags & SI_W_SPORT)) && |
6370 | ((nat->nat_odport == sport) || | | 6370 | ((nat->nat_odport == sport) || |
6371 | (flags & SI_W_DPORT))) | | 6371 | (flags & SI_W_DPORT))) |
6372 | return 1; | | 6372 | return 1; |
6373 | break; | | 6373 | break; |
6374 | case 0: /* inbound packet / inbound entry */ | | 6374 | case 0: /* inbound packet / inbound entry */ |
6375 | if (((nat->nat_osport == sport) || | | 6375 | if (((nat->nat_osport == sport) || |
6376 | (flags & SI_W_SPORT)) && | | 6376 | (flags & SI_W_SPORT)) && |
6377 | ((nat->nat_odport == dport) || | | 6377 | ((nat->nat_odport == dport) || |
6378 | (flags & SI_W_DPORT))) | | 6378 | (flags & SI_W_DPORT))) |
6379 | return 1; | | 6379 | return 1; |
6380 | break; | | 6380 | break; |
6381 | default: | | 6381 | default: |
6382 | break; | | 6382 | break; |
6383 | } | | 6383 | } |
6384 | | | 6384 | |
6385 | return(0); | | 6385 | return(0); |
6386 | } | | 6386 | } |
6387 | | | 6387 | |
6388 | | | 6388 | |
6389 | /* ------------------------------------------------------------------------ */ | | 6389 | /* ------------------------------------------------------------------------ */ |
6390 | /* Function: nat_mssclamp */ | | 6390 | /* Function: nat_mssclamp */ |
6391 | /* Returns: Nil */ | | 6391 | /* Returns: Nil */ |
6392 | /* Parameters: tcp(I) - pointer to TCP header */ | | 6392 | /* Parameters: tcp(I) - pointer to TCP header */ |
6393 | /* maxmss(I) - value to clamp the TCP MSS to */ | | 6393 | /* maxmss(I) - value to clamp the TCP MSS to */ |
6394 | /* fin(I) - pointer to packet information */ | | 6394 | /* fin(I) - pointer to packet information */ |
6395 | /* csump(I) - pointer to TCP checksum */ | | 6395 | /* csump(I) - pointer to TCP checksum */ |
6396 | /* */ | | 6396 | /* */ |
6397 | /* Check for MSS option and clamp it if necessary. If found and changed, */ | | 6397 | /* Check for MSS option and clamp it if necessary. If found and changed, */ |
6398 | /* then the TCP header checksum will be updated to reflect the change in */ | | 6398 | /* then the TCP header checksum will be updated to reflect the change in */ |
6399 | /* the MSS. */ | | 6399 | /* the MSS. */ |
6400 | /* ------------------------------------------------------------------------ */ | | 6400 | /* ------------------------------------------------------------------------ */ |
6401 | static void | | 6401 | static void |
6402 | ipf_nat_mssclamp(tcphdr_t *tcp, u_32_t maxmss, fr_info_t *fin, u_short *csump) | | 6402 | ipf_nat_mssclamp(tcphdr_t *tcp, u_32_t maxmss, fr_info_t *fin, u_short *csump) |
6403 | { | | 6403 | { |
6404 | u_char *cp, *ep, opt; | | 6404 | u_char *cp, *ep, opt; |
6405 | int hlen, advance; | | 6405 | int hlen, advance; |
6406 | u_32_t mss, sumd; | | 6406 | u_32_t mss, sumd; |
6407 | | | 6407 | |
6408 | hlen = TCP_OFF(tcp) << 2; | | 6408 | hlen = TCP_OFF(tcp) << 2; |
6409 | if (hlen > sizeof(*tcp)) { | | 6409 | if (hlen > sizeof(*tcp)) { |
6410 | cp = (u_char *)tcp + sizeof(*tcp); | | 6410 | cp = (u_char *)tcp + sizeof(*tcp); |
6411 | ep = (u_char *)tcp + hlen; | | 6411 | ep = (u_char *)tcp + hlen; |
6412 | | | 6412 | |
6413 | while (cp < ep) { | | 6413 | while (cp < ep) { |
6414 | opt = cp[0]; | | 6414 | opt = cp[0]; |
6415 | if (opt == TCPOPT_EOL) | | 6415 | if (opt == TCPOPT_EOL) |
6416 | break; | | 6416 | break; |
6417 | else if (opt == TCPOPT_NOP) { | | 6417 | else if (opt == TCPOPT_NOP) { |
6418 | cp++; | | 6418 | cp++; |
6419 | continue; | | 6419 | continue; |
6420 | } | | 6420 | } |
6421 | | | 6421 | |
6422 | if (cp + 1 >= ep) | | 6422 | if (cp + 1 >= ep) |
6423 | break; | | 6423 | break; |
6424 | advance = cp[1]; | | 6424 | advance = cp[1]; |
6425 | if ((cp + advance > ep) || (advance <= 0)) | | 6425 | if ((cp + advance > ep) || (advance <= 0)) |
6426 | break; | | 6426 | break; |
6427 | switch (opt) | | 6427 | switch (opt) |
6428 | { | | 6428 | { |
6429 | case TCPOPT_MAXSEG: | | 6429 | case TCPOPT_MAXSEG: |
6430 | if (advance != 4) | | 6430 | if (advance != 4) |
6431 | break; | | 6431 | break; |
6432 | mss = cp[2] * 256 + cp[3]; | | 6432 | mss = cp[2] * 256 + cp[3]; |
6433 | if (mss > maxmss) { | | 6433 | if (mss > maxmss) { |
6434 | cp[2] = maxmss / 256; | | 6434 | cp[2] = maxmss / 256; |
6435 | cp[3] = maxmss & 0xff; | | 6435 | cp[3] = maxmss & 0xff; |
6436 | CALC_SUMD(mss, maxmss, sumd); | | 6436 | CALC_SUMD(mss, maxmss, sumd); |
6437 | ipf_fix_outcksum(0, csump, sumd, 0); | | 6437 | ipf_fix_outcksum(0, csump, sumd, 0); |
6438 | } | | 6438 | } |
6439 | break; | | 6439 | break; |
6440 | default: | | 6440 | default: |
6441 | /* ignore unknown options */ | | 6441 | /* ignore unknown options */ |
6442 | break; | | 6442 | break; |
6443 | } | | 6443 | } |
6444 | | | 6444 | |
6445 | cp += advance; | | 6445 | cp += advance; |
6446 | } | | 6446 | } |
6447 | } | | 6447 | } |
6448 | } | | 6448 | } |
6449 | | | 6449 | |
6450 | | | 6450 | |
6451 | /* ------------------------------------------------------------------------ */ | | 6451 | /* ------------------------------------------------------------------------ */ |
6452 | /* Function: ipf_nat_setqueue */ | | 6452 | /* Function: ipf_nat_setqueue */ |
6453 | /* Returns: Nil */ | | 6453 | /* Returns: Nil */ |
6454 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6454 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6455 | /* softn(I) - pointer to NAT context structure */ | | 6455 | /* softn(I) - pointer to NAT context structure */ |
6456 | /* nat(I)- pointer to NAT structure */ | | 6456 | /* nat(I)- pointer to NAT structure */ |
6457 | /* Locks: ipf_nat (read or write) */ | | 6457 | /* Locks: ipf_nat (read or write) */ |
6458 | /* */ | | 6458 | /* */ |
6459 | /* Put the NAT entry on its default queue entry, using rev as a helped in */ | | 6459 | /* Put the NAT entry on its default queue entry, using rev as a helped in */ |
6460 | /* determining which queue it should be placed on. */ | | 6460 | /* determining which queue it should be placed on. */ |
6461 | /* ------------------------------------------------------------------------ */ | | 6461 | /* ------------------------------------------------------------------------ */ |
6462 | void | | 6462 | void |
6463 | ipf_nat_setqueue(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) | | 6463 | ipf_nat_setqueue(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat) |
6464 | { | | 6464 | { |
6465 | ipftq_t *oifq, *nifq; | | 6465 | ipftq_t *oifq, *nifq; |
6466 | int rev = nat->nat_rev; | | 6466 | int rev = nat->nat_rev; |
6467 | | | 6467 | |
6468 | if (nat->nat_ptr != NULL) | | 6468 | if (nat->nat_ptr != NULL) |
6469 | nifq = nat->nat_ptr->in_tqehead[rev]; | | 6469 | nifq = nat->nat_ptr->in_tqehead[rev]; |
6470 | else | | 6470 | else |
6471 | nifq = NULL; | | 6471 | nifq = NULL; |
6472 | | | 6472 | |
6473 | if (nifq == NULL) { | | 6473 | if (nifq == NULL) { |
6474 | switch (nat->nat_pr[0]) | | 6474 | switch (nat->nat_pr[0]) |
6475 | { | | 6475 | { |
6476 | case IPPROTO_UDP : | | 6476 | case IPPROTO_UDP : |
6477 | nifq = &softn->ipf_nat_udptq; | | 6477 | nifq = &softn->ipf_nat_udptq; |
6478 | break; | | 6478 | break; |
6479 | case IPPROTO_ICMP : | | 6479 | case IPPROTO_ICMP : |
6480 | nifq = &softn->ipf_nat_icmptq; | | 6480 | nifq = &softn->ipf_nat_icmptq; |
6481 | break; | | 6481 | break; |
6482 | case IPPROTO_TCP : | | 6482 | case IPPROTO_TCP : |
6483 | nifq = softn->ipf_nat_tcptq + | | 6483 | nifq = softn->ipf_nat_tcptq + |
6484 | nat->nat_tqe.tqe_state[rev]; | | 6484 | nat->nat_tqe.tqe_state[rev]; |
6485 | break; | | 6485 | break; |
6486 | default : | | 6486 | default : |
6487 | nifq = &softn->ipf_nat_iptq; | | 6487 | nifq = &softn->ipf_nat_iptq; |
6488 | break; | | 6488 | break; |
6489 | } | | 6489 | } |
6490 | } | | 6490 | } |
6491 | | | 6491 | |
6492 | oifq = nat->nat_tqe.tqe_ifq; | | 6492 | oifq = nat->nat_tqe.tqe_ifq; |
6493 | /* | | 6493 | /* |
6494 | * If it's currently on a timeout queue, move it from one queue to | | 6494 | * If it's currently on a timeout queue, move it from one queue to |
6495 | * another, else put it on the end of the newly determined queue. | | 6495 | * another, else put it on the end of the newly determined queue. |
6496 | */ | | 6496 | */ |
6497 | if (oifq != NULL) | | 6497 | if (oifq != NULL) |
6498 | ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq); | | 6498 | ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq); |
6499 | else | | 6499 | else |
6500 | ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat); | | 6500 | ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat); |
6501 | return; | | 6501 | return; |
6502 | } | | 6502 | } |
6503 | | | 6503 | |
6504 | | | 6504 | |
6505 | /* ------------------------------------------------------------------------ */ | | 6505 | /* ------------------------------------------------------------------------ */ |
6506 | /* Function: nat_getnext */ | | 6506 | /* Function: nat_getnext */ |
6507 | /* Returns: int - 0 == ok, else error */ | | 6507 | /* Returns: int - 0 == ok, else error */ |
6508 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6508 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6509 | /* t(I) - pointer to ipftoken structure */ | | 6509 | /* t(I) - pointer to ipftoken structure */ |
6510 | /* itp(I) - pointer to ipfgeniter_t structure */ | | 6510 | /* itp(I) - pointer to ipfgeniter_t structure */ |
6511 | /* */ | | 6511 | /* */ |
6512 | /* Fetch the next nat/ipnat structure pointer from the linked list and */ | | 6512 | /* Fetch the next nat/ipnat structure pointer from the linked list and */ |
6513 | /* copy it out to the storage space pointed to by itp_data. The next item */ | | 6513 | /* copy it out to the storage space pointed to by itp_data. The next item */ |
6514 | /* in the list to look at is put back in the ipftoken struture. */ | | 6514 | /* in the list to look at is put back in the ipftoken struture. */ |
6515 | /* ------------------------------------------------------------------------ */ | | 6515 | /* ------------------------------------------------------------------------ */ |
6516 | static int | | 6516 | static int |
6517 | ipf_nat_getnext(ipf_main_softc_t *softc, ipftoken_t *t, ipfgeniter_t *itp, | | 6517 | ipf_nat_getnext(ipf_main_softc_t *softc, ipftoken_t *t, ipfgeniter_t *itp, |
6518 | ipfobj_t *objp) | | 6518 | ipfobj_t *objp) |
6519 | { | | 6519 | { |
6520 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 6520 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
6521 | hostmap_t *hm, *nexthm = NULL, zerohm; | | 6521 | hostmap_t *hm, *nexthm = NULL, zerohm; |
6522 | ipnat_t *ipn, *nextipnat = NULL, zeroipn; | | 6522 | ipnat_t *ipn, *nextipnat = NULL, zeroipn; |
6523 | nat_t *nat, *nextnat = NULL, zeronat; | | 6523 | nat_t *nat, *nextnat = NULL, zeronat; |
6524 | int error = 0; | | 6524 | int error = 0; |
6525 | void *nnext; | | 6525 | void *nnext; |
6526 | | | 6526 | |
6527 | if (itp->igi_nitems != 1) { | | 6527 | if (itp->igi_nitems != 1) { |
6528 | IPFERROR(60075); | | 6528 | IPFERROR(60075); |
6529 | return ENOSPC; | | 6529 | return ENOSPC; |
6530 | } | | 6530 | } |
6531 | | | 6531 | |
6532 | READ_ENTER(&softc->ipf_nat); | | 6532 | READ_ENTER(&softc->ipf_nat); |
6533 | | | 6533 | |
6534 | switch (itp->igi_type) | | 6534 | switch (itp->igi_type) |
6535 | { | | 6535 | { |
6536 | case IPFGENITER_HOSTMAP : | | 6536 | case IPFGENITER_HOSTMAP : |
6537 | hm = t->ipt_data; | | 6537 | hm = t->ipt_data; |
6538 | if (hm == NULL) { | | 6538 | if (hm == NULL) { |
6539 | nexthm = softn->ipf_hm_maplist; | | 6539 | nexthm = softn->ipf_hm_maplist; |
6540 | } else { | | 6540 | } else { |
6541 | nexthm = hm->hm_next; | | 6541 | nexthm = hm->hm_next; |
6542 | } | | 6542 | } |
6543 | if (nexthm != NULL) { | | 6543 | if (nexthm != NULL) { |
6544 | ATOMIC_INC32(nexthm->hm_ref); | | 6544 | ATOMIC_INC32(nexthm->hm_ref); |
6545 | t->ipt_data = nexthm; | | 6545 | t->ipt_data = nexthm; |
6546 | } else { | | 6546 | } else { |
6547 | bzero(&zerohm, sizeof(zerohm)); | | 6547 | bzero(&zerohm, sizeof(zerohm)); |
6548 | nexthm = &zerohm; | | 6548 | nexthm = &zerohm; |
6549 | t->ipt_data = NULL; | | 6549 | t->ipt_data = NULL; |
6550 | } | | 6550 | } |
6551 | nnext = nexthm->hm_next; | | 6551 | nnext = nexthm->hm_next; |
6552 | break; | | 6552 | break; |
6553 | | | 6553 | |
6554 | case IPFGENITER_IPNAT : | | 6554 | case IPFGENITER_IPNAT : |
6555 | ipn = t->ipt_data; | | 6555 | ipn = t->ipt_data; |
6556 | if (ipn == NULL) { | | 6556 | if (ipn == NULL) { |
6557 | nextipnat = softn->ipf_nat_list; | | 6557 | nextipnat = softn->ipf_nat_list; |
6558 | } else { | | 6558 | } else { |
6559 | nextipnat = ipn->in_next; | | 6559 | nextipnat = ipn->in_next; |
6560 | } | | 6560 | } |
6561 | if (nextipnat != NULL) { | | 6561 | if (nextipnat != NULL) { |
6562 | ATOMIC_INC32(nextipnat->in_use); | | 6562 | ATOMIC_INC32(nextipnat->in_use); |
6563 | t->ipt_data = nextipnat; | | 6563 | t->ipt_data = nextipnat; |
6564 | } else { | | 6564 | } else { |
6565 | bzero(&zeroipn, sizeof(zeroipn)); | | 6565 | bzero(&zeroipn, sizeof(zeroipn)); |
6566 | nextipnat = &zeroipn; | | 6566 | nextipnat = &zeroipn; |
6567 | t->ipt_data = NULL; | | 6567 | t->ipt_data = NULL; |
6568 | } | | 6568 | } |
6569 | nnext = nextipnat->in_next; | | 6569 | nnext = nextipnat->in_next; |
6570 | break; | | 6570 | break; |
6571 | | | 6571 | |
6572 | case IPFGENITER_NAT : | | 6572 | case IPFGENITER_NAT : |
6573 | nat = t->ipt_data; | | 6573 | nat = t->ipt_data; |
6574 | if (nat == NULL) { | | 6574 | if (nat == NULL) { |
6575 | nextnat = softn->ipf_nat_instances; | | 6575 | nextnat = softn->ipf_nat_instances; |
6576 | } else { | | 6576 | } else { |
6577 | nextnat = nat->nat_next; | | 6577 | nextnat = nat->nat_next; |
6578 | } | | 6578 | } |
6579 | if (nextnat != NULL) { | | 6579 | if (nextnat != NULL) { |
6580 | MUTEX_ENTER(&nextnat->nat_lock); | | 6580 | MUTEX_ENTER(&nextnat->nat_lock); |
6581 | nextnat->nat_ref++; | | 6581 | nextnat->nat_ref++; |
6582 | MUTEX_EXIT(&nextnat->nat_lock); | | 6582 | MUTEX_EXIT(&nextnat->nat_lock); |
6583 | t->ipt_data = nextnat; | | 6583 | t->ipt_data = nextnat; |
6584 | } else { | | 6584 | } else { |
6585 | bzero(&zeronat, sizeof(zeronat)); | | 6585 | bzero(&zeronat, sizeof(zeronat)); |
6586 | nextnat = &zeronat; | | 6586 | nextnat = &zeronat; |
6587 | t->ipt_data = NULL; | | 6587 | t->ipt_data = NULL; |
6588 | } | | 6588 | } |
6589 | nnext = nextnat->nat_next; | | 6589 | nnext = nextnat->nat_next; |
6590 | break; | | 6590 | break; |
6591 | | | 6591 | |
6592 | default : | | 6592 | default : |
6593 | RWLOCK_EXIT(&softc->ipf_nat); | | 6593 | RWLOCK_EXIT(&softc->ipf_nat); |
6594 | IPFERROR(60055); | | 6594 | IPFERROR(60055); |
6595 | return EINVAL; | | 6595 | return EINVAL; |
6596 | } | | 6596 | } |
6597 | | | 6597 | |
6598 | RWLOCK_EXIT(&softc->ipf_nat); | | 6598 | RWLOCK_EXIT(&softc->ipf_nat); |
6599 | | | 6599 | |
6600 | objp->ipfo_ptr = itp->igi_data; | | 6600 | objp->ipfo_ptr = itp->igi_data; |
6601 | | | 6601 | |
6602 | switch (itp->igi_type) | | 6602 | switch (itp->igi_type) |
6603 | { | | 6603 | { |
6604 | case IPFGENITER_HOSTMAP : | | 6604 | case IPFGENITER_HOSTMAP : |
6605 | error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm)); | | 6605 | error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm)); |
6606 | if (error != 0) { | | 6606 | if (error != 0) { |
6607 | IPFERROR(60049); | | 6607 | IPFERROR(60049); |
6608 | error = EFAULT; | | 6608 | error = EFAULT; |
6609 | } | | 6609 | } |
6610 | if (hm != NULL) { | | 6610 | if (hm != NULL) { |
6611 | WRITE_ENTER(&softc->ipf_nat); | | 6611 | WRITE_ENTER(&softc->ipf_nat); |
6612 | ipf_nat_hostmapdel(softc, &hm); | | 6612 | ipf_nat_hostmapdel(softc, &hm); |
6613 | RWLOCK_EXIT(&softc->ipf_nat); | | 6613 | RWLOCK_EXIT(&softc->ipf_nat); |
6614 | } | | 6614 | } |
6615 | break; | | 6615 | break; |
6616 | | | 6616 | |
6617 | case IPFGENITER_IPNAT : | | 6617 | case IPFGENITER_IPNAT : |
6618 | objp->ipfo_size = nextipnat->in_size; | | 6618 | objp->ipfo_size = nextipnat->in_size; |
6619 | objp->ipfo_type = IPFOBJ_IPNAT; | | 6619 | objp->ipfo_type = IPFOBJ_IPNAT; |
6620 | error = ipf_outobjk(softc, objp, nextipnat); | | 6620 | error = ipf_outobjk(softc, objp, nextipnat); |
6621 | if (ipn != NULL) { | | 6621 | if (ipn != NULL) { |
6622 | WRITE_ENTER(&softc->ipf_nat); | | 6622 | WRITE_ENTER(&softc->ipf_nat); |
6623 | ipf_nat_rule_deref(softc, &ipn); | | 6623 | ipf_nat_rule_deref(softc, &ipn); |
6624 | RWLOCK_EXIT(&softc->ipf_nat); | | 6624 | RWLOCK_EXIT(&softc->ipf_nat); |
6625 | } | | 6625 | } |
6626 | break; | | 6626 | break; |
6627 | | | 6627 | |
6628 | case IPFGENITER_NAT : | | 6628 | case IPFGENITER_NAT : |
6629 | objp->ipfo_size = sizeof(nat_t); | | 6629 | objp->ipfo_size = sizeof(nat_t); |
6630 | objp->ipfo_type = IPFOBJ_NAT; | | 6630 | objp->ipfo_type = IPFOBJ_NAT; |
6631 | error = ipf_outobjk(softc, objp, nextnat); | | 6631 | error = ipf_outobjk(softc, objp, nextnat); |
6632 | if (nat != NULL) | | 6632 | if (nat != NULL) |
6633 | ipf_nat_deref(softc, &nat); | | 6633 | ipf_nat_deref(softc, &nat); |
6634 | | | 6634 | |
6635 | break; | | 6635 | break; |
6636 | } | | 6636 | } |
6637 | | | 6637 | |
6638 | if (nnext == NULL) | | 6638 | if (nnext == NULL) |
6639 | ipf_token_mark_complete(t); | | 6639 | ipf_token_mark_complete(t); |
6640 | | | 6640 | |
6641 | return error; | | 6641 | return error; |
6642 | } | | 6642 | } |
6643 | | | 6643 | |
6644 | | | 6644 | |
6645 | /* ------------------------------------------------------------------------ */ | | 6645 | /* ------------------------------------------------------------------------ */ |
6646 | /* Function: nat_extraflush */ | | 6646 | /* Function: nat_extraflush */ |
6647 | /* Returns: int - 0 == success, -1 == failure */ | | 6647 | /* Returns: int - 0 == success, -1 == failure */ |
6648 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6648 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6649 | /* softn(I) - pointer to NAT context structure */ | | 6649 | /* softn(I) - pointer to NAT context structure */ |
6650 | /* which(I) - how to flush the active NAT table */ | | 6650 | /* which(I) - how to flush the active NAT table */ |
6651 | /* Write Locks: ipf_nat */ | | 6651 | /* Write Locks: ipf_nat */ |
6652 | /* */ | | 6652 | /* */ |
6653 | /* Flush nat tables. Three actions currently defined: */ | | 6653 | /* Flush nat tables. Three actions currently defined: */ |
6654 | /* which == 0 : flush all nat table entries */ | | 6654 | /* which == 0 : flush all nat table entries */ |
6655 | /* which == 1 : flush TCP connections which have started to close but are */ | | 6655 | /* which == 1 : flush TCP connections which have started to close but are */ |
6656 | /* stuck for some reason. */ | | 6656 | /* stuck for some reason. */ |
6657 | /* which == 2 : flush TCP connections which have been idle for a long time, */ | | 6657 | /* which == 2 : flush TCP connections which have been idle for a long time, */ |
6658 | /* starting at > 4 days idle and working back in successive half-*/ | | 6658 | /* starting at > 4 days idle and working back in successive half-*/ |
6659 | /* days to at most 12 hours old. If this fails to free enough */ | | 6659 | /* days to at most 12 hours old. If this fails to free enough */ |
6660 | /* slots then work backwards in half hour slots to 30 minutes. */ | | 6660 | /* slots then work backwards in half hour slots to 30 minutes. */ |
6661 | /* If that too fails, then work backwards in 30 second intervals */ | | 6661 | /* If that too fails, then work backwards in 30 second intervals */ |
6662 | /* for the last 30 minutes to at worst 30 seconds idle. */ | | 6662 | /* for the last 30 minutes to at worst 30 seconds idle. */ |
6663 | /* ------------------------------------------------------------------------ */ | | 6663 | /* ------------------------------------------------------------------------ */ |
6664 | static int | | 6664 | static int |
6665 | ipf_nat_extraflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, int which) | | 6665 | ipf_nat_extraflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, int which) |
6666 | { | | 6666 | { |
6667 | nat_t *nat, **natp; | | 6667 | nat_t *nat, **natp; |
6668 | ipftqent_t *tqn; | | 6668 | ipftqent_t *tqn; |
6669 | ipftq_t *ifq; | | 6669 | ipftq_t *ifq; |
6670 | int removed; | | 6670 | int removed; |
6671 | SPL_INT(s); | | 6671 | SPL_INT(s); |
6672 | | | 6672 | |
6673 | removed = 0; | | 6673 | removed = 0; |
6674 | | | 6674 | |
6675 | SPL_NET(s); | | 6675 | SPL_NET(s); |
6676 | switch (which) | | 6676 | switch (which) |
6677 | { | | 6677 | { |
6678 | case 0 : | | 6678 | case 0 : |
6679 | softn->ipf_nat_stats.ns_flush_all++; | | 6679 | softn->ipf_nat_stats.ns_flush_all++; |
6680 | /* | | 6680 | /* |
6681 | * Style 0 flush removes everything... | | 6681 | * Style 0 flush removes everything... |
6682 | */ | | 6682 | */ |
6683 | for (natp = &softn->ipf_nat_instances; | | 6683 | for (natp = &softn->ipf_nat_instances; |
6684 | ((nat = *natp) != NULL); ) { | | 6684 | ((nat = *natp) != NULL); ) { |
6685 | ipf_nat_delete(softc, nat, NL_FLUSH); | | 6685 | ipf_nat_delete(softc, nat, NL_FLUSH); |
6686 | removed++; | | 6686 | removed++; |
6687 | } | | 6687 | } |
6688 | break; | | 6688 | break; |
6689 | | | 6689 | |
6690 | case 1 : | | 6690 | case 1 : |
6691 | softn->ipf_nat_stats.ns_flush_closing++; | | 6691 | softn->ipf_nat_stats.ns_flush_closing++; |
6692 | /* | | 6692 | /* |
6693 | * Since we're only interested in things that are closing, | | 6693 | * Since we're only interested in things that are closing, |
6694 | * we can start with the appropriate timeout queue. | | 6694 | * we can start with the appropriate timeout queue. |
6695 | */ | | 6695 | */ |
6696 | for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT; | | 6696 | for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT; |
6697 | ifq != NULL; ifq = ifq->ifq_next) { | | 6697 | ifq != NULL; ifq = ifq->ifq_next) { |
6698 | | | 6698 | |
6699 | for (tqn = ifq->ifq_head; tqn != NULL; ) { | | 6699 | for (tqn = ifq->ifq_head; tqn != NULL; ) { |
6700 | nat = tqn->tqe_parent; | | 6700 | nat = tqn->tqe_parent; |
6701 | tqn = tqn->tqe_next; | | 6701 | tqn = tqn->tqe_next; |
6702 | if (nat->nat_pr[0] != IPPROTO_TCP || | | 6702 | if (nat->nat_pr[0] != IPPROTO_TCP || |
6703 | nat->nat_pr[1] != IPPROTO_TCP) | | 6703 | nat->nat_pr[1] != IPPROTO_TCP) |
6704 | break; | | 6704 | break; |
6705 | ipf_nat_delete(softc, nat, NL_EXPIRE); | | 6705 | ipf_nat_delete(softc, nat, NL_EXPIRE); |
6706 | removed++; | | 6706 | removed++; |
6707 | } | | 6707 | } |
6708 | } | | 6708 | } |
6709 | | | 6709 | |
6710 | /* | | 6710 | /* |
6711 | * Also need to look through the user defined queues. | | 6711 | * Also need to look through the user defined queues. |
6712 | */ | | 6712 | */ |
6713 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; | | 6713 | for (ifq = softn->ipf_nat_utqe; ifq != NULL; |
6714 | ifq = ifq->ifq_next) { | | 6714 | ifq = ifq->ifq_next) { |
6715 | for (tqn = ifq->ifq_head; tqn != NULL; ) { | | 6715 | for (tqn = ifq->ifq_head; tqn != NULL; ) { |
6716 | nat = tqn->tqe_parent; | | 6716 | nat = tqn->tqe_parent; |
6717 | tqn = tqn->tqe_next; | | 6717 | tqn = tqn->tqe_next; |
6718 | if (nat->nat_pr[0] != IPPROTO_TCP || | | 6718 | if (nat->nat_pr[0] != IPPROTO_TCP || |
6719 | nat->nat_pr[1] != IPPROTO_TCP) | | 6719 | nat->nat_pr[1] != IPPROTO_TCP) |
6720 | continue; | | 6720 | continue; |
6721 | | | 6721 | |
6722 | if ((nat->nat_tcpstate[0] > | | 6722 | if ((nat->nat_tcpstate[0] > |
6723 | IPF_TCPS_ESTABLISHED) && | | 6723 | IPF_TCPS_ESTABLISHED) && |
6724 | (nat->nat_tcpstate[1] > | | 6724 | (nat->nat_tcpstate[1] > |
6725 | IPF_TCPS_ESTABLISHED)) { | | 6725 | IPF_TCPS_ESTABLISHED)) { |
6726 | ipf_nat_delete(softc, nat, NL_EXPIRE); | | 6726 | ipf_nat_delete(softc, nat, NL_EXPIRE); |
6727 | removed++; | | 6727 | removed++; |
6728 | } | | 6728 | } |
6729 | } | | 6729 | } |
6730 | } | | 6730 | } |
6731 | break; | | 6731 | break; |
6732 | | | 6732 | |
6733 | /* | | 6733 | /* |
6734 | * Args 5-11 correspond to flushing those particular states | | 6734 | * Args 5-11 correspond to flushing those particular states |
6735 | * for TCP connections. | | 6735 | * for TCP connections. |
6736 | */ | | 6736 | */ |
6737 | case IPF_TCPS_CLOSE_WAIT : | | 6737 | case IPF_TCPS_CLOSE_WAIT : |
6738 | case IPF_TCPS_FIN_WAIT_1 : | | 6738 | case IPF_TCPS_FIN_WAIT_1 : |
6739 | case IPF_TCPS_CLOSING : | | 6739 | case IPF_TCPS_CLOSING : |
6740 | case IPF_TCPS_LAST_ACK : | | 6740 | case IPF_TCPS_LAST_ACK : |
6741 | case IPF_TCPS_FIN_WAIT_2 : | | 6741 | case IPF_TCPS_FIN_WAIT_2 : |
6742 | case IPF_TCPS_TIME_WAIT : | | 6742 | case IPF_TCPS_TIME_WAIT : |
6743 | case IPF_TCPS_CLOSED : | | 6743 | case IPF_TCPS_CLOSED : |
6744 | softn->ipf_nat_stats.ns_flush_state++; | | 6744 | softn->ipf_nat_stats.ns_flush_state++; |
6745 | tqn = softn->ipf_nat_tcptq[which].ifq_head; | | 6745 | tqn = softn->ipf_nat_tcptq[which].ifq_head; |
6746 | while (tqn != NULL) { | | 6746 | while (tqn != NULL) { |
6747 | nat = tqn->tqe_parent; | | 6747 | nat = tqn->tqe_parent; |
6748 | tqn = tqn->tqe_next; | | 6748 | tqn = tqn->tqe_next; |
6749 | ipf_nat_delete(softc, nat, NL_FLUSH); | | 6749 | ipf_nat_delete(softc, nat, NL_FLUSH); |
6750 | removed++; | | 6750 | removed++; |
6751 | } | | 6751 | } |
6752 | break; | | 6752 | break; |
6753 | | | 6753 | |
6754 | default : | | 6754 | default : |
6755 | if (which < 30) | | 6755 | if (which < 30) |
6756 | break; | | 6756 | break; |
6757 | | | 6757 | |
6758 | softn->ipf_nat_stats.ns_flush_timeout++; | | 6758 | softn->ipf_nat_stats.ns_flush_timeout++; |
6759 | /* | | 6759 | /* |
6760 | * Take a large arbitrary number to mean the number of seconds | | 6760 | * Take a large arbitrary number to mean the number of seconds |
6761 | * for which which consider to be the maximum value we'll allow | | 6761 | * for which which consider to be the maximum value we'll allow |
6762 | * the expiration to be. | | 6762 | * the expiration to be. |
6763 | */ | | 6763 | */ |
6764 | which = IPF_TTLVAL(which); | | 6764 | which = IPF_TTLVAL(which); |
6765 | for (natp = &softn->ipf_nat_instances; | | 6765 | for (natp = &softn->ipf_nat_instances; |
6766 | ((nat = *natp) != NULL); ) { | | 6766 | ((nat = *natp) != NULL); ) { |
6767 | if (softc->ipf_ticks - nat->nat_touched > which) { | | 6767 | if (softc->ipf_ticks - nat->nat_touched > which) { |
6768 | ipf_nat_delete(softc, nat, NL_FLUSH); | | 6768 | ipf_nat_delete(softc, nat, NL_FLUSH); |
6769 | removed++; | | 6769 | removed++; |
6770 | } else | | 6770 | } else |
6771 | natp = &nat->nat_next; | | 6771 | natp = &nat->nat_next; |
6772 | } | | 6772 | } |
6773 | break; | | 6773 | break; |
6774 | } | | 6774 | } |
6775 | | | 6775 | |
6776 | if (which != 2) { | | 6776 | if (which != 2) { |
6777 | SPL_X(s); | | 6777 | SPL_X(s); |
6778 | return removed; | | 6778 | return removed; |
6779 | } | | 6779 | } |
6780 | | | 6780 | |
6781 | softn->ipf_nat_stats.ns_flush_queue++; | | 6781 | softn->ipf_nat_stats.ns_flush_queue++; |
6782 | | | 6782 | |
6783 | /* | | 6783 | /* |
6784 | * Asked to remove inactive entries because the table is full, try | | 6784 | * Asked to remove inactive entries because the table is full, try |
6785 | * again, 3 times, if first attempt failed with a different criteria | | 6785 | * again, 3 times, if first attempt failed with a different criteria |
6786 | * each time. The order tried in must be in decreasing age. | | 6786 | * each time. The order tried in must be in decreasing age. |
6787 | * Another alternative is to implement random drop and drop N entries | | 6787 | * Another alternative is to implement random drop and drop N entries |
6788 | * at random until N have been freed up. | | 6788 | * at random until N have been freed up. |
6789 | */ | | 6789 | */ |
6790 | if (softc->ipf_ticks - softn->ipf_nat_last_force_flush > | | 6790 | if (softc->ipf_ticks - softn->ipf_nat_last_force_flush > |
6791 | IPF_TTLVAL(5)) { | | 6791 | IPF_TTLVAL(5)) { |
6792 | softn->ipf_nat_last_force_flush = softc->ipf_ticks; | | 6792 | softn->ipf_nat_last_force_flush = softc->ipf_ticks; |
6793 | | | 6793 | |
6794 | removed = ipf_queueflush(softc, ipf_nat_flush_entry, | | 6794 | removed = ipf_queueflush(softc, ipf_nat_flush_entry, |
6795 | softn->ipf_nat_tcptq, | | 6795 | softn->ipf_nat_tcptq, |
6796 | softn->ipf_nat_utqe, | | 6796 | softn->ipf_nat_utqe, |
6797 | &softn->ipf_nat_stats.ns_active, | | 6797 | &softn->ipf_nat_stats.ns_active, |
6798 | softn->ipf_nat_table_sz, | | 6798 | softn->ipf_nat_table_sz, |
6799 | softn->ipf_nat_table_wm_low); | | 6799 | softn->ipf_nat_table_wm_low); |
6800 | } | | 6800 | } |
6801 | | | 6801 | |
6802 | SPL_X(s); | | 6802 | SPL_X(s); |
6803 | return removed; | | 6803 | return removed; |
6804 | } | | 6804 | } |
6805 | | | 6805 | |
6806 | | | 6806 | |
6807 | /* ------------------------------------------------------------------------ */ | | 6807 | /* ------------------------------------------------------------------------ */ |
6808 | /* Function: ipf_nat_flush_entry */ | | 6808 | /* Function: ipf_nat_flush_entry */ |
6809 | /* Returns: 0 - always succeeds */ | | 6809 | /* Returns: 0 - always succeeds */ |
6810 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6810 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6811 | /* entry(I) - pointer to NAT entry */ | | 6811 | /* entry(I) - pointer to NAT entry */ |
6812 | /* Write Locks: ipf_nat */ | | 6812 | /* Write Locks: ipf_nat */ |
6813 | /* */ | | 6813 | /* */ |
6814 | /* This function is a stepping stone between ipf_queueflush() and */ | | 6814 | /* This function is a stepping stone between ipf_queueflush() and */ |
6815 | /* nat_dlete(). It is used so we can provide a uniform interface via the */ | | 6815 | /* nat_dlete(). It is used so we can provide a uniform interface via the */ |
6816 | /* ipf_queueflush() function. Since the nat_delete() function returns void */ | | 6816 | /* ipf_queueflush() function. Since the nat_delete() function returns void */ |
6817 | /* we translate that to mean it always succeeds in deleting something. */ | | 6817 | /* we translate that to mean it always succeeds in deleting something. */ |
6818 | /* ------------------------------------------------------------------------ */ | | 6818 | /* ------------------------------------------------------------------------ */ |
6819 | static int | | 6819 | static int |
6820 | ipf_nat_flush_entry(ipf_main_softc_t *softc, void *entry) | | 6820 | ipf_nat_flush_entry(ipf_main_softc_t *softc, void *entry) |
6821 | { | | 6821 | { |
6822 | ipf_nat_delete(softc, entry, NL_FLUSH); | | 6822 | ipf_nat_delete(softc, entry, NL_FLUSH); |
6823 | return 0; | | 6823 | return 0; |
6824 | } | | 6824 | } |
6825 | | | 6825 | |
6826 | | | 6826 | |
6827 | /* ------------------------------------------------------------------------ */ | | 6827 | /* ------------------------------------------------------------------------ */ |
6828 | /* Function: ipf_nat_iterator */ | | 6828 | /* Function: ipf_nat_iterator */ |
6829 | /* Returns: int - 0 == ok, else error */ | | 6829 | /* Returns: int - 0 == ok, else error */ |
6830 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6830 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6831 | /* token(I) - pointer to ipftoken structure */ | | 6831 | /* token(I) - pointer to ipftoken structure */ |
6832 | /* itp(I) - pointer to ipfgeniter_t structure */ | | 6832 | /* itp(I) - pointer to ipfgeniter_t structure */ |
6833 | /* obj(I) - pointer to data description structure */ | | 6833 | /* obj(I) - pointer to data description structure */ |
6834 | /* */ | | 6834 | /* */ |
6835 | /* This function acts as a handler for the SIOCGENITER ioctls that use a */ | | 6835 | /* This function acts as a handler for the SIOCGENITER ioctls that use a */ |
6836 | /* generic structure to iterate through a list. There are three different */ | | 6836 | /* generic structure to iterate through a list. There are three different */ |
6837 | /* linked lists of NAT related information to go through: NAT rules, active */ | | 6837 | /* linked lists of NAT related information to go through: NAT rules, active */ |
6838 | /* NAT mappings and the NAT fragment cache. */ | | 6838 | /* NAT mappings and the NAT fragment cache. */ |
6839 | /* ------------------------------------------------------------------------ */ | | 6839 | /* ------------------------------------------------------------------------ */ |
6840 | static int | | 6840 | static int |
6841 | ipf_nat_iterator(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp, | | 6841 | ipf_nat_iterator(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp, |
6842 | ipfobj_t *obj) | | 6842 | ipfobj_t *obj) |
6843 | { | | 6843 | { |
6844 | int error; | | 6844 | int error; |
6845 | | | 6845 | |
6846 | if (itp->igi_data == NULL) { | | 6846 | if (itp->igi_data == NULL) { |
6847 | IPFERROR(60052); | | 6847 | IPFERROR(60052); |
6848 | return EFAULT; | | 6848 | return EFAULT; |
6849 | } | | 6849 | } |
6850 | | | 6850 | |
6851 | switch (itp->igi_type) | | 6851 | switch (itp->igi_type) |
6852 | { | | 6852 | { |
6853 | case IPFGENITER_HOSTMAP : | | 6853 | case IPFGENITER_HOSTMAP : |
6854 | case IPFGENITER_IPNAT : | | 6854 | case IPFGENITER_IPNAT : |
6855 | case IPFGENITER_NAT : | | 6855 | case IPFGENITER_NAT : |
6856 | error = ipf_nat_getnext(softc, token, itp, obj); | | 6856 | error = ipf_nat_getnext(softc, token, itp, obj); |
6857 | break; | | 6857 | break; |
6858 | | | 6858 | |
6859 | case IPFGENITER_NATFRAG : | | 6859 | case IPFGENITER_NATFRAG : |
6860 | error = ipf_frag_nat_next(softc, token, itp); | | 6860 | error = ipf_frag_nat_next(softc, token, itp); |
6861 | break; | | 6861 | break; |
6862 | default : | | 6862 | default : |
6863 | IPFERROR(60053); | | 6863 | IPFERROR(60053); |
6864 | error = EINVAL; | | 6864 | error = EINVAL; |
6865 | break; | | 6865 | break; |
6866 | } | | 6866 | } |
6867 | | | 6867 | |
6868 | return error; | | 6868 | return error; |
6869 | } | | 6869 | } |
6870 | | | 6870 | |
6871 | | | 6871 | |
6872 | /* ------------------------------------------------------------------------ */ | | 6872 | /* ------------------------------------------------------------------------ */ |
6873 | /* Function: ipf_nat_setpending */ | | 6873 | /* Function: ipf_nat_setpending */ |
6874 | /* Returns: Nil */ | | 6874 | /* Returns: Nil */ |
6875 | /* Parameters: softc(I) - pointer to soft context main structure */ | | 6875 | /* Parameters: softc(I) - pointer to soft context main structure */ |
6876 | /* nat(I) - pointer to NAT structure */ | | 6876 | /* nat(I) - pointer to NAT structure */ |
6877 | /* Locks: ipf_nat (read or write) */ | | 6877 | /* Locks: ipf_nat (read or write) */ |
6878 | /* */ | | 6878 | /* */ |
6879 | /* Put the NAT entry on to the pending queue - this queue has a very short */ | | 6879 | /* Put the NAT entry on to the pending queue - this queue has a very short */ |
6880 | /* lifetime where items are put that can't be deleted straight away because */ | | 6880 | /* lifetime where items are put that can't be deleted straight away because */ |
6881 | /* of locking issues but we want to delete them ASAP, anyway. In calling */ | | 6881 | /* of locking issues but we want to delete them ASAP, anyway. In calling */ |
6882 | /* this function, it is assumed that the owner (if there is one, as shown */ | | 6882 | /* this function, it is assumed that the owner (if there is one, as shown */ |
6883 | /* by nat_me) is no longer interested in it. */ | | 6883 | /* by nat_me) is no longer interested in it. */ |
6884 | /* ------------------------------------------------------------------------ */ | | 6884 | /* ------------------------------------------------------------------------ */ |
6885 | void | | 6885 | void |
6886 | ipf_nat_setpending(ipf_main_softc_t *softc, nat_t *nat) | | 6886 | ipf_nat_setpending(ipf_main_softc_t *softc, nat_t *nat) |
6887 | { | | 6887 | { |
6888 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 6888 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
6889 | ipftq_t *oifq; | | 6889 | ipftq_t *oifq; |
6890 | | | 6890 | |
6891 | oifq = nat->nat_tqe.tqe_ifq; | | 6891 | oifq = nat->nat_tqe.tqe_ifq; |
6892 | if (oifq != NULL) | | 6892 | if (oifq != NULL) |
6893 | ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, | | 6893 | ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, |
6894 | &softn->ipf_nat_pending); | | 6894 | &softn->ipf_nat_pending); |
6895 | else | | 6895 | else |
6896 | ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, | | 6896 | ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, |
6897 | &softn->ipf_nat_pending, nat); | | 6897 | &softn->ipf_nat_pending, nat); |
6898 | | | 6898 | |
6899 | if (nat->nat_me != NULL) { | | 6899 | if (nat->nat_me != NULL) { |
6900 | *nat->nat_me = NULL; | | 6900 | *nat->nat_me = NULL; |
6901 | nat->nat_me = NULL; | | 6901 | nat->nat_me = NULL; |
6902 | nat->nat_ref--; | | 6902 | nat->nat_ref--; |
6903 | ASSERT(nat->nat_ref >= 0); | | 6903 | ASSERT(nat->nat_ref >= 0); |
6904 | } | | 6904 | } |
6905 | } | | 6905 | } |
6906 | | | 6906 | |
6907 | | | 6907 | |
6908 | /* ------------------------------------------------------------------------ */ | | 6908 | /* ------------------------------------------------------------------------ */ |
6909 | /* Function: nat_newrewrite */ | | 6909 | /* Function: nat_newrewrite */ |
6910 | /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ | | 6910 | /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ |
6911 | /* allow rule to be moved if IPN_ROUNDR is set. */ | | 6911 | /* allow rule to be moved if IPN_ROUNDR is set. */ |
6912 | /* Parameters: fin(I) - pointer to packet information */ | | 6912 | /* Parameters: fin(I) - pointer to packet information */ |
6913 | /* nat(I) - pointer to NAT entry */ | | 6913 | /* nat(I) - pointer to NAT entry */ |
6914 | /* ni(I) - pointer to structure with misc. information needed */ | | 6914 | /* ni(I) - pointer to structure with misc. information needed */ |
6915 | /* to create new NAT entry. */ | | 6915 | /* to create new NAT entry. */ |
6916 | /* Write Lock: ipf_nat */ | | 6916 | /* Write Lock: ipf_nat */ |
6917 | /* */ | | 6917 | /* */ |
6918 | /* This function is responsible for setting up an active NAT session where */ | | 6918 | /* This function is responsible for setting up an active NAT session where */ |
6919 | /* we are changing both the source and destination parameters at the same */ | | 6919 | /* we are changing both the source and destination parameters at the same */ |
6920 | /* time. The loop in here works differently to elsewhere - each iteration */ | | 6920 | /* time. The loop in here works differently to elsewhere - each iteration */ |
6921 | /* is responsible for changing a single parameter that can be incremented. */ | | 6921 | /* is responsible for changing a single parameter that can be incremented. */ |
6922 | /* So one pass may increase the source IP#, next source port, next dest. IP#*/ | | 6922 | /* So one pass may increase the source IP#, next source port, next dest. IP#*/ |
6923 | /* and the last destination port for a total of 4 iterations to try each. */ | | 6923 | /* and the last destination port for a total of 4 iterations to try each. */ |
6924 | /* This is done to try and exhaustively use the translation space available.*/ | | 6924 | /* This is done to try and exhaustively use the translation space available.*/ |
6925 | /* ------------------------------------------------------------------------ */ | | 6925 | /* ------------------------------------------------------------------------ */ |
6926 | static int | | 6926 | static int |
6927 | ipf_nat_newrewrite(fr_info_t *fin, nat_t *nat, natinfo_t *nai) | | 6927 | ipf_nat_newrewrite(fr_info_t *fin, nat_t *nat, natinfo_t *nai) |
6928 | { | | 6928 | { |
6929 | int src_search = 1; | | 6929 | int src_search = 1; |
6930 | int dst_search = 1; | | 6930 | int dst_search = 1; |
6931 | fr_info_t frnat; | | 6931 | fr_info_t frnat; |
6932 | u_32_t flags; | | 6932 | u_32_t flags; |
6933 | u_short swap; | | 6933 | u_short swap; |
6934 | ipnat_t *np; | | 6934 | ipnat_t *np; |
6935 | nat_t *natl; | | 6935 | nat_t *natl; |
6936 | int l = 0; | | 6936 | int l = 0; |
6937 | int changed; | | 6937 | int changed; |
6938 | | | 6938 | |
6939 | natl = NULL; | | 6939 | natl = NULL; |
6940 | changed = -1; | | 6940 | changed = -1; |
6941 | np = nai->nai_np; | | 6941 | np = nai->nai_np; |
6942 | flags = nat->nat_flags; | | 6942 | flags = nat->nat_flags; |
6943 | bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); | | 6943 | bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); |
6944 | | | 6944 | |
6945 | nat->nat_hm = NULL; | | 6945 | nat->nat_hm = NULL; |
6946 | | | 6946 | |
6947 | do { | | 6947 | do { |
6948 | changed = -1; | | 6948 | changed = -1; |
6949 | /* TRACE (l, src_search, dst_search, np) */ | | 6949 | /* TRACE (l, src_search, dst_search, np) */ |
6950 | | | 6950 | |
6951 | if ((src_search == 0) && (np->in_spnext == 0) && | | 6951 | if ((src_search == 0) && (np->in_spnext == 0) && |
6952 | (dst_search == 0) && (np->in_dpnext == 0)) { | | 6952 | (dst_search == 0) && (np->in_dpnext == 0)) { |
6953 | if (l > 0) | | 6953 | if (l > 0) |
6954 | return -1; | | 6954 | return -1; |
6955 | } | | 6955 | } |
6956 | | | 6956 | |
6957 | /* | | 6957 | /* |
6958 | * Find a new source address | | 6958 | * Find a new source address |
6959 | */ | | 6959 | */ |
6960 | if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr, | | 6960 | if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr, |
6961 | &frnat.fin_saddr) == -1) { | | 6961 | &frnat.fin_saddr) == -1) { |
6962 | return -1; | | 6962 | return -1; |
6963 | } | | 6963 | } |
6964 | | | 6964 | |
6965 | if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) { | | 6965 | if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) { |
6966 | src_search = 0; | | 6966 | src_search = 0; |
6967 | if (np->in_stepnext == 0) | | 6967 | if (np->in_stepnext == 0) |
6968 | np->in_stepnext = 1; | | 6968 | np->in_stepnext = 1; |
6969 | | | 6969 | |
6970 | } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { | | 6970 | } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) { |
6971 | src_search = 0; | | 6971 | src_search = 0; |
6972 | if (np->in_stepnext == 0) | | 6972 | if (np->in_stepnext == 0) |
6973 | np->in_stepnext = 1; | | 6973 | np->in_stepnext = 1; |
6974 | | | 6974 | |
6975 | } else if (np->in_nsrcmsk == 0xffffffff) { | | 6975 | } else if (np->in_nsrcmsk == 0xffffffff) { |
6976 | src_search = 0; | | 6976 | src_search = 0; |
6977 | if (np->in_stepnext == 0) | | 6977 | if (np->in_stepnext == 0) |
6978 | np->in_stepnext = 1; | | 6978 | np->in_stepnext = 1; |
6979 | | | 6979 | |
6980 | } else if (np->in_nsrcmsk != 0xffffffff) { | | 6980 | } else if (np->in_nsrcmsk != 0xffffffff) { |
6981 | if (np->in_stepnext == 0 && changed == -1) { | | 6981 | if (np->in_stepnext == 0 && changed == -1) { |
6982 | np->in_snip++; | | 6982 | np->in_snip++; |
6983 | np->in_stepnext++; | | 6983 | np->in_stepnext++; |
6984 | changed = 0; | | 6984 | changed = 0; |
6985 | } | | 6985 | } |
6986 | } | | 6986 | } |
6987 | | | 6987 | |
6988 | if ((flags & IPN_TCPUDPICMP) != 0) { | | 6988 | if ((flags & IPN_TCPUDPICMP) != 0) { |
6989 | if (np->in_spnext != 0) | | 6989 | if (np->in_spnext != 0) |
6990 | frnat.fin_data[0] = np->in_spnext; | | 6990 | frnat.fin_data[0] = np->in_spnext; |
6991 | | | 6991 | |
6992 | /* | | 6992 | /* |
6993 | * Standard port translation. Select next port. | | 6993 | * Standard port translation. Select next port. |
6994 | */ | | 6994 | */ |
6995 | if ((flags & IPN_FIXEDSPORT) != 0) { | | 6995 | if ((flags & IPN_FIXEDSPORT) != 0) { |
6996 | np->in_stepnext = 2; | | 6996 | np->in_stepnext = 2; |
6997 | } else if ((np->in_stepnext == 1) && | | 6997 | } else if ((np->in_stepnext == 1) && |
6998 | (changed == -1) && (natl != NULL)) { | | 6998 | (changed == -1) && (natl != NULL)) { |
6999 | np->in_spnext++; | | 6999 | np->in_spnext++; |
7000 | np->in_stepnext++; | | 7000 | np->in_stepnext++; |
7001 | changed = 1; | | 7001 | changed = 1; |
7002 | if (np->in_spnext > np->in_spmax) | | 7002 | if (np->in_spnext > np->in_spmax) |
7003 | np->in_spnext = np->in_spmin; | | 7003 | np->in_spnext = np->in_spmin; |
7004 | } | | 7004 | } |
7005 | } else { | | 7005 | } else { |
7006 | np->in_stepnext = 2; | | 7006 | np->in_stepnext = 2; |
7007 | } | | 7007 | } |
7008 | np->in_stepnext &= 0x3; | | 7008 | np->in_stepnext &= 0x3; |
7009 | | | 7009 | |
7010 | /* | | 7010 | /* |
7011 | * Find a new destination address | | 7011 | * Find a new destination address |
7012 | */ | | 7012 | */ |
7013 | /* TRACE (fin, np, l, frnat) */ | | 7013 | /* TRACE (fin, np, l, frnat) */ |
7014 | | | 7014 | |
7015 | if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr, | | 7015 | if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr, |
7016 | &frnat.fin_daddr) == -1) | | 7016 | &frnat.fin_daddr) == -1) |
7017 | return -1; | | 7017 | return -1; |
7018 | if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { | | 7018 | if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) { |
7019 | dst_search = 0; | | 7019 | dst_search = 0; |
7020 | if (np->in_stepnext == 2) | | 7020 | if (np->in_stepnext == 2) |
7021 | np->in_stepnext = 3; | | 7021 | np->in_stepnext = 3; |
7022 | | | 7022 | |
7023 | } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) { | | 7023 | } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) { |
7024 | dst_search = 0; | | 7024 | dst_search = 0; |
7025 | if (np->in_stepnext == 2) | | 7025 | if (np->in_stepnext == 2) |
7026 | np->in_stepnext = 3; | | 7026 | np->in_stepnext = 3; |
7027 | | | 7027 | |
7028 | } else if (np->in_ndstmsk == 0xffffffff) { | | 7028 | } else if (np->in_ndstmsk == 0xffffffff) { |
7029 | dst_search = 0; | | 7029 | dst_search = 0; |
7030 | if (np->in_stepnext == 2) | | 7030 | if (np->in_stepnext == 2) |
7031 | np->in_stepnext = 3; | | 7031 | np->in_stepnext = 3; |
7032 | | | 7032 | |
7033 | } else if (np->in_ndstmsk != 0xffffffff) { | | 7033 | } else if (np->in_ndstmsk != 0xffffffff) { |
7034 | if ((np->in_stepnext == 2) && (changed == -1) && | | 7034 | if ((np->in_stepnext == 2) && (changed == -1) && |
7035 | (natl != NULL)) { | | 7035 | (natl != NULL)) { |
7036 | changed = 2; | | 7036 | changed = 2; |
7037 | np->in_stepnext++; | | 7037 | np->in_stepnext++; |
7038 | np->in_dnip++; | | 7038 | np->in_dnip++; |
7039 | } | | 7039 | } |
7040 | } | | 7040 | } |
7041 | | | 7041 | |
7042 | if ((flags & IPN_TCPUDPICMP) != 0) { | | 7042 | if ((flags & IPN_TCPUDPICMP) != 0) { |
7043 | if (np->in_dpnext != 0) | | 7043 | if (np->in_dpnext != 0) |
7044 | frnat.fin_data[1] = np->in_dpnext; | | 7044 | frnat.fin_data[1] = np->in_dpnext; |
7045 | | | 7045 | |
7046 | /* | | 7046 | /* |
7047 | * Standard port translation. Select next port. | | 7047 | * Standard port translation. Select next port. |
7048 | */ | | 7048 | */ |
7049 | if ((flags & IPN_FIXEDDPORT) != 0) { | | 7049 | if ((flags & IPN_FIXEDDPORT) != 0) { |
7050 | np->in_stepnext = 0; | | 7050 | np->in_stepnext = 0; |
7051 | } else if (np->in_stepnext == 3 && changed == -1) { | | 7051 | } else if (np->in_stepnext == 3 && changed == -1) { |
7052 | np->in_dpnext++; | | 7052 | np->in_dpnext++; |
7053 | np->in_stepnext++; | | 7053 | np->in_stepnext++; |
7054 | changed = 3; | | 7054 | changed = 3; |
7055 | if (np->in_dpnext > np->in_dpmax) | | 7055 | if (np->in_dpnext > np->in_dpmax) |
7056 | np->in_dpnext = np->in_dpmin; | | 7056 | np->in_dpnext = np->in_dpmin; |
7057 | } | | 7057 | } |
7058 | } else { | | 7058 | } else { |
7059 | if (np->in_stepnext == 3) | | 7059 | if (np->in_stepnext == 3) |
7060 | np->in_stepnext = 0; | | 7060 | np->in_stepnext = 0; |
7061 | } | | 7061 | } |
7062 | | | 7062 | |
7063 | /* TRACE (frnat) */ | | 7063 | /* TRACE (frnat) */ |
7064 | | | 7064 | |
7065 | /* | | 7065 | /* |
7066 | * Here we do a lookup of the connection as seen from | | 7066 | * Here we do a lookup of the connection as seen from |
7067 | * the outside. If an IP# pair already exists, try | | 7067 | * the outside. If an IP# pair already exists, try |
7068 | * again. So if you have A->B becomes C->B, you can | | 7068 | * again. So if you have A->B becomes C->B, you can |
7069 | * also have D->E become C->E but not D->B causing | | 7069 | * also have D->E become C->E but not D->B causing |
7070 | * another C->B. Also take protocol and ports into | | 7070 | * another C->B. Also take protocol and ports into |
7071 | * account when determining whether a pre-existing | | 7071 | * account when determining whether a pre-existing |
7072 | * NAT setup will cause an external conflict where | | 7072 | * NAT setup will cause an external conflict where |
7073 | * this is appropriate. | | 7073 | * this is appropriate. |
7074 | * | | 7074 | * |
7075 | * fin_data[] is swapped around because we are doing a | | 7075 | * fin_data[] is swapped around because we are doing a |
7076 | * lookup of the packet is if it were moving in the opposite | | 7076 | * lookup of the packet is if it were moving in the opposite |
7077 | * direction of the one we are working with now. | | 7077 | * direction of the one we are working with now. |
7078 | */ | | 7078 | */ |
7079 | if (flags & IPN_TCPUDP) { | | 7079 | if (flags & IPN_TCPUDP) { |
7080 | swap = frnat.fin_data[0]; | | 7080 | swap = frnat.fin_data[0]; |
7081 | frnat.fin_data[0] = frnat.fin_data[1]; | | 7081 | frnat.fin_data[0] = frnat.fin_data[1]; |
7082 | frnat.fin_data[1] = swap; | | 7082 | frnat.fin_data[1] = swap; |
7083 | } | | 7083 | } |
7084 | if (fin->fin_out == 1) { | | 7084 | if (fin->fin_out == 1) { |
7085 | natl = ipf_nat_inlookup(&frnat, | | 7085 | natl = ipf_nat_inlookup(&frnat, |
7086 | flags & ~(SI_WILDP|NAT_SEARCH), | | 7086 | flags & ~(SI_WILDP|NAT_SEARCH), |
7087 | (u_int)frnat.fin_p, | | 7087 | (u_int)frnat.fin_p, |
7088 | frnat.fin_dst, frnat.fin_src); | | 7088 | frnat.fin_dst, frnat.fin_src); |
7089 | | | 7089 | |
7090 | } else { | | 7090 | } else { |
7091 | natl = ipf_nat_outlookup(&frnat, | | 7091 | natl = ipf_nat_outlookup(&frnat, |
7092 | flags & ~(SI_WILDP|NAT_SEARCH), | | 7092 | flags & ~(SI_WILDP|NAT_SEARCH), |
7093 | (u_int)frnat.fin_p, | | 7093 | (u_int)frnat.fin_p, |
7094 | frnat.fin_dst, frnat.fin_src); | | 7094 | frnat.fin_dst, frnat.fin_src); |
7095 | } | | 7095 | } |
7096 | if (flags & IPN_TCPUDP) { | | 7096 | if (flags & IPN_TCPUDP) { |
7097 | swap = frnat.fin_data[0]; | | 7097 | swap = frnat.fin_data[0]; |
7098 | frnat.fin_data[0] = frnat.fin_data[1]; | | 7098 | frnat.fin_data[0] = frnat.fin_data[1]; |
7099 | frnat.fin_data[1] = swap; | | 7099 | frnat.fin_data[1] = swap; |
7100 | } | | 7100 | } |
7101 | | | 7101 | |
7102 | /* TRACE natl, in_stepnext, l */ | | 7102 | /* TRACE natl, in_stepnext, l */ |
7103 | | | 7103 | |
7104 | if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */ | | 7104 | if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */ |
7105 | return -1; | | 7105 | return -1; |
7106 | | | 7106 | |
7107 | np->in_stepnext &= 0x3; | | 7107 | np->in_stepnext &= 0x3; |
7108 | | | 7108 | |
7109 | l++; | | 7109 | l++; |
7110 | changed = -1; | | 7110 | changed = -1; |
7111 | } while (natl != NULL); | | 7111 | } while (natl != NULL); |
7112 | | | 7112 | |
7113 | nat->nat_osrcip = fin->fin_src; | | 7113 | nat->nat_osrcip = fin->fin_src; |
7114 | nat->nat_odstip = fin->fin_dst; | | 7114 | nat->nat_odstip = fin->fin_dst; |
7115 | nat->nat_nsrcip = frnat.fin_src; | | 7115 | nat->nat_nsrcip = frnat.fin_src; |
7116 | nat->nat_ndstip = frnat.fin_dst; | | 7116 | nat->nat_ndstip = frnat.fin_dst; |
7117 | | | 7117 | |
7118 | if ((flags & IPN_TCPUDP) != 0) { | | 7118 | if ((flags & IPN_TCPUDP) != 0) { |
7119 | nat->nat_osport = htons(fin->fin_data[0]); | | 7119 | nat->nat_osport = htons(fin->fin_data[0]); |
7120 | nat->nat_odport = htons(fin->fin_data[1]); | | 7120 | nat->nat_odport = htons(fin->fin_data[1]); |
7121 | nat->nat_nsport = htons(frnat.fin_data[0]); | | 7121 | nat->nat_nsport = htons(frnat.fin_data[0]); |
7122 | nat->nat_ndport = htons(frnat.fin_data[1]); | | 7122 | nat->nat_ndport = htons(frnat.fin_data[1]); |
7123 | } else if ((flags & IPN_ICMPQUERY) != 0) { | | 7123 | } else if ((flags & IPN_ICMPQUERY) != 0) { |
7124 | nat->nat_oicmpid = fin->fin_data[1]; | | 7124 | nat->nat_oicmpid = fin->fin_data[1]; |
7125 | nat->nat_nicmpid = frnat.fin_data[1]; | | 7125 | nat->nat_nicmpid = frnat.fin_data[1]; |
7126 | } | | 7126 | } |
7127 | | | 7127 | |
7128 | return 0; | | 7128 | return 0; |
7129 | } | | 7129 | } |
7130 | | | 7130 | |
7131 | | | 7131 | |
7132 | /* ------------------------------------------------------------------------ */ | | 7132 | /* ------------------------------------------------------------------------ */ |
7133 | /* Function: nat_newdivert */ | | 7133 | /* Function: nat_newdivert */ |
7134 | /* Returns: int - -1 == error, 0 == success */ | | 7134 | /* Returns: int - -1 == error, 0 == success */ |
7135 | /* Parameters: fin(I) - pointer to packet information */ | | 7135 | /* Parameters: fin(I) - pointer to packet information */ |
7136 | /* nat(I) - pointer to NAT entry */ | | 7136 | /* nat(I) - pointer to NAT entry */ |
7137 | /* ni(I) - pointer to structure with misc. information needed */ | | 7137 | /* ni(I) - pointer to structure with misc. information needed */ |
7138 | /* to create new NAT entry. */ | | 7138 | /* to create new NAT entry. */ |
7139 | /* Write Lock: ipf_nat */ | | 7139 | /* Write Lock: ipf_nat */ |
7140 | /* */ | | 7140 | /* */ |
7141 | /* Create a new NAT divert session as defined by the NAT rule. This is */ | | 7141 | /* Create a new NAT divert session as defined by the NAT rule. This is */ |
7142 | /* somewhat different to other NAT session creation routines because we */ | | 7142 | /* somewhat different to other NAT session creation routines because we */ |
7143 | /* do not iterate through either port numbers or IP addresses, searching */ | | 7143 | /* do not iterate through either port numbers or IP addresses, searching */ |
7144 | /* for a unique mapping, however, a complimentary duplicate check is made. */ | | 7144 | /* for a unique mapping, however, a complimentary duplicate check is made. */ |
7145 | /* ------------------------------------------------------------------------ */ | | 7145 | /* ------------------------------------------------------------------------ */ |
7146 | static int | | 7146 | static int |
7147 | ipf_nat_newdivert(fr_info_t *fin, nat_t *nat, natinfo_t *nai) | | 7147 | ipf_nat_newdivert(fr_info_t *fin, nat_t *nat, natinfo_t *nai) |
7148 | { | | 7148 | { |
7149 | ipf_main_softc_t *softc = fin->fin_main_soft; | | 7149 | ipf_main_softc_t *softc = fin->fin_main_soft; |
7150 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; | | 7150 | ipf_nat_softc_t *softn = softc->ipf_nat_soft; |
7151 | fr_info_t frnat; | | 7151 | fr_info_t frnat; |
7152 | ipnat_t *np; | | 7152 | ipnat_t *np; |
7153 | nat_t *natl; | | 7153 | nat_t *natl; |
7154 | int p; | | 7154 | int p; |
7155 | | | 7155 | |
7156 | np = nai->nai_np; | | 7156 | np = nai->nai_np; |
7157 | bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); | | 7157 | bcopy((char *)fin, (char *)&frnat, sizeof(*fin)); |
7158 | | | 7158 | |
7159 | nat->nat_pr[0] = 0; | | 7159 | nat->nat_pr[0] = 0; |
7160 | nat->nat_osrcaddr = fin->fin_saddr; | | 7160 | nat->nat_osrcaddr = fin->fin_saddr; |
7161 | nat->nat_odstaddr = fin->fin_daddr; | | 7161 | nat->nat_odstaddr = fin->fin_daddr; |
7162 | frnat.fin_saddr = htonl(np->in_snip); | | 7162 | frnat.fin_saddr = htonl(np->in_snip); |
7163 | frnat.fin_daddr = htonl(np->in_dnip); | | 7163 | frnat.fin_daddr = htonl(np->in_dnip); |
7164 | if ((nat->nat_flags & IPN_TCPUDP) != 0) { | | 7164 | if ((nat->nat_flags & IPN_TCPUDP) != 0) { |
7165 | nat->nat_osport = htons(fin->fin_data[0]); | | 7165 | nat->nat_osport = htons(fin->fin_data[0]); |
7166 | nat->nat_odport = htons(fin->fin_data[1]); | | 7166 | nat->nat_odport = htons(fin->fin_data[1]); |
7167 | } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { | | 7167 | } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) { |
7168 | nat->nat_oicmpid = fin->fin_data[1]; | | 7168 | nat->nat_oicmpid = fin->fin_data[1]; |
7169 | } | | 7169 | } |
7170 | | | 7170 | |
7171 | if (np->in_redir & NAT_DIVERTUDP) { | | 7171 | if (np->in_redir & NAT_DIVERTUDP) { |
7172 | frnat.fin_data[0] = np->in_spnext; | | 7172 | frnat.fin_data[0] = np->in_spnext; |
7173 | frnat.fin_data[1] = np->in_dpnext; | | 7173 | frnat.fin_data[1] = np->in_dpnext; |
7174 | frnat.fin_flx |= FI_TCPUDP; | | 7174 | frnat.fin_flx |= FI_TCPUDP; |
7175 | p = IPPROTO_UDP; | | 7175 | p = IPPROTO_UDP; |
7176 | } else { | | 7176 | } else { |
7177 | frnat.fin_flx &= ~FI_TCPUDP; | | 7177 | frnat.fin_flx &= ~FI_TCPUDP; |
7178 | p = IPPROTO_IPIP; | | 7178 | p = IPPROTO_IPIP; |
7179 | } | | 7179 | } |
7180 | | | 7180 | |