1 | /* $NetBSD: fil.c,v 1.19 2016/08/05 09:06:52 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (C) 2012 by Darren Reed. |
5 | * |
6 | * See the IPFILTER.LICENCE file for details on licencing. |
7 | * |
8 | * Id: fil.c,v 1.1.1.2 2012/07/22 13:45:07 darrenr Exp $ |
9 | * |
10 | */ |
11 | #if defined(KERNEL) || defined(_KERNEL) |
12 | # undef KERNEL |
13 | # undef _KERNEL |
14 | # define KERNEL 1 |
15 | # define _KERNEL 1 |
16 | #endif |
17 | #include <sys/errno.h> |
18 | #include <sys/types.h> |
19 | #include <sys/param.h> |
20 | #include <sys/time.h> |
21 | #if defined(_KERNEL) && defined(__FreeBSD_version) && \ |
22 | (__FreeBSD_version >= 220000) |
23 | # if (__FreeBSD_version >= 400000) |
24 | # if !defined(IPFILTER_LKM) |
25 | # include "opt_inet6.h" |
26 | # endif |
27 | # if (__FreeBSD_version == 400019) |
28 | # define CSUM_DELAY_DATA |
29 | # endif |
30 | # endif |
31 | # include <sys/filio.h> |
32 | #else |
33 | # include <sys/ioctl.h> |
34 | #endif |
35 | #if (defined(__SVR4) || defined(__svr4__)) && defined(sun) |
36 | # include <sys/filio.h> |
37 | #endif |
38 | #if !defined(_AIX51) |
39 | # include <sys/fcntl.h> |
40 | #endif |
41 | #if defined(_KERNEL) |
42 | # include <sys/systm.h> |
43 | # include <sys/file.h> |
44 | #else |
45 | # include <stdio.h> |
46 | # include <string.h> |
47 | # include <stdlib.h> |
48 | # include <stddef.h> |
49 | # include <sys/file.h> |
50 | # define _KERNEL |
51 | # ifdef __OpenBSD__ |
52 | struct file; |
53 | # endif |
54 | # include <sys/uio.h> |
55 | # undef _KERNEL |
56 | #endif |
57 | #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ |
58 | !defined(linux) |
59 | # include <sys/mbuf.h> |
60 | #else |
61 | # if !defined(linux) |
62 | # include <sys/byteorder.h> |
63 | # endif |
64 | # if (SOLARIS2 < 5) && defined(sun) |
65 | # include <sys/dditypes.h> |
66 | # endif |
67 | #endif |
68 | #ifdef __hpux |
69 | # define _NET_ROUTE_INCLUDED |
70 | #endif |
71 | #if !defined(linux) |
72 | # include <sys/protosw.h> |
73 | #endif |
74 | #include <sys/socket.h> |
75 | #include <net/if.h> |
76 | #ifdef sun |
77 | # include <net/af.h> |
78 | #endif |
79 | #include <netinet/in.h> |
80 | #include <netinet/in_systm.h> |
81 | #include <netinet/ip.h> |
82 | #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ |
83 | # include <sys/hashing.h> |
84 | # include <netinet/in_var.h> |
85 | #endif |
86 | #include <netinet/tcp.h> |
87 | #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL) |
88 | # include <netinet/udp.h> |
89 | # include <netinet/ip_icmp.h> |
90 | #endif |
91 | #ifdef __hpux |
92 | # undef _NET_ROUTE_INCLUDED |
93 | #endif |
94 | #ifdef __osf__ |
95 | # undef _RADIX_H_ |
96 | #endif |
97 | #include "netinet/ip_compat.h" |
98 | #ifdef USE_INET6 |
99 | # include <netinet/icmp6.h> |
100 | # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) |
101 | # include <netinet6/in6_var.h> |
102 | # endif |
103 | #endif |
104 | #include "netinet/ip_fil.h" |
105 | #include "netinet/ip_nat.h" |
106 | #include "netinet/ip_frag.h" |
107 | #include "netinet/ip_state.h" |
108 | #include "netinet/ip_proxy.h" |
109 | #include "netinet/ip_auth.h" |
110 | #ifdef IPFILTER_SCAN |
111 | # include "netinet/ip_scan.h" |
112 | #endif |
113 | #include "netinet/ip_sync.h" |
114 | #include "netinet/ip_lookup.h" |
115 | #include "netinet/ip_pool.h" |
116 | #include "netinet/ip_htable.h" |
117 | #ifdef IPFILTER_COMPILED |
118 | # include "netinet/ip_rules.h" |
119 | #endif |
120 | #if defined(IPFILTER_BPF) && defined(_KERNEL) |
121 | # include <net/bpf.h> |
122 | #endif |
123 | #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) |
124 | # include <sys/malloc.h> |
125 | #endif |
126 | #include "netinet/ipl.h" |
127 | |
128 | #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) |
129 | # include <sys/callout.h> |
130 | extern struct callout ipf_slowtimer_ch; |
131 | #endif |
132 | #if defined(__OpenBSD__) |
133 | # include <sys/timeout.h> |
134 | extern struct timeout ipf_slowtimer_ch; |
135 | #endif |
136 | /* END OF INCLUDES */ |
137 | |
138 | #if !defined(lint) |
139 | #if defined(__NetBSD__) |
140 | #include <sys/cdefs.h> |
141 | __KERNEL_RCSID(0, "$NetBSD: fil.c,v 1.19 2016/08/05 09:06:52 christos Exp $" ); |
142 | #else |
143 | static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed" ; |
144 | static const char rcsid[] = "@(#)Id: fil.c,v 1.1.1.2 2012/07/22 13:45:07 darrenr Exp $" ; |
145 | #endif |
146 | #endif |
147 | |
148 | #ifndef _KERNEL |
149 | # include "ipf.h" |
150 | # include "ipt.h" |
151 | extern int opts; |
152 | extern int blockreason; |
153 | #endif /* _KERNEL */ |
154 | |
155 | #define LBUMP(x) softc->x++ |
156 | #define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0) |
157 | |
158 | static INLINE int ipf_check_ipf(fr_info_t *, frentry_t *, int); |
159 | static u_32_t ipf_checkcipso(fr_info_t *, u_char *, int); |
160 | static u_32_t ipf_checkripso(u_char *); |
161 | static u_32_t ipf_decaps(fr_info_t *, u_32_t, int); |
162 | #ifdef IPFILTER_LOG |
163 | static frentry_t *ipf_dolog(fr_info_t *, u_32_t *); |
164 | #endif |
165 | static int ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **); |
166 | static int ipf_flush_groups(ipf_main_softc_t *, frgroup_t **, int); |
167 | static ipfunc_t ipf_findfunc(ipfunc_t); |
168 | static void *ipf_findlookup(ipf_main_softc_t *, int, frentry_t *, |
169 | i6addr_t *, i6addr_t *); |
170 | static frentry_t *ipf_firewall(fr_info_t *, u_32_t *); |
171 | static int ipf_fr_matcharray(fr_info_t *, int *); |
172 | static int ipf_frruleiter(ipf_main_softc_t *, void *, int, void *); |
173 | static void ipf_funcfini(ipf_main_softc_t *, frentry_t *);; |
174 | static int ipf_funcinit(ipf_main_softc_t *, frentry_t *); |
175 | static int ipf_geniter(ipf_main_softc_t *, ipftoken_t *, |
176 | ipfgeniter_t *); |
177 | static void ipf_getstat(ipf_main_softc_t *, |
178 | struct friostat *, int); |
179 | static int ipf_group_flush(ipf_main_softc_t *, frgroup_t *); |
180 | static void ipf_group_free(frgroup_t *); |
181 | static int ipf_grpmapfini(struct ipf_main_softc_s *, frentry_t *); |
182 | static int ipf_grpmapinit(struct ipf_main_softc_s *, frentry_t *); |
183 | static frentry_t *ipf_nextrule(ipf_main_softc_t *, int, int, |
184 | frentry_t *, int); |
185 | static int ipf_portcheck(frpcmp_t *, u_32_t); |
186 | static INLINE int ipf_pr_ah(fr_info_t *); |
187 | static INLINE void ipf_pr_esp(fr_info_t *); |
188 | static INLINE void ipf_pr_gre(fr_info_t *); |
189 | static INLINE void ipf_pr_udp(fr_info_t *); |
190 | static INLINE void ipf_pr_tcp(fr_info_t *); |
191 | static INLINE void ipf_pr_icmp(fr_info_t *); |
192 | static INLINE void ipf_pr_ipv4hdr(fr_info_t *); |
193 | static INLINE void ipf_pr_short(fr_info_t *, int); |
194 | static INLINE int ipf_pr_tcpcommon(fr_info_t *); |
195 | static INLINE int ipf_pr_udpcommon(fr_info_t *); |
196 | static void ipf_rule_delete(ipf_main_softc_t *, frentry_t *f, |
197 | int, int); |
198 | static void ipf_rule_expire_insert(ipf_main_softc_t *, |
199 | frentry_t *, int); |
200 | static int ipf_synclist(ipf_main_softc_t *, frentry_t *, void *); |
201 | static void ipf_token_flush(ipf_main_softc_t *); |
202 | static void ipf_token_unlink(ipf_main_softc_t *, ipftoken_t *); |
203 | static ipftuneable_t *ipf_tune_findbyname(ipftuneable_t *, const char *); |
204 | static ipftuneable_t *ipf_tune_findbycookie(ipftuneable_t **, void *, |
205 | void **); |
206 | static int ipf_updateipid(fr_info_t *); |
207 | static int ipf_settimeout(struct ipf_main_softc_s *, |
208 | struct ipftuneable *, ipftuneval_t *); |
209 | |
210 | |
211 | /* |
212 | * bit values for identifying presence of individual IP options |
213 | * All of these tables should be ordered by increasing key value on the left |
214 | * hand side to allow for binary searching of the array and include a trailer |
215 | * with a 0 for the bitmask for linear searches to easily find the end with. |
216 | */ |
217 | static const struct optlist ipopts[20] = { |
218 | { IPOPT_NOP, 0x000001 }, |
219 | { IPOPT_RR, 0x000002 }, |
220 | { IPOPT_ZSU, 0x000004 }, |
221 | { IPOPT_MTUP, 0x000008 }, |
222 | { IPOPT_MTUR, 0x000010 }, |
223 | { IPOPT_ENCODE, 0x000020 }, |
224 | { IPOPT_TS, 0x000040 }, |
225 | { IPOPT_TR, 0x000080 }, |
226 | { IPOPT_SECURITY, 0x000100 }, |
227 | { IPOPT_LSRR, 0x000200 }, |
228 | { IPOPT_E_SEC, 0x000400 }, |
229 | { IPOPT_CIPSO, 0x000800 }, |
230 | { IPOPT_SATID, 0x001000 }, |
231 | { IPOPT_SSRR, 0x002000 }, |
232 | { IPOPT_ADDEXT, 0x004000 }, |
233 | { IPOPT_VISA, 0x008000 }, |
234 | { IPOPT_IMITD, 0x010000 }, |
235 | { IPOPT_EIP, 0x020000 }, |
236 | { IPOPT_FINN, 0x040000 }, |
237 | { 0, 0x000000 } |
238 | }; |
239 | |
240 | #ifdef USE_INET6 |
241 | static const struct optlist ip6exthdr[] = { |
242 | { IPPROTO_HOPOPTS, 0x000001 }, |
243 | { IPPROTO_IPV6, 0x000002 }, |
244 | { IPPROTO_ROUTING, 0x000004 }, |
245 | { IPPROTO_FRAGMENT, 0x000008 }, |
246 | { IPPROTO_ESP, 0x000010 }, |
247 | { IPPROTO_AH, 0x000020 }, |
248 | { IPPROTO_NONE, 0x000040 }, |
249 | { IPPROTO_DSTOPTS, 0x000080 }, |
250 | { IPPROTO_MOBILITY, 0x000100 }, |
251 | { 0, 0 } |
252 | }; |
253 | #endif |
254 | |
255 | /* |
256 | * bit values for identifying presence of individual IP security options |
257 | */ |
258 | static const struct optlist secopt[8] = { |
259 | { IPSO_CLASS_RES4, 0x01 }, |
260 | { IPSO_CLASS_TOPS, 0x02 }, |
261 | { IPSO_CLASS_SECR, 0x04 }, |
262 | { IPSO_CLASS_RES3, 0x08 }, |
263 | { IPSO_CLASS_CONF, 0x10 }, |
264 | { IPSO_CLASS_UNCL, 0x20 }, |
265 | { IPSO_CLASS_RES2, 0x40 }, |
266 | { IPSO_CLASS_RES1, 0x80 } |
267 | }; |
268 | |
269 | char ipfilter_version[] = IPL_VERSION; |
270 | |
271 | int ipf_features = 0 |
272 | #ifdef IPFILTER_LKM |
273 | | IPF_FEAT_LKM |
274 | #endif |
275 | #ifdef IPFILTER_LOG |
276 | | IPF_FEAT_LOG |
277 | #endif |
278 | | IPF_FEAT_LOOKUP |
279 | #ifdef IPFILTER_BPF |
280 | | IPF_FEAT_BPF |
281 | #endif |
282 | #ifdef IPFILTER_COMPILED |
283 | | IPF_FEAT_COMPILED |
284 | #endif |
285 | #ifdef IPFILTER_CKSUM |
286 | | IPF_FEAT_CKSUM |
287 | #endif |
288 | | IPF_FEAT_SYNC |
289 | #ifdef IPFILTER_SCAN |
290 | | IPF_FEAT_SCAN |
291 | #endif |
292 | #ifdef USE_INET6 |
293 | | IPF_FEAT_IPV6 |
294 | #endif |
295 | ; |
296 | |
297 | |
298 | /* |
299 | * Table of functions available for use with call rules. |
300 | */ |
301 | static ipfunc_resolve_t ipf_availfuncs[] = { |
302 | { "srcgrpmap" , ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini }, |
303 | { "dstgrpmap" , ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini }, |
304 | { "" , NULL, NULL, NULL } |
305 | }; |
306 | |
307 | static ipftuneable_t ipf_main_tuneables[] = { |
308 | { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) }, |
309 | "ipf_flags" , 0, 0xffffffff, |
310 | stsizeof(ipf_main_softc_t, ipf_flags), |
311 | 0, NULL, NULL }, |
312 | { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) }, |
313 | "active" , 0, 0, |
314 | stsizeof(ipf_main_softc_t, ipf_active), |
315 | IPFT_RDONLY, NULL, NULL }, |
316 | { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) }, |
317 | "control_forwarding" , 0, 1, |
318 | stsizeof(ipf_main_softc_t, ipf_control_forwarding), |
319 | 0, NULL, NULL }, |
320 | { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) }, |
321 | "update_ipid" , 0, 1, |
322 | stsizeof(ipf_main_softc_t, ipf_update_ipid), |
323 | 0, NULL, NULL }, |
324 | { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) }, |
325 | "chksrc" , 0, 1, |
326 | stsizeof(ipf_main_softc_t, ipf_chksrc), |
327 | 0, NULL, NULL }, |
328 | { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) }, |
329 | "min_ttl" , 0, 1, |
330 | stsizeof(ipf_main_softc_t, ipf_minttl), |
331 | 0, NULL, NULL }, |
332 | { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) }, |
333 | "icmp_minfragmtu" , 0, 1, |
334 | stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu), |
335 | 0, NULL, NULL }, |
336 | { { (void *)offsetof(ipf_main_softc_t, ipf_pass) }, |
337 | "default_pass" , 0, 0xffffffff, |
338 | stsizeof(ipf_main_softc_t, ipf_pass), |
339 | 0, NULL, NULL }, |
340 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) }, |
341 | "tcp_idle_timeout" , 1, 0x7fffffff, |
342 | stsizeof(ipf_main_softc_t, ipf_tcpidletimeout), |
343 | 0, NULL, ipf_settimeout }, |
344 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) }, |
345 | "tcp_close_wait" , 1, 0x7fffffff, |
346 | stsizeof(ipf_main_softc_t, ipf_tcpclosewait), |
347 | 0, NULL, ipf_settimeout }, |
348 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) }, |
349 | "tcp_last_ack" , 1, 0x7fffffff, |
350 | stsizeof(ipf_main_softc_t, ipf_tcplastack), |
351 | 0, NULL, ipf_settimeout }, |
352 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) }, |
353 | "tcp_timeout" , 1, 0x7fffffff, |
354 | stsizeof(ipf_main_softc_t, ipf_tcptimeout), |
355 | 0, NULL, ipf_settimeout }, |
356 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) }, |
357 | "tcp_syn_sent" , 1, 0x7fffffff, |
358 | stsizeof(ipf_main_softc_t, ipf_tcpsynsent), |
359 | 0, NULL, ipf_settimeout }, |
360 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) }, |
361 | "tcp_syn_received" , 1, 0x7fffffff, |
362 | stsizeof(ipf_main_softc_t, ipf_tcpsynrecv), |
363 | 0, NULL, ipf_settimeout }, |
364 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) }, |
365 | "tcp_closed" , 1, 0x7fffffff, |
366 | stsizeof(ipf_main_softc_t, ipf_tcpclosed), |
367 | 0, NULL, ipf_settimeout }, |
368 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) }, |
369 | "tcp_half_closed" , 1, 0x7fffffff, |
370 | stsizeof(ipf_main_softc_t, ipf_tcphalfclosed), |
371 | 0, NULL, ipf_settimeout }, |
372 | { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) }, |
373 | "tcp_time_wait" , 1, 0x7fffffff, |
374 | stsizeof(ipf_main_softc_t, ipf_tcptimewait), |
375 | 0, NULL, ipf_settimeout }, |
376 | { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) }, |
377 | "udp_timeout" , 1, 0x7fffffff, |
378 | stsizeof(ipf_main_softc_t, ipf_udptimeout), |
379 | 0, NULL, ipf_settimeout }, |
380 | { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) }, |
381 | "udp_ack_timeout" , 1, 0x7fffffff, |
382 | stsizeof(ipf_main_softc_t, ipf_udpacktimeout), |
383 | 0, NULL, ipf_settimeout }, |
384 | { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) }, |
385 | "icmp_timeout" , 1, 0x7fffffff, |
386 | stsizeof(ipf_main_softc_t, ipf_icmptimeout), |
387 | 0, NULL, ipf_settimeout }, |
388 | { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) }, |
389 | "icmp_ack_timeout" , 1, 0x7fffffff, |
390 | stsizeof(ipf_main_softc_t, ipf_icmpacktimeout), |
391 | 0, NULL, ipf_settimeout }, |
392 | { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) }, |
393 | "ip_timeout" , 1, 0x7fffffff, |
394 | stsizeof(ipf_main_softc_t, ipf_iptimeout), |
395 | 0, NULL, ipf_settimeout }, |
396 | #if defined(INSTANCES) && defined(_KERNEL) |
397 | { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) }, |
398 | "intercept_loopback" , 0, 1, |
399 | stsizeof(ipf_main_softc_t, ipf_get_loopback), |
400 | 0, NULL, ipf_set_loopback }, |
401 | #endif |
402 | { { 0 }, |
403 | NULL, 0, 0, |
404 | 0, |
405 | 0, NULL, NULL } |
406 | }; |
407 | |
408 | |
409 | /* |
410 | * The next section of code is a a collection of small routines that set |
411 | * fields in the fr_info_t structure passed based on properties of the |
412 | * current packet. There are different routines for the same protocol |
413 | * for each of IPv4 and IPv6. Adding a new protocol, for which there |
414 | * will "special" inspection for setup, is now more easily done by adding |
415 | * a new routine and expanding the ipf_pr_ipinit*() function rather than by |
416 | * adding more code to a growing switch statement. |
417 | */ |
418 | #ifdef USE_INET6 |
419 | static INLINE int ipf_pr_ah6(fr_info_t *); |
420 | static INLINE void ipf_pr_esp6(fr_info_t *); |
421 | static INLINE void ipf_pr_gre6(fr_info_t *); |
422 | static INLINE void ipf_pr_udp6(fr_info_t *); |
423 | static INLINE void ipf_pr_tcp6(fr_info_t *); |
424 | static INLINE void ipf_pr_icmp6(fr_info_t *); |
425 | static INLINE void ipf_pr_ipv6hdr(fr_info_t *); |
426 | static INLINE void ipf_pr_short6(fr_info_t *, int); |
427 | static INLINE int ipf_pr_hopopts6(fr_info_t *); |
428 | static INLINE int ipf_pr_mobility6(fr_info_t *); |
429 | static INLINE int ipf_pr_routing6(fr_info_t *); |
430 | static INLINE int ipf_pr_dstopts6(fr_info_t *); |
431 | static INLINE int ipf_pr_fragment6(fr_info_t *); |
432 | static INLINE struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int); |
433 | |
434 | |
435 | /* ------------------------------------------------------------------------ */ |
436 | /* Function: ipf_pr_short6 */ |
437 | /* Returns: void */ |
438 | /* Parameters: fin(I) - pointer to packet information */ |
439 | /* xmin(I) - minimum header size */ |
440 | /* */ |
441 | /* IPv6 Only */ |
442 | /* This is function enforces the 'is a packet too short to be legit' rule */ |
443 | /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ |
444 | /* for ipf_pr_short() for more details. */ |
445 | /* ------------------------------------------------------------------------ */ |
446 | static INLINE void |
447 | ipf_pr_short6(fr_info_t *fin, int xmin) |
448 | { |
449 | |
450 | if (fin->fin_dlen < xmin) |
451 | fin->fin_flx |= FI_SHORT; |
452 | } |
453 | |
454 | |
455 | /* ------------------------------------------------------------------------ */ |
456 | /* Function: ipf_pr_ipv6hdr */ |
457 | /* Returns: void */ |
458 | /* Parameters: fin(I) - pointer to packet information */ |
459 | /* */ |
460 | /* IPv6 Only */ |
461 | /* Copy values from the IPv6 header into the fr_info_t struct and call the */ |
462 | /* per-protocol analyzer if it exists. In validating the packet, a protocol*/ |
463 | /* analyzer may pullup or free the packet itself so we need to be vigiliant */ |
464 | /* of that possibility arising. */ |
465 | /* ------------------------------------------------------------------------ */ |
466 | static INLINE void |
467 | ipf_pr_ipv6hdr(fr_info_t *fin) |
468 | { |
469 | ip6_t *ip6 = (ip6_t *)fin->fin_ip; |
470 | int p, go = 1, i, hdrcount; |
471 | fr_ip_t *fi = &fin->fin_fi; |
472 | |
473 | fin->fin_off = 0; |
474 | |
475 | fi->fi_tos = 0; |
476 | fi->fi_optmsk = 0; |
477 | fi->fi_secmsk = 0; |
478 | fi->fi_auth = 0; |
479 | |
480 | p = ip6->ip6_nxt; |
481 | fin->fin_crc = p; |
482 | fi->fi_ttl = ip6->ip6_hlim; |
483 | fi->fi_src.in6 = ip6->ip6_src; |
484 | fin->fin_crc += fi->fi_src.i6[0]; |
485 | fin->fin_crc += fi->fi_src.i6[1]; |
486 | fin->fin_crc += fi->fi_src.i6[2]; |
487 | fin->fin_crc += fi->fi_src.i6[3]; |
488 | fi->fi_dst.in6 = ip6->ip6_dst; |
489 | fin->fin_crc += fi->fi_dst.i6[0]; |
490 | fin->fin_crc += fi->fi_dst.i6[1]; |
491 | fin->fin_crc += fi->fi_dst.i6[2]; |
492 | fin->fin_crc += fi->fi_dst.i6[3]; |
493 | fin->fin_id = 0; |
494 | if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) |
495 | fin->fin_flx |= FI_MULTICAST|FI_MBCAST; |
496 | |
497 | hdrcount = 0; |
498 | while (go && !(fin->fin_flx & FI_SHORT)) { |
499 | switch (p) |
500 | { |
501 | case IPPROTO_UDP : |
502 | ipf_pr_udp6(fin); |
503 | go = 0; |
504 | break; |
505 | |
506 | case IPPROTO_TCP : |
507 | ipf_pr_tcp6(fin); |
508 | go = 0; |
509 | break; |
510 | |
511 | case IPPROTO_ICMPV6 : |
512 | ipf_pr_icmp6(fin); |
513 | go = 0; |
514 | break; |
515 | |
516 | case IPPROTO_GRE : |
517 | ipf_pr_gre6(fin); |
518 | go = 0; |
519 | break; |
520 | |
521 | case IPPROTO_HOPOPTS : |
522 | p = ipf_pr_hopopts6(fin); |
523 | break; |
524 | |
525 | case IPPROTO_MOBILITY : |
526 | p = ipf_pr_mobility6(fin); |
527 | break; |
528 | |
529 | case IPPROTO_DSTOPTS : |
530 | p = ipf_pr_dstopts6(fin); |
531 | break; |
532 | |
533 | case IPPROTO_ROUTING : |
534 | p = ipf_pr_routing6(fin); |
535 | break; |
536 | |
537 | case IPPROTO_AH : |
538 | p = ipf_pr_ah6(fin); |
539 | break; |
540 | |
541 | case IPPROTO_ESP : |
542 | ipf_pr_esp6(fin); |
543 | go = 0; |
544 | break; |
545 | |
546 | case IPPROTO_IPV6 : |
547 | for (i = 0; ip6exthdr[i].ol_bit != 0; i++) |
548 | if (ip6exthdr[i].ol_val == p) { |
549 | fin->fin_flx |= ip6exthdr[i].ol_bit; |
550 | break; |
551 | } |
552 | go = 0; |
553 | break; |
554 | |
555 | case IPPROTO_NONE : |
556 | go = 0; |
557 | break; |
558 | |
559 | case IPPROTO_FRAGMENT : |
560 | p = ipf_pr_fragment6(fin); |
561 | /* |
562 | * Given that the only fragments we want to let through |
563 | * (where fin_off != 0) are those where the non-first |
564 | * fragments only have data, we can safely stop looking |
565 | * at headers if this is a non-leading fragment. |
566 | */ |
567 | if (fin->fin_off != 0) |
568 | go = 0; |
569 | break; |
570 | |
571 | default : |
572 | go = 0; |
573 | break; |
574 | } |
575 | hdrcount++; |
576 | |
577 | /* |
578 | * It is important to note that at this point, for the |
579 | * extension headers (go != 0), the entire header may not have |
580 | * been pulled up when the code gets to this point. This is |
581 | * only done for "go != 0" because the other header handlers |
582 | * will all pullup their complete header. The other indicator |
583 | * of an incomplete packet is that this was just an extension |
584 | * header. |
585 | */ |
586 | if ((go != 0) && (p != IPPROTO_NONE) && |
587 | (ipf_pr_pullup(fin, 0) == -1)) { |
588 | p = IPPROTO_NONE; |
589 | break; |
590 | } |
591 | } |
592 | |
593 | /* |
594 | * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup |
595 | * and destroy whatever packet was here. The caller of this function |
596 | * expects us to return if there is a problem with ipf_pullup. |
597 | */ |
598 | if (fin->fin_m == NULL) { |
599 | ipf_main_softc_t *softc = fin->fin_main_soft; |
600 | |
601 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad); |
602 | return; |
603 | } |
604 | |
605 | fi->fi_p = p; |
606 | |
607 | /* |
608 | * IPv6 fragment case 1 - see comment for ipf_pr_fragment6(). |
609 | * "go != 0" imples the above loop hasn't arrived at a layer 4 header. |
610 | */ |
611 | if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) { |
612 | ipf_main_softc_t *softc = fin->fin_main_soft; |
613 | |
614 | fin->fin_flx |= FI_BAD; |
615 | DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go); |
616 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag); |
617 | LBUMP(ipf_stats[fin->fin_out].fr_v6_bad); |
618 | } |
619 | } |
620 | |
621 | |
622 | /* ------------------------------------------------------------------------ */ |
623 | /* Function: ipf_pr_ipv6exthdr */ |
624 | /* Returns: struct ip6_ext * - pointer to the start of the next header */ |
625 | /* or NULL if there is a prolblem. */ |
626 | /* Parameters: fin(I) - pointer to packet information */ |
627 | /* multiple(I) - flag indicating yes/no if multiple occurances */ |
628 | /* of this extension header are allowed. */ |
629 | /* proto(I) - protocol number for this extension header */ |
630 | /* */ |
631 | /* IPv6 Only */ |
632 | /* This function embodies a number of common checks that all IPv6 extension */ |
633 | /* headers must be subjected to. For example, making sure the packet is */ |
634 | /* big enough for it to be in, checking if it is repeated and setting a */ |
635 | /* flag to indicate its presence. */ |
636 | /* ------------------------------------------------------------------------ */ |
637 | static INLINE struct ip6_ext * |
638 | ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto) |
639 | { |
640 | ipf_main_softc_t *softc = fin->fin_main_soft; |
641 | struct ip6_ext *hdr; |
642 | u_short shift; |
643 | int i; |
644 | |
645 | fin->fin_flx |= FI_V6EXTHDR; |
646 | |
647 | /* 8 is default length of extension hdr */ |
648 | if ((fin->fin_dlen - 8) < 0) { |
649 | fin->fin_flx |= FI_SHORT; |
650 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short); |
651 | return NULL; |
652 | } |
653 | |
654 | if (ipf_pr_pullup(fin, 8) == -1) { |
655 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup); |
656 | return NULL; |
657 | } |
658 | |
659 | hdr = fin->fin_dp; |
660 | switch (proto) |
661 | { |
662 | case IPPROTO_FRAGMENT : |
663 | shift = 8; |
664 | break; |
665 | default : |
666 | shift = 8 + (hdr->ip6e_len << 3); |
667 | break; |
668 | } |
669 | |
670 | if (shift > fin->fin_dlen) { /* Nasty extension header length? */ |
671 | fin->fin_flx |= FI_BAD; |
672 | DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen); |
673 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen); |
674 | return NULL; |
675 | } |
676 | |
677 | fin->fin_dp = (char *)fin->fin_dp + shift; |
678 | fin->fin_dlen -= shift; |
679 | |
680 | /* |
681 | * If we have seen a fragment header, do not set any flags to indicate |
682 | * the presence of this extension header as it has no impact on the |
683 | * end result until after it has been defragmented. |
684 | */ |
685 | if (fin->fin_flx & FI_FRAG) |
686 | return hdr; |
687 | |
688 | for (i = 0; ip6exthdr[i].ol_bit != 0; i++) |
689 | if (ip6exthdr[i].ol_val == proto) { |
690 | /* |
691 | * Most IPv6 extension headers are only allowed once. |
692 | */ |
693 | if ((multiple == 0) && |
694 | ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) { |
695 | fin->fin_flx |= FI_BAD; |
696 | DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit)); |
697 | } else |
698 | fin->fin_optmsk |= ip6exthdr[i].ol_bit; |
699 | break; |
700 | } |
701 | |
702 | return hdr; |
703 | } |
704 | |
705 | |
706 | /* ------------------------------------------------------------------------ */ |
707 | /* Function: ipf_pr_hopopts6 */ |
708 | /* Returns: int - value of the next header or IPPROTO_NONE if error */ |
709 | /* Parameters: fin(I) - pointer to packet information */ |
710 | /* */ |
711 | /* IPv6 Only */ |
712 | /* This is function checks pending hop by hop options extension header */ |
713 | /* ------------------------------------------------------------------------ */ |
714 | static INLINE int |
715 | ipf_pr_hopopts6(fr_info_t *fin) |
716 | { |
717 | struct ip6_ext *hdr; |
718 | |
719 | hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); |
720 | if (hdr == NULL) |
721 | return IPPROTO_NONE; |
722 | return hdr->ip6e_nxt; |
723 | } |
724 | |
725 | |
726 | /* ------------------------------------------------------------------------ */ |
727 | /* Function: ipf_pr_mobility6 */ |
728 | /* Returns: int - value of the next header or IPPROTO_NONE if error */ |
729 | /* Parameters: fin(I) - pointer to packet information */ |
730 | /* */ |
731 | /* IPv6 Only */ |
732 | /* This is function checks the IPv6 mobility extension header */ |
733 | /* ------------------------------------------------------------------------ */ |
734 | static INLINE int |
735 | ipf_pr_mobility6(fr_info_t *fin) |
736 | { |
737 | struct ip6_ext *hdr; |
738 | |
739 | hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); |
740 | if (hdr == NULL) |
741 | return IPPROTO_NONE; |
742 | return hdr->ip6e_nxt; |
743 | } |
744 | |
745 | |
746 | /* ------------------------------------------------------------------------ */ |
747 | /* Function: ipf_pr_routing6 */ |
748 | /* Returns: int - value of the next header or IPPROTO_NONE if error */ |
749 | /* Parameters: fin(I) - pointer to packet information */ |
750 | /* */ |
751 | /* IPv6 Only */ |
752 | /* This is function checks pending routing extension header */ |
753 | /* ------------------------------------------------------------------------ */ |
754 | static INLINE int |
755 | ipf_pr_routing6(fr_info_t *fin) |
756 | { |
757 | struct ip6_routing *hdr; |
758 | |
759 | hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING); |
760 | if (hdr == NULL) |
761 | return IPPROTO_NONE; |
762 | |
763 | switch (hdr->ip6r_type) |
764 | { |
765 | case 0 : |
766 | /* |
767 | * Nasty extension header length? |
768 | */ |
769 | if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) || |
770 | (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) { |
771 | ipf_main_softc_t *softc = fin->fin_main_soft; |
772 | |
773 | fin->fin_flx |= FI_BAD; |
774 | DT1(ipf_fi_bad_routing6, fr_info_t *, fin); |
775 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad); |
776 | return IPPROTO_NONE; |
777 | } |
778 | break; |
779 | |
780 | default : |
781 | break; |
782 | } |
783 | |
784 | return hdr->ip6r_nxt; |
785 | } |
786 | |
787 | |
788 | /* ------------------------------------------------------------------------ */ |
789 | /* Function: ipf_pr_fragment6 */ |
790 | /* Returns: int - value of the next header or IPPROTO_NONE if error */ |
791 | /* Parameters: fin(I) - pointer to packet information */ |
792 | /* */ |
793 | /* IPv6 Only */ |
794 | /* Examine the IPv6 fragment header and extract fragment offset information.*/ |
795 | /* */ |
796 | /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */ |
797 | /* so than in IPv4. There are 5 cases of fragments with IPv6 that all */ |
798 | /* packets with a fragment header can fit into. They are as follows: */ |
799 | /* */ |
800 | /* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */ |
801 | /* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */ |
802 | /* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */ |
803 | /* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */ |
804 | /* 5. [IPV6][0-n EH][FH][data] */ |
805 | /* */ |
806 | /* IPV6 = IPv6 header, FH = Fragment Header, */ |
807 | /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */ |
808 | /* */ |
809 | /* Packets that match 1, 2, 3 will be dropped as the only reasonable */ |
810 | /* scenario in which they happen is in extreme circumstances that are most */ |
811 | /* likely to be an indication of an attack rather than normal traffic. */ |
812 | /* A type 3 packet may be sent by an attacked after a type 4 packet. There */ |
813 | /* are two rules that can be used to guard against type 3 packets: L4 */ |
814 | /* headers must always be in a packet that has the offset field set to 0 */ |
815 | /* and no packet is allowed to overlay that where offset = 0. */ |
816 | /* ------------------------------------------------------------------------ */ |
817 | static INLINE int |
818 | ipf_pr_fragment6(fr_info_t *fin) |
819 | { |
820 | ipf_main_softc_t *softc = fin->fin_main_soft; |
821 | struct ip6_frag *frag; |
822 | |
823 | fin->fin_flx |= FI_FRAG; |
824 | |
825 | frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT); |
826 | if (frag == NULL) { |
827 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad); |
828 | return IPPROTO_NONE; |
829 | } |
830 | |
831 | if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { |
832 | /* |
833 | * Any fragment that isn't the last fragment must have its |
834 | * length as a multiple of 8. |
835 | */ |
836 | if ((fin->fin_plen & 7) != 0) { |
837 | fin->fin_flx |= FI_BAD; |
838 | DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7)); |
839 | } |
840 | } |
841 | |
842 | fin->fin_fraghdr = frag; |
843 | fin->fin_id = frag->ip6f_ident; |
844 | fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); |
845 | if (fin->fin_off != 0) |
846 | fin->fin_flx |= FI_FRAGBODY; |
847 | |
848 | /* |
849 | * Jumbograms aren't handled, so the max. length is 64k |
850 | */ |
851 | if ((fin->fin_off << 3) + fin->fin_dlen > 65535) { |
852 | fin->fin_flx |= FI_BAD; |
853 | DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen)); |
854 | } |
855 | |
856 | /* |
857 | * We don't know where the transport layer header (or whatever is next |
858 | * is), as it could be behind destination options (amongst others) so |
859 | * return the fragment header as the type of packet this is. Note that |
860 | * this effectively disables the fragment cache for > 1 protocol at a |
861 | * time. |
862 | */ |
863 | return frag->ip6f_nxt; |
864 | } |
865 | |
866 | |
867 | /* ------------------------------------------------------------------------ */ |
868 | /* Function: ipf_pr_dstopts6 */ |
869 | /* Returns: int - value of the next header or IPPROTO_NONE if error */ |
870 | /* Parameters: fin(I) - pointer to packet information */ |
871 | /* */ |
872 | /* IPv6 Only */ |
873 | /* This is function checks pending destination options extension header */ |
874 | /* ------------------------------------------------------------------------ */ |
875 | static INLINE int |
876 | ipf_pr_dstopts6(fr_info_t *fin) |
877 | { |
878 | ipf_main_softc_t *softc = fin->fin_main_soft; |
879 | struct ip6_ext *hdr; |
880 | |
881 | hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS); |
882 | if (hdr == NULL) { |
883 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad); |
884 | return IPPROTO_NONE; |
885 | } |
886 | return hdr->ip6e_nxt; |
887 | } |
888 | |
889 | |
890 | /* ------------------------------------------------------------------------ */ |
891 | /* Function: ipf_pr_icmp6 */ |
892 | /* Returns: void */ |
893 | /* Parameters: fin(I) - pointer to packet information */ |
894 | /* */ |
895 | /* IPv6 Only */ |
896 | /* This routine is mainly concerned with determining the minimum valid size */ |
897 | /* for an ICMPv6 packet. */ |
898 | /* ------------------------------------------------------------------------ */ |
899 | static INLINE void |
900 | ipf_pr_icmp6(fr_info_t *fin) |
901 | { |
902 | int minicmpsz = sizeof(struct icmp6_hdr); |
903 | struct icmp6_hdr *icmp6; |
904 | |
905 | if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) { |
906 | ipf_main_softc_t *softc = fin->fin_main_soft; |
907 | |
908 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup); |
909 | return; |
910 | } |
911 | |
912 | if (fin->fin_dlen > 1) { |
913 | ip6_t *ip6; |
914 | |
915 | icmp6 = fin->fin_dp; |
916 | |
917 | fin->fin_data[0] = *(u_short *)icmp6; |
918 | |
919 | if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) |
920 | fin->fin_flx |= FI_ICMPQUERY; |
921 | |
922 | switch (icmp6->icmp6_type) |
923 | { |
924 | case ICMP6_ECHO_REPLY : |
925 | case ICMP6_ECHO_REQUEST : |
926 | if (fin->fin_dlen >= 6) |
927 | fin->fin_data[1] = icmp6->icmp6_id; |
928 | minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); |
929 | break; |
930 | |
931 | case ICMP6_DST_UNREACH : |
932 | case ICMP6_PACKET_TOO_BIG : |
933 | case ICMP6_TIME_EXCEEDED : |
934 | case ICMP6_PARAM_PROB : |
935 | fin->fin_flx |= FI_ICMPERR; |
936 | minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); |
937 | if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) |
938 | break; |
939 | |
940 | if (M_LEN(fin->fin_m) < fin->fin_plen) { |
941 | if (ipf_coalesce(fin) != 1) |
942 | return; |
943 | } |
944 | |
945 | if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) |
946 | return; |
947 | |
948 | /* |
949 | * If the destination of this packet doesn't match the |
950 | * source of the original packet then this packet is |
951 | * not correct. |
952 | */ |
953 | icmp6 = fin->fin_dp; |
954 | ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); |
955 | if (IP6_NEQ(&fin->fin_fi.fi_dst, |
956 | &ip6->ip6_src)) { |
957 | fin->fin_flx |= FI_BAD; |
958 | DT1(ipf_fi_bad_icmp6, fr_info_t *, fin); |
959 | } |
960 | break; |
961 | default : |
962 | break; |
963 | } |
964 | } |
965 | |
966 | ipf_pr_short6(fin, minicmpsz); |
967 | if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) { |
968 | u_char p = fin->fin_p; |
969 | |
970 | fin->fin_p = IPPROTO_ICMPV6; |
971 | ipf_checkv6sum(fin); |
972 | fin->fin_p = p; |
973 | } |
974 | } |
975 | |
976 | |
977 | /* ------------------------------------------------------------------------ */ |
978 | /* Function: ipf_pr_udp6 */ |
979 | /* Returns: void */ |
980 | /* Parameters: fin(I) - pointer to packet information */ |
981 | /* */ |
982 | /* IPv6 Only */ |
983 | /* Analyse the packet for IPv6/UDP properties. */ |
984 | /* Is not expected to be called for fragmented packets. */ |
985 | /* ------------------------------------------------------------------------ */ |
986 | static INLINE void |
987 | ipf_pr_udp6(fr_info_t *fin) |
988 | { |
989 | |
990 | if (ipf_pr_udpcommon(fin) == 0) { |
991 | u_char p = fin->fin_p; |
992 | |
993 | fin->fin_p = IPPROTO_UDP; |
994 | ipf_checkv6sum(fin); |
995 | fin->fin_p = p; |
996 | } |
997 | } |
998 | |
999 | |
1000 | /* ------------------------------------------------------------------------ */ |
1001 | /* Function: ipf_pr_tcp6 */ |
1002 | /* Returns: void */ |
1003 | /* Parameters: fin(I) - pointer to packet information */ |
1004 | /* */ |
1005 | /* IPv6 Only */ |
1006 | /* Analyse the packet for IPv6/TCP properties. */ |
1007 | /* Is not expected to be called for fragmented packets. */ |
1008 | /* ------------------------------------------------------------------------ */ |
1009 | static INLINE void |
1010 | ipf_pr_tcp6(fr_info_t *fin) |
1011 | { |
1012 | |
1013 | if (ipf_pr_tcpcommon(fin) == 0) { |
1014 | u_char p = fin->fin_p; |
1015 | |
1016 | fin->fin_p = IPPROTO_TCP; |
1017 | ipf_checkv6sum(fin); |
1018 | fin->fin_p = p; |
1019 | } |
1020 | } |
1021 | |
1022 | |
1023 | /* ------------------------------------------------------------------------ */ |
1024 | /* Function: ipf_pr_esp6 */ |
1025 | /* Returns: void */ |
1026 | /* Parameters: fin(I) - pointer to packet information */ |
1027 | /* */ |
1028 | /* IPv6 Only */ |
1029 | /* Analyse the packet for ESP properties. */ |
1030 | /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ |
1031 | /* even though the newer ESP packets must also have a sequence number that */ |
1032 | /* is 32bits as well, it is not possible(?) to determine the version from a */ |
1033 | /* simple packet header. */ |
1034 | /* ------------------------------------------------------------------------ */ |
1035 | static INLINE void |
1036 | ipf_pr_esp6(fr_info_t *fin) |
1037 | { |
1038 | |
1039 | if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) { |
1040 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1041 | |
1042 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup); |
1043 | return; |
1044 | } |
1045 | } |
1046 | |
1047 | |
1048 | /* ------------------------------------------------------------------------ */ |
1049 | /* Function: ipf_pr_ah6 */ |
1050 | /* Returns: int - value of the next header or IPPROTO_NONE if error */ |
1051 | /* Parameters: fin(I) - pointer to packet information */ |
1052 | /* */ |
1053 | /* IPv6 Only */ |
1054 | /* Analyse the packet for AH properties. */ |
1055 | /* The minimum length is taken to be the combination of all fields in the */ |
1056 | /* header being present and no authentication data (null algorithm used.) */ |
1057 | /* ------------------------------------------------------------------------ */ |
1058 | static INLINE int |
1059 | ipf_pr_ah6(fr_info_t *fin) |
1060 | { |
1061 | authhdr_t *ah; |
1062 | |
1063 | fin->fin_flx |= FI_AH; |
1064 | |
1065 | ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); |
1066 | if (ah == NULL) { |
1067 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1068 | |
1069 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad); |
1070 | return IPPROTO_NONE; |
1071 | } |
1072 | |
1073 | ipf_pr_short6(fin, sizeof(*ah)); |
1074 | |
1075 | /* |
1076 | * No need for another pullup, ipf_pr_ipv6exthdr() will pullup |
1077 | * enough data to satisfy ah_next (the very first one.) |
1078 | */ |
1079 | return ah->ah_next; |
1080 | } |
1081 | |
1082 | |
1083 | /* ------------------------------------------------------------------------ */ |
1084 | /* Function: ipf_pr_gre6 */ |
1085 | /* Returns: void */ |
1086 | /* Parameters: fin(I) - pointer to packet information */ |
1087 | /* */ |
1088 | /* Analyse the packet for GRE properties. */ |
1089 | /* ------------------------------------------------------------------------ */ |
1090 | static INLINE void |
1091 | ipf_pr_gre6(fr_info_t *fin) |
1092 | { |
1093 | grehdr_t *gre; |
1094 | |
1095 | if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { |
1096 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1097 | |
1098 | LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup); |
1099 | return; |
1100 | } |
1101 | |
1102 | gre = fin->fin_dp; |
1103 | if (GRE_REV(gre->gr_flags) == 1) |
1104 | fin->fin_data[0] = gre->gr_call; |
1105 | } |
1106 | #endif /* USE_INET6 */ |
1107 | |
1108 | |
1109 | /* ------------------------------------------------------------------------ */ |
1110 | /* Function: ipf_pr_pullup */ |
1111 | /* Returns: int - 0 == pullup succeeded, -1 == failure */ |
1112 | /* Parameters: fin(I) - pointer to packet information */ |
1113 | /* plen(I) - length (excluding L3 header) to pullup */ |
1114 | /* */ |
1115 | /* Short inline function to cut down on code duplication to perform a call */ |
1116 | /* to ipf_pullup to ensure there is the required amount of data, */ |
1117 | /* consecutively in the packet buffer. */ |
1118 | /* */ |
1119 | /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ |
1120 | /* points to the first byte after the complete layer 3 header, which will */ |
1121 | /* include all of the known extension headers for IPv6 or options for IPv4. */ |
1122 | /* */ |
1123 | /* Since fr_pullup() expects the total length of bytes to be pulled up, it */ |
1124 | /* is necessary to add those we can already assume to be pulled up (fin_dp */ |
1125 | /* - fin_ip) to what is passed through. */ |
1126 | /* ------------------------------------------------------------------------ */ |
1127 | int |
1128 | ipf_pr_pullup(fr_info_t *fin, int plen) |
1129 | { |
1130 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1131 | |
1132 | if (fin->fin_m != NULL) { |
1133 | if (fin->fin_dp != NULL) |
1134 | plen += (char *)fin->fin_dp - |
1135 | ((char *)fin->fin_ip + fin->fin_hlen); |
1136 | plen += fin->fin_hlen; |
1137 | if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) { |
1138 | #if defined(_KERNEL) |
1139 | if (ipf_pullup(fin->fin_m, fin, plen) == NULL) { |
1140 | DT(ipf_pullup_fail); |
1141 | LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); |
1142 | return -1; |
1143 | } |
1144 | LBUMP(ipf_stats[fin->fin_out].fr_pull[0]); |
1145 | #else |
1146 | LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); |
1147 | /* |
1148 | * Fake ipf_pullup failing |
1149 | */ |
1150 | fin->fin_reason = FRB_PULLUP; |
1151 | *fin->fin_mp = NULL; |
1152 | fin->fin_m = NULL; |
1153 | fin->fin_ip = NULL; |
1154 | return -1; |
1155 | #endif |
1156 | } |
1157 | } |
1158 | return 0; |
1159 | } |
1160 | |
1161 | |
1162 | /* ------------------------------------------------------------------------ */ |
1163 | /* Function: ipf_pr_short */ |
1164 | /* Returns: void */ |
1165 | /* Parameters: fin(I) - pointer to packet information */ |
1166 | /* xmin(I) - minimum header size */ |
1167 | /* */ |
1168 | /* Check if a packet is "short" as defined by xmin. The rule we are */ |
1169 | /* applying here is that the packet must not be fragmented within the layer */ |
1170 | /* 4 header. That is, it must not be a fragment that has its offset set to */ |
1171 | /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ |
1172 | /* entire layer 4 header must be present (min). */ |
1173 | /* ------------------------------------------------------------------------ */ |
1174 | static INLINE void |
1175 | ipf_pr_short(fr_info_t *fin, int xmin) |
1176 | { |
1177 | |
1178 | if (fin->fin_off == 0) { |
1179 | if (fin->fin_dlen < xmin) |
1180 | fin->fin_flx |= FI_SHORT; |
1181 | } else if (fin->fin_off < xmin) { |
1182 | fin->fin_flx |= FI_SHORT; |
1183 | } |
1184 | } |
1185 | |
1186 | |
1187 | /* ------------------------------------------------------------------------ */ |
1188 | /* Function: ipf_pr_icmp */ |
1189 | /* Returns: void */ |
1190 | /* Parameters: fin(I) - pointer to packet information */ |
1191 | /* */ |
1192 | /* IPv4 Only */ |
1193 | /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ |
1194 | /* except extrememly bad packets, both type and code will be present. */ |
1195 | /* The expected minimum size of an ICMP packet is very much dependent on */ |
1196 | /* the type of it. */ |
1197 | /* */ |
1198 | /* XXX - other ICMP sanity checks? */ |
1199 | /* ------------------------------------------------------------------------ */ |
1200 | static INLINE void |
1201 | ipf_pr_icmp(fr_info_t *fin) |
1202 | { |
1203 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1204 | int minicmpsz = sizeof(struct icmp); |
1205 | icmphdr_t *icmp; |
1206 | ip_t *oip; |
1207 | |
1208 | ipf_pr_short(fin, ICMPERR_ICMPHLEN); |
1209 | |
1210 | if (fin->fin_off != 0) { |
1211 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag); |
1212 | return; |
1213 | } |
1214 | |
1215 | if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) { |
1216 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup); |
1217 | return; |
1218 | } |
1219 | |
1220 | icmp = fin->fin_dp; |
1221 | |
1222 | fin->fin_data[0] = *(u_short *)icmp; |
1223 | fin->fin_data[1] = icmp->icmp_id; |
1224 | |
1225 | switch (icmp->icmp_type) |
1226 | { |
1227 | case ICMP_ECHOREPLY : |
1228 | case ICMP_ECHO : |
1229 | /* Router discovery messaes - RFC 1256 */ |
1230 | case ICMP_ROUTERADVERT : |
1231 | case ICMP_ROUTERSOLICIT : |
1232 | fin->fin_flx |= FI_ICMPQUERY; |
1233 | minicmpsz = ICMP_MINLEN; |
1234 | break; |
1235 | /* |
1236 | * type(1) + code(1) + cksum(2) + id(2) seq(2) + |
1237 | * 3 * timestamp(3 * 4) |
1238 | */ |
1239 | case ICMP_TSTAMP : |
1240 | case ICMP_TSTAMPREPLY : |
1241 | fin->fin_flx |= FI_ICMPQUERY; |
1242 | minicmpsz = 20; |
1243 | break; |
1244 | /* |
1245 | * type(1) + code(1) + cksum(2) + id(2) seq(2) + |
1246 | * mask(4) |
1247 | */ |
1248 | case ICMP_IREQ : |
1249 | case ICMP_IREQREPLY : |
1250 | case ICMP_MASKREQ : |
1251 | case ICMP_MASKREPLY : |
1252 | fin->fin_flx |= FI_ICMPQUERY; |
1253 | minicmpsz = 12; |
1254 | break; |
1255 | /* |
1256 | * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) |
1257 | */ |
1258 | case ICMP_UNREACH : |
1259 | #ifdef icmp_nextmtu |
1260 | if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { |
1261 | if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) { |
1262 | fin->fin_flx |= FI_BAD; |
1263 | DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu); |
1264 | } |
1265 | } |
1266 | #endif |
1267 | case ICMP_SOURCEQUENCH : |
1268 | case ICMP_REDIRECT : |
1269 | case ICMP_TIMXCEED : |
1270 | case ICMP_PARAMPROB : |
1271 | fin->fin_flx |= FI_ICMPERR; |
1272 | if (ipf_coalesce(fin) != 1) { |
1273 | LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce); |
1274 | return; |
1275 | } |
1276 | |
1277 | /* |
1278 | * ICMP error packets should not be generated for IP |
1279 | * packets that are a fragment that isn't the first |
1280 | * fragment. |
1281 | */ |
1282 | oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); |
1283 | if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) { |
1284 | fin->fin_flx |= FI_BAD; |
1285 | DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK)); |
1286 | } |
1287 | |
1288 | /* |
1289 | * If the destination of this packet doesn't match the |
1290 | * source of the original packet then this packet is |
1291 | * not correct. |
1292 | */ |
1293 | if (oip->ip_src.s_addr != fin->fin_daddr) { |
1294 | fin->fin_flx |= FI_BAD; |
1295 | DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin); |
1296 | } |
1297 | break; |
1298 | default : |
1299 | break; |
1300 | } |
1301 | |
1302 | ipf_pr_short(fin, minicmpsz); |
1303 | |
1304 | ipf_checkv4sum(fin); |
1305 | } |
1306 | |
1307 | |
1308 | /* ------------------------------------------------------------------------ */ |
1309 | /* Function: ipf_pr_tcpcommon */ |
1310 | /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ |
1311 | /* Parameters: fin(I) - pointer to packet information */ |
1312 | /* */ |
1313 | /* TCP header sanity checking. Look for bad combinations of TCP flags, */ |
1314 | /* and make some checks with how they interact with other fields. */ |
1315 | /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ |
1316 | /* valid and mark the packet as bad if not. */ |
1317 | /* ------------------------------------------------------------------------ */ |
1318 | static INLINE int |
1319 | ipf_pr_tcpcommon(fr_info_t *fin) |
1320 | { |
1321 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1322 | int flags, tlen; |
1323 | tcphdr_t *tcp; |
1324 | |
1325 | fin->fin_flx |= FI_TCPUDP; |
1326 | if (fin->fin_off != 0) { |
1327 | LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag); |
1328 | return 0; |
1329 | } |
1330 | |
1331 | if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) { |
1332 | LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); |
1333 | return -1; |
1334 | } |
1335 | |
1336 | tcp = fin->fin_dp; |
1337 | if (fin->fin_dlen > 3) { |
1338 | fin->fin_sport = ntohs(tcp->th_sport); |
1339 | fin->fin_dport = ntohs(tcp->th_dport); |
1340 | } |
1341 | |
1342 | if ((fin->fin_flx & FI_SHORT) != 0) { |
1343 | LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short); |
1344 | return 1; |
1345 | } |
1346 | |
1347 | /* |
1348 | * Use of the TCP data offset *must* result in a value that is at |
1349 | * least the same size as the TCP header. |
1350 | */ |
1351 | tlen = TCP_OFF(tcp) << 2; |
1352 | if (tlen < sizeof(tcphdr_t)) { |
1353 | LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small); |
1354 | fin->fin_flx |= FI_BAD; |
1355 | DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t)); |
1356 | return 1; |
1357 | } |
1358 | |
1359 | flags = tcp->th_flags; |
1360 | fin->fin_tcpf = tcp->th_flags; |
1361 | |
1362 | /* |
1363 | * If the urgent flag is set, then the urgent pointer must |
1364 | * also be set and vice versa. Good TCP packets do not have |
1365 | * just one of these set. |
1366 | */ |
1367 | if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { |
1368 | fin->fin_flx |= FI_BAD; |
1369 | DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); |
1370 | #if 0 |
1371 | } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { |
1372 | /* |
1373 | * Ignore this case (#if 0) as it shows up in "real" |
1374 | * traffic with bogus values in the urgent pointer field. |
1375 | */ |
1376 | fin->fin_flx |= FI_BAD; |
1377 | DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); |
1378 | #endif |
1379 | } else if (((flags & (TH_SYN|TH_FIN)) != 0) && |
1380 | ((flags & (TH_RST|TH_ACK)) == TH_RST)) { |
1381 | /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ |
1382 | fin->fin_flx |= FI_BAD; |
1383 | DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin); |
1384 | #if 1 |
1385 | } else if (((flags & TH_SYN) != 0) && |
1386 | ((flags & (TH_URG|TH_PUSH)) != 0)) { |
1387 | /* |
1388 | * SYN with URG and PUSH set is not for normal TCP but it is |
1389 | * possible(?) with T/TCP...but who uses T/TCP? |
1390 | */ |
1391 | fin->fin_flx |= FI_BAD; |
1392 | DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin); |
1393 | #endif |
1394 | } else if (!(flags & TH_ACK)) { |
1395 | /* |
1396 | * If the ack bit isn't set, then either the SYN or |
1397 | * RST bit must be set. If the SYN bit is set, then |
1398 | * we expect the ACK field to be 0. If the ACK is |
1399 | * not set and if URG, PSH or FIN are set, consdier |
1400 | * that to indicate a bad TCP packet. |
1401 | */ |
1402 | if ((flags == TH_SYN) && (tcp->th_ack != 0)) { |
1403 | /* |
1404 | * Cisco PIX sets the ACK field to a random value. |
1405 | * In light of this, do not set FI_BAD until a patch |
1406 | * is available from Cisco to ensure that |
1407 | * interoperability between existing systems is |
1408 | * achieved. |
1409 | */ |
1410 | /*fin->fin_flx |= FI_BAD*/; |
1411 | /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/ |
1412 | } else if (!(flags & (TH_RST|TH_SYN))) { |
1413 | fin->fin_flx |= FI_BAD; |
1414 | DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin); |
1415 | } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { |
1416 | fin->fin_flx |= FI_BAD; |
1417 | DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin); |
1418 | } |
1419 | } |
1420 | if (fin->fin_flx & FI_BAD) { |
1421 | LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags); |
1422 | return 1; |
1423 | } |
1424 | |
1425 | /* |
1426 | * At this point, it's not exactly clear what is to be gained by |
1427 | * marking up which TCP options are and are not present. The one we |
1428 | * are most interested in is the TCP window scale. This is only in |
1429 | * a SYN packet [RFC1323] so we don't need this here...? |
1430 | * Now if we were to analyse the header for passive fingerprinting, |
1431 | * then that might add some weight to adding this... |
1432 | */ |
1433 | if (tlen == sizeof(tcphdr_t)) { |
1434 | return 0; |
1435 | } |
1436 | |
1437 | if (ipf_pr_pullup(fin, tlen) == -1) { |
1438 | LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); |
1439 | return -1; |
1440 | } |
1441 | |
1442 | #if 0 |
1443 | tcp = fin->fin_dp; |
1444 | ip = fin->fin_ip; |
1445 | s = (u_char *)(tcp + 1); |
1446 | off = IP_HL(ip) << 2; |
1447 | # ifdef _KERNEL |
1448 | if (fin->fin_mp != NULL) { |
1449 | mb_t *m = *fin->fin_mp; |
1450 | |
1451 | if (off + tlen > M_LEN(m)) |
1452 | return; |
1453 | } |
1454 | # endif |
1455 | for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { |
1456 | opt = *s; |
1457 | if (opt == '\0') |
1458 | break; |
1459 | else if (opt == TCPOPT_NOP) |
1460 | ol = 1; |
1461 | else { |
1462 | if (tlen < 2) |
1463 | break; |
1464 | ol = (int)*(s + 1); |
1465 | if (ol < 2 || ol > tlen) |
1466 | break; |
1467 | } |
1468 | |
1469 | for (i = 9, mv = 4; mv >= 0; ) { |
1470 | op = ipopts + i; |
1471 | if (opt == (u_char)op->ol_val) { |
1472 | optmsk |= op->ol_bit; |
1473 | break; |
1474 | } |
1475 | } |
1476 | tlen -= ol; |
1477 | s += ol; |
1478 | } |
1479 | #endif /* 0 */ |
1480 | |
1481 | return 0; |
1482 | } |
1483 | |
1484 | |
1485 | |
1486 | /* ------------------------------------------------------------------------ */ |
1487 | /* Function: ipf_pr_udpcommon */ |
1488 | /* Returns: int - 0 = header ok, 1 = bad packet */ |
1489 | /* Parameters: fin(I) - pointer to packet information */ |
1490 | /* */ |
1491 | /* Extract the UDP source and destination ports, if present. If compiled */ |
1492 | /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ |
1493 | /* ------------------------------------------------------------------------ */ |
1494 | static INLINE int |
1495 | ipf_pr_udpcommon(fr_info_t *fin) |
1496 | { |
1497 | udphdr_t *udp; |
1498 | |
1499 | fin->fin_flx |= FI_TCPUDP; |
1500 | |
1501 | if (!fin->fin_off && (fin->fin_dlen > 3)) { |
1502 | if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) { |
1503 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1504 | |
1505 | fin->fin_flx |= FI_SHORT; |
1506 | LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup); |
1507 | return 1; |
1508 | } |
1509 | |
1510 | udp = fin->fin_dp; |
1511 | |
1512 | fin->fin_sport = ntohs(udp->uh_sport); |
1513 | fin->fin_dport = ntohs(udp->uh_dport); |
1514 | } |
1515 | |
1516 | return 0; |
1517 | } |
1518 | |
1519 | |
1520 | /* ------------------------------------------------------------------------ */ |
1521 | /* Function: ipf_pr_tcp */ |
1522 | /* Returns: void */ |
1523 | /* Parameters: fin(I) - pointer to packet information */ |
1524 | /* */ |
1525 | /* IPv4 Only */ |
1526 | /* Analyse the packet for IPv4/TCP properties. */ |
1527 | /* ------------------------------------------------------------------------ */ |
1528 | static INLINE void |
1529 | ipf_pr_tcp(fr_info_t *fin) |
1530 | { |
1531 | |
1532 | ipf_pr_short(fin, sizeof(tcphdr_t)); |
1533 | |
1534 | if (ipf_pr_tcpcommon(fin) == 0) |
1535 | ipf_checkv4sum(fin); |
1536 | } |
1537 | |
1538 | |
1539 | /* ------------------------------------------------------------------------ */ |
1540 | /* Function: ipf_pr_udp */ |
1541 | /* Returns: void */ |
1542 | /* Parameters: fin(I) - pointer to packet information */ |
1543 | /* */ |
1544 | /* IPv4 Only */ |
1545 | /* Analyse the packet for IPv4/UDP properties. */ |
1546 | /* ------------------------------------------------------------------------ */ |
1547 | static INLINE void |
1548 | ipf_pr_udp(fr_info_t *fin) |
1549 | { |
1550 | |
1551 | ipf_pr_short(fin, sizeof(udphdr_t)); |
1552 | |
1553 | if (ipf_pr_udpcommon(fin) == 0) |
1554 | ipf_checkv4sum(fin); |
1555 | } |
1556 | |
1557 | |
1558 | /* ------------------------------------------------------------------------ */ |
1559 | /* Function: ipf_pr_esp */ |
1560 | /* Returns: void */ |
1561 | /* Parameters: fin(I) - pointer to packet information */ |
1562 | /* */ |
1563 | /* Analyse the packet for ESP properties. */ |
1564 | /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ |
1565 | /* even though the newer ESP packets must also have a sequence number that */ |
1566 | /* is 32bits as well, it is not possible(?) to determine the version from a */ |
1567 | /* simple packet header. */ |
1568 | /* ------------------------------------------------------------------------ */ |
1569 | static INLINE void |
1570 | ipf_pr_esp(fr_info_t *fin) |
1571 | { |
1572 | |
1573 | if (fin->fin_off == 0) { |
1574 | ipf_pr_short(fin, 8); |
1575 | if (ipf_pr_pullup(fin, 8) == -1) { |
1576 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1577 | |
1578 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup); |
1579 | } |
1580 | } |
1581 | } |
1582 | |
1583 | |
1584 | /* ------------------------------------------------------------------------ */ |
1585 | /* Function: ipf_pr_ah */ |
1586 | /* Returns: int - value of the next header or IPPROTO_NONE if error */ |
1587 | /* Parameters: fin(I) - pointer to packet information */ |
1588 | /* */ |
1589 | /* Analyse the packet for AH properties. */ |
1590 | /* The minimum length is taken to be the combination of all fields in the */ |
1591 | /* header being present and no authentication data (null algorithm used.) */ |
1592 | /* ------------------------------------------------------------------------ */ |
1593 | static INLINE int |
1594 | ipf_pr_ah(fr_info_t *fin) |
1595 | { |
1596 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1597 | authhdr_t *ah; |
1598 | int len; |
1599 | |
1600 | fin->fin_flx |= FI_AH; |
1601 | ipf_pr_short(fin, sizeof(*ah)); |
1602 | |
1603 | if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) { |
1604 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad); |
1605 | return IPPROTO_NONE; |
1606 | } |
1607 | |
1608 | if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) { |
1609 | DT(fr_v4_ah_pullup_1); |
1610 | LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); |
1611 | return IPPROTO_NONE; |
1612 | } |
1613 | |
1614 | ah = (authhdr_t *)fin->fin_dp; |
1615 | |
1616 | len = (ah->ah_plen + 2) << 2; |
1617 | ipf_pr_short(fin, len); |
1618 | if (ipf_pr_pullup(fin, len) == -1) { |
1619 | DT(fr_v4_ah_pullup_2); |
1620 | LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); |
1621 | return IPPROTO_NONE; |
1622 | } |
1623 | |
1624 | /* |
1625 | * Adjust fin_dp and fin_dlen for skipping over the authentication |
1626 | * header. |
1627 | */ |
1628 | fin->fin_dp = (char *)fin->fin_dp + len; |
1629 | fin->fin_dlen -= len; |
1630 | return ah->ah_next; |
1631 | } |
1632 | |
1633 | |
1634 | /* ------------------------------------------------------------------------ */ |
1635 | /* Function: ipf_pr_gre */ |
1636 | /* Returns: void */ |
1637 | /* Parameters: fin(I) - pointer to packet information */ |
1638 | /* */ |
1639 | /* Analyse the packet for GRE properties. */ |
1640 | /* ------------------------------------------------------------------------ */ |
1641 | static INLINE void |
1642 | ipf_pr_gre(fr_info_t *fin) |
1643 | { |
1644 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1645 | grehdr_t *gre; |
1646 | |
1647 | ipf_pr_short(fin, sizeof(grehdr_t)); |
1648 | |
1649 | if (fin->fin_off != 0) { |
1650 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag); |
1651 | return; |
1652 | } |
1653 | |
1654 | if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { |
1655 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup); |
1656 | return; |
1657 | } |
1658 | |
1659 | gre = fin->fin_dp; |
1660 | if (GRE_REV(gre->gr_flags) == 1) |
1661 | fin->fin_data[0] = gre->gr_call; |
1662 | } |
1663 | |
1664 | |
1665 | /* ------------------------------------------------------------------------ */ |
1666 | /* Function: ipf_pr_ipv4hdr */ |
1667 | /* Returns: void */ |
1668 | /* Parameters: fin(I) - pointer to packet information */ |
1669 | /* */ |
1670 | /* IPv4 Only */ |
1671 | /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ |
1672 | /* Check all options present and flag their presence if any exist. */ |
1673 | /* ------------------------------------------------------------------------ */ |
1674 | static INLINE void |
1675 | ipf_pr_ipv4hdr(fr_info_t *fin) |
1676 | { |
1677 | u_short optmsk = 0, secmsk = 0, auth = 0; |
1678 | int hlen, ol, mv, p, i; |
1679 | const struct optlist *op; |
1680 | u_char *s, opt; |
1681 | u_short off; |
1682 | fr_ip_t *fi; |
1683 | ip_t *ip; |
1684 | |
1685 | fi = &fin->fin_fi; |
1686 | hlen = fin->fin_hlen; |
1687 | |
1688 | ip = fin->fin_ip; |
1689 | p = ip->ip_p; |
1690 | fi->fi_p = p; |
1691 | fin->fin_crc = p; |
1692 | fi->fi_tos = ip->ip_tos; |
1693 | fin->fin_id = ip->ip_id; |
1694 | off = ntohs(ip->ip_off); |
1695 | |
1696 | /* Get both TTL and protocol */ |
1697 | fi->fi_p = ip->ip_p; |
1698 | fi->fi_ttl = ip->ip_ttl; |
1699 | |
1700 | /* Zero out bits not used in IPv6 address */ |
1701 | fi->fi_src.i6[1] = 0; |
1702 | fi->fi_src.i6[2] = 0; |
1703 | fi->fi_src.i6[3] = 0; |
1704 | fi->fi_dst.i6[1] = 0; |
1705 | fi->fi_dst.i6[2] = 0; |
1706 | fi->fi_dst.i6[3] = 0; |
1707 | |
1708 | fi->fi_saddr = ip->ip_src.s_addr; |
1709 | fin->fin_crc += fi->fi_saddr; |
1710 | fi->fi_daddr = ip->ip_dst.s_addr; |
1711 | fin->fin_crc += fi->fi_daddr; |
1712 | if (IN_CLASSD(ntohl(fi->fi_daddr))) |
1713 | fin->fin_flx |= FI_MULTICAST|FI_MBCAST; |
1714 | |
1715 | /* |
1716 | * set packet attribute flags based on the offset and |
1717 | * calculate the byte offset that it represents. |
1718 | */ |
1719 | off &= IP_MF|IP_OFFMASK; |
1720 | if (off != 0) { |
1721 | int morefrag = off & IP_MF; |
1722 | |
1723 | fi->fi_flx |= FI_FRAG; |
1724 | off &= IP_OFFMASK; |
1725 | if (off != 0) { |
1726 | fin->fin_flx |= FI_FRAGBODY; |
1727 | off <<= 3; |
1728 | if ((off + fin->fin_dlen > 65535) || |
1729 | (fin->fin_dlen == 0) || |
1730 | ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { |
1731 | /* |
1732 | * The length of the packet, starting at its |
1733 | * offset cannot exceed 65535 (0xffff) as the |
1734 | * length of an IP packet is only 16 bits. |
1735 | * |
1736 | * Any fragment that isn't the last fragment |
1737 | * must have a length greater than 0 and it |
1738 | * must be an even multiple of 8. |
1739 | */ |
1740 | fi->fi_flx |= FI_BAD; |
1741 | DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); |
1742 | } |
1743 | } |
1744 | } |
1745 | fin->fin_off = off; |
1746 | |
1747 | /* |
1748 | * Call per-protocol setup and checking |
1749 | */ |
1750 | if (p == IPPROTO_AH) { |
1751 | /* |
1752 | * Treat AH differently because we expect there to be another |
1753 | * layer 4 header after it. |
1754 | */ |
1755 | p = ipf_pr_ah(fin); |
1756 | } |
1757 | |
1758 | switch (p) |
1759 | { |
1760 | case IPPROTO_UDP : |
1761 | ipf_pr_udp(fin); |
1762 | break; |
1763 | case IPPROTO_TCP : |
1764 | ipf_pr_tcp(fin); |
1765 | break; |
1766 | case IPPROTO_ICMP : |
1767 | ipf_pr_icmp(fin); |
1768 | break; |
1769 | case IPPROTO_ESP : |
1770 | ipf_pr_esp(fin); |
1771 | break; |
1772 | case IPPROTO_GRE : |
1773 | ipf_pr_gre(fin); |
1774 | break; |
1775 | } |
1776 | |
1777 | ip = fin->fin_ip; |
1778 | if (ip == NULL) |
1779 | return; |
1780 | |
1781 | /* |
1782 | * If it is a standard IP header (no options), set the flag fields |
1783 | * which relate to options to 0. |
1784 | */ |
1785 | if (hlen == sizeof(*ip)) { |
1786 | fi->fi_optmsk = 0; |
1787 | fi->fi_secmsk = 0; |
1788 | fi->fi_auth = 0; |
1789 | return; |
1790 | } |
1791 | |
1792 | /* |
1793 | * So the IP header has some IP options attached. Walk the entire |
1794 | * list of options present with this packet and set flags to indicate |
1795 | * which ones are here and which ones are not. For the somewhat out |
1796 | * of date and obscure security classification options, set a flag to |
1797 | * represent which classification is present. |
1798 | */ |
1799 | fi->fi_flx |= FI_OPTIONS; |
1800 | |
1801 | for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { |
1802 | opt = *s; |
1803 | if (opt == '\0') |
1804 | break; |
1805 | else if (opt == IPOPT_NOP) |
1806 | ol = 1; |
1807 | else { |
1808 | if (hlen < 2) |
1809 | break; |
1810 | ol = (int)*(s + 1); |
1811 | if (ol < 2 || ol > hlen) |
1812 | break; |
1813 | } |
1814 | for (i = 9, mv = 4; mv >= 0; ) { |
1815 | op = ipopts + i; |
1816 | |
1817 | if ((opt == (u_char)op->ol_val) && (ol > 4)) { |
1818 | u_32_t doi; |
1819 | |
1820 | switch (opt) |
1821 | { |
1822 | case IPOPT_SECURITY : |
1823 | if (optmsk & op->ol_bit) { |
1824 | fin->fin_flx |= FI_BAD; |
1825 | DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); |
1826 | } else { |
1827 | doi = ipf_checkripso(s); |
1828 | secmsk = doi >> 16; |
1829 | auth = doi & 0xffff; |
1830 | } |
1831 | break; |
1832 | |
1833 | case IPOPT_CIPSO : |
1834 | |
1835 | if (optmsk & op->ol_bit) { |
1836 | fin->fin_flx |= FI_BAD; |
1837 | DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); |
1838 | } else { |
1839 | doi = ipf_checkcipso(fin, |
1840 | s, ol); |
1841 | secmsk = doi >> 16; |
1842 | auth = doi & 0xffff; |
1843 | } |
1844 | break; |
1845 | } |
1846 | optmsk |= op->ol_bit; |
1847 | } |
1848 | |
1849 | if (opt < op->ol_val) |
1850 | i -= mv; |
1851 | else |
1852 | i += mv; |
1853 | mv--; |
1854 | } |
1855 | hlen -= ol; |
1856 | s += ol; |
1857 | } |
1858 | |
1859 | /* |
1860 | * |
1861 | */ |
1862 | if (auth && !(auth & 0x0100)) |
1863 | auth &= 0xff00; |
1864 | fi->fi_optmsk = optmsk; |
1865 | fi->fi_secmsk = secmsk; |
1866 | fi->fi_auth = auth; |
1867 | } |
1868 | |
1869 | |
1870 | /* ------------------------------------------------------------------------ */ |
1871 | /* Function: ipf_checkripso */ |
1872 | /* Returns: void */ |
1873 | /* Parameters: s(I) - pointer to start of RIPSO option */ |
1874 | /* */ |
1875 | /* ------------------------------------------------------------------------ */ |
1876 | static u_32_t |
1877 | ipf_checkripso(u_char *s) |
1878 | { |
1879 | const struct optlist *sp; |
1880 | u_short secmsk = 0, auth = 0; |
1881 | u_char sec; |
1882 | int j, m; |
1883 | |
1884 | sec = *(s + 2); /* classification */ |
1885 | for (j = 3, m = 2; m >= 0; ) { |
1886 | sp = secopt + j; |
1887 | if (sec == sp->ol_val) { |
1888 | secmsk |= sp->ol_bit; |
1889 | auth = *(s + 3); |
1890 | auth *= 256; |
1891 | auth += *(s + 4); |
1892 | break; |
1893 | } |
1894 | if (sec < sp->ol_val) |
1895 | j -= m; |
1896 | else |
1897 | j += m; |
1898 | m--; |
1899 | } |
1900 | |
1901 | return (secmsk << 16) | auth; |
1902 | } |
1903 | |
1904 | |
1905 | /* ------------------------------------------------------------------------ */ |
1906 | /* Function: ipf_checkcipso */ |
1907 | /* Returns: u_32_t - 0 = failure, else the doi from the header */ |
1908 | /* Parameters: fin(IO) - pointer to packet information */ |
1909 | /* s(I) - pointer to start of CIPSO option */ |
1910 | /* ol(I) - length of CIPSO option field */ |
1911 | /* */ |
1912 | /* This function returns the domain of integrity (DOI) field from the CIPSO */ |
1913 | /* header and returns that whilst also storing the highest sensitivity */ |
1914 | /* value found in the fr_info_t structure. */ |
1915 | /* */ |
1916 | /* No attempt is made to extract the category bitmaps as these are defined */ |
1917 | /* by the user (rather than the protocol) and can be rather numerous on the */ |
1918 | /* end nodes. */ |
1919 | /* ------------------------------------------------------------------------ */ |
1920 | static u_32_t |
1921 | ipf_checkcipso(fr_info_t *fin, u_char *s, int ol) |
1922 | { |
1923 | ipf_main_softc_t *softc = fin->fin_main_soft; |
1924 | fr_ip_t *fi; |
1925 | u_32_t doi; |
1926 | u_char *t, tag, tlen, sensitivity; |
1927 | int len; |
1928 | |
1929 | if (ol < 6 || ol > 40) { |
1930 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad); |
1931 | fin->fin_flx |= FI_BAD; |
1932 | DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol); |
1933 | return 0; |
1934 | } |
1935 | |
1936 | fi = &fin->fin_fi; |
1937 | fi->fi_sensitivity = 0; |
1938 | /* |
1939 | * The DOI field MUST be there. |
1940 | */ |
1941 | bcopy(s + 2, &doi, sizeof(doi)); |
1942 | |
1943 | t = (u_char *)s + 6; |
1944 | for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) { |
1945 | tag = *t; |
1946 | tlen = *(t + 1); |
1947 | if (tlen > len || tlen < 4 || tlen > 34) { |
1948 | LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen); |
1949 | fin->fin_flx |= FI_BAD; |
1950 | DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen); |
1951 | return 0; |
1952 | } |
1953 | |
1954 | sensitivity = 0; |
1955 | /* |
1956 | * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet |
1957 | * draft (16 July 1992) that has expired. |
1958 | */ |
1959 | if (tag == 0) { |
1960 | fin->fin_flx |= FI_BAD; |
1961 | DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag); |
1962 | continue; |
1963 | } else if (tag == 1) { |
1964 | if (*(t + 2) != 0) { |
1965 | fin->fin_flx |= FI_BAD; |
1966 | DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2)); |
1967 | continue; |
1968 | } |
1969 | sensitivity = *(t + 3); |
1970 | /* Category bitmap for categories 0-239 */ |
1971 | |
1972 | } else if (tag == 4) { |
1973 | if (*(t + 2) != 0) { |
1974 | fin->fin_flx |= FI_BAD; |
1975 | DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2)); |
1976 | continue; |
1977 | } |
1978 | sensitivity = *(t + 3); |
1979 | /* Enumerated categories, 16bits each, upto 15 */ |
1980 | |
1981 | } else if (tag == 5) { |
1982 | if (*(t + 2) != 0) { |
1983 | fin->fin_flx |= FI_BAD; |
1984 | DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2)); |
1985 | continue; |
1986 | } |
1987 | sensitivity = *(t + 3); |
1988 | /* Range of categories (2*16bits), up to 7 pairs */ |
1989 | |
1990 | } else if (tag > 127) { |
1991 | /* Custom defined DOI */ |
1992 | ; |
1993 | } else { |
1994 | DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag); |
1995 | fin->fin_flx |= FI_BAD; |
1996 | continue; |
1997 | } |
1998 | |
1999 | if (sensitivity > fi->fi_sensitivity) |
2000 | fi->fi_sensitivity = sensitivity; |
2001 | } |
2002 | |
2003 | return doi; |
2004 | } |
2005 | |
2006 | |
2007 | /* ------------------------------------------------------------------------ */ |
2008 | /* Function: ipf_makefrip */ |
2009 | /* Returns: int - 0 == packet ok, -1 == packet freed */ |
2010 | /* Parameters: hlen(I) - length of IP packet header */ |
2011 | /* ip(I) - pointer to the IP header */ |
2012 | /* fin(IO) - pointer to packet information */ |
2013 | /* */ |
2014 | /* Compact the IP header into a structure which contains just the info. */ |
2015 | /* which is useful for comparing IP headers with and store this information */ |
2016 | /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ |
2017 | /* this function will be called with either an IPv4 or IPv6 packet. */ |
2018 | /* ------------------------------------------------------------------------ */ |
2019 | int |
2020 | ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin) |
2021 | { |
2022 | ipf_main_softc_t *softc = fin->fin_main_soft; |
2023 | int v; |
2024 | |
2025 | fin->fin_depth = 0; |
2026 | fin->fin_hlen = (u_short)hlen; |
2027 | fin->fin_ip = ip; |
2028 | fin->fin_rule = 0xffffffff; |
2029 | fin->fin_group[0] = -1; |
2030 | fin->fin_group[1] = '\0'; |
2031 | fin->fin_dp = (char *)ip + hlen; |
2032 | |
2033 | v = fin->fin_v; |
2034 | if (v == 4) { |
2035 | fin->fin_plen = ntohs(ip->ip_len); |
2036 | fin->fin_dlen = fin->fin_plen - hlen; |
2037 | ipf_pr_ipv4hdr(fin); |
2038 | #ifdef USE_INET6 |
2039 | } else if (v == 6) { |
2040 | fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); |
2041 | fin->fin_dlen = fin->fin_plen; |
2042 | fin->fin_plen += hlen; |
2043 | |
2044 | ipf_pr_ipv6hdr(fin); |
2045 | #endif |
2046 | } |
2047 | if (fin->fin_ip == NULL) { |
2048 | LBUMP(ipf_stats[fin->fin_out].fr_ip_freed); |
2049 | return -1; |
2050 | } |
2051 | return 0; |
2052 | } |
2053 | |
2054 | |
2055 | /* ------------------------------------------------------------------------ */ |
2056 | /* Function: ipf_portcheck */ |
2057 | /* Returns: int - 1 == port matched, 0 == port match failed */ |
2058 | /* Parameters: frp(I) - pointer to port check `expression' */ |
2059 | /* pop(I) - port number to evaluate */ |
2060 | /* */ |
2061 | /* Perform a comparison of a port number against some other(s), using a */ |
2062 | /* structure with compare information stored in it. */ |
2063 | /* ------------------------------------------------------------------------ */ |
2064 | static INLINE int |
2065 | ipf_portcheck(frpcmp_t *frp, u_32_t pop) |
2066 | { |
2067 | int err = 1; |
2068 | u_32_t po; |
2069 | |
2070 | po = frp->frp_port; |
2071 | |
2072 | /* |
2073 | * Do opposite test to that required and continue if that succeeds. |
2074 | */ |
2075 | switch (frp->frp_cmp) |
2076 | { |
2077 | case FR_EQUAL : |
2078 | if (pop != po) /* EQUAL */ |
2079 | err = 0; |
2080 | break; |
2081 | case FR_NEQUAL : |
2082 | if (pop == po) /* NOTEQUAL */ |
2083 | err = 0; |
2084 | break; |
2085 | case FR_LESST : |
2086 | if (pop >= po) /* LESSTHAN */ |
2087 | err = 0; |
2088 | break; |
2089 | case FR_GREATERT : |
2090 | if (pop <= po) /* GREATERTHAN */ |
2091 | err = 0; |
2092 | break; |
2093 | case FR_LESSTE : |
2094 | if (pop > po) /* LT or EQ */ |
2095 | err = 0; |
2096 | break; |
2097 | case FR_GREATERTE : |
2098 | if (pop < po) /* GT or EQ */ |
2099 | err = 0; |
2100 | break; |
2101 | case FR_OUTRANGE : |
2102 | if (pop >= po && pop <= frp->frp_top) /* Out of range */ |
2103 | err = 0; |
2104 | break; |
2105 | case FR_INRANGE : |
2106 | if (pop <= po || pop >= frp->frp_top) /* In range */ |
2107 | err = 0; |
2108 | break; |
2109 | case FR_INCRANGE : |
2110 | if (pop < po || pop > frp->frp_top) /* Inclusive range */ |
2111 | err = 0; |
2112 | break; |
2113 | default : |
2114 | break; |
2115 | } |
2116 | return err; |
2117 | } |
2118 | |
2119 | |
2120 | /* ------------------------------------------------------------------------ */ |
2121 | /* Function: ipf_tcpudpchk */ |
2122 | /* Returns: int - 1 == protocol matched, 0 == check failed */ |
2123 | /* Parameters: fda(I) - pointer to packet information */ |
2124 | /* ft(I) - pointer to structure with comparison data */ |
2125 | /* */ |
2126 | /* Compares the current pcket (assuming it is TCP/UDP) information with a */ |
2127 | /* structure containing information that we want to match against. */ |
2128 | /* ------------------------------------------------------------------------ */ |
2129 | int |
2130 | ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft) |
2131 | { |
2132 | int err = 1; |
2133 | |
2134 | /* |
2135 | * Both ports should *always* be in the first fragment. |
2136 | * So far, I cannot find any cases where they can not be. |
2137 | * |
2138 | * compare destination ports |
2139 | */ |
2140 | if (ft->ftu_dcmp) |
2141 | err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]); |
2142 | |
2143 | /* |
2144 | * compare source ports |
2145 | */ |
2146 | if (err && ft->ftu_scmp) |
2147 | err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]); |
2148 | |
2149 | /* |
2150 | * If we don't have all the TCP/UDP header, then how can we |
2151 | * expect to do any sort of match on it ? If we were looking for |
2152 | * TCP flags, then NO match. If not, then match (which should |
2153 | * satisfy the "short" class too). |
2154 | */ |
2155 | if (err && (fi->fi_p == IPPROTO_TCP)) { |
2156 | if (fi->fi_flx & FI_SHORT) |
2157 | return !(ft->ftu_tcpf | ft->ftu_tcpfm); |
2158 | /* |
2159 | * Match the flags ? If not, abort this match. |
2160 | */ |
2161 | if (ft->ftu_tcpfm && |
2162 | ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) { |
2163 | FR_DEBUG(("f. %#x & %#x != %#x\n" , fi->fi_tcpf, |
2164 | ft->ftu_tcpfm, ft->ftu_tcpf)); |
2165 | err = 0; |
2166 | } |
2167 | } |
2168 | return err; |
2169 | } |
2170 | |
2171 | |
2172 | /* ------------------------------------------------------------------------ */ |
2173 | /* Function: ipf_check_ipf */ |
2174 | /* Returns: int - 0 == match, else no match */ |
2175 | /* Parameters: fin(I) - pointer to packet information */ |
2176 | /* fr(I) - pointer to filter rule */ |
2177 | /* portcmp(I) - flag indicating whether to attempt matching on */ |
2178 | /* TCP/UDP port data. */ |
2179 | /* */ |
2180 | /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ |
2181 | /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ |
2182 | /* this function. */ |
2183 | /* ------------------------------------------------------------------------ */ |
2184 | static INLINE int |
2185 | ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp) |
2186 | { |
2187 | u_32_t *ld, *lm, *lip; |
2188 | fripf_t *fri; |
2189 | fr_ip_t *fi; |
2190 | int i; |
2191 | |
2192 | fi = &fin->fin_fi; |
2193 | fri = fr->fr_ipf; |
2194 | lip = (u_32_t *)fi; |
2195 | lm = (u_32_t *)&fri->fri_mip; |
2196 | ld = (u_32_t *)&fri->fri_ip; |
2197 | |
2198 | /* |
2199 | * first 32 bits to check coversion: |
2200 | * IP version, TOS, TTL, protocol |
2201 | */ |
2202 | i = ((*lip & *lm) != *ld); |
2203 | FR_DEBUG(("0. %#08x & %#08x != %#08x\n" , |
2204 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2205 | if (i) |
2206 | return 1; |
2207 | |
2208 | /* |
2209 | * Next 32 bits is a constructed bitmask indicating which IP options |
2210 | * are present (if any) in this packet. |
2211 | */ |
2212 | lip++, lm++, ld++; |
2213 | i = ((*lip & *lm) != *ld); |
2214 | FR_DEBUG(("1. %#08x & %#08x != %#08x\n" , |
2215 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2216 | if (i != 0) |
2217 | return 1; |
2218 | |
2219 | lip++, lm++, ld++; |
2220 | /* |
2221 | * Unrolled loops (4 each, for 32 bits) for address checks. |
2222 | */ |
2223 | /* |
2224 | * Check the source address. |
2225 | */ |
2226 | if (fr->fr_satype == FRI_LOOKUP) { |
2227 | i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr, |
2228 | fi->fi_v, lip, fin->fin_plen); |
2229 | if (i == -1) |
2230 | return 1; |
2231 | lip += 3; |
2232 | lm += 3; |
2233 | ld += 3; |
2234 | } else { |
2235 | i = ((*lip & *lm) != *ld); |
2236 | FR_DEBUG(("2a. %#08x & %#08x != %#08x\n" , |
2237 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2238 | if (fi->fi_v == 6) { |
2239 | lip++, lm++, ld++; |
2240 | i |= ((*lip & *lm) != *ld); |
2241 | FR_DEBUG(("2b. %#08x & %#08x != %#08x\n" , |
2242 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2243 | lip++, lm++, ld++; |
2244 | i |= ((*lip & *lm) != *ld); |
2245 | FR_DEBUG(("2c. %#08x & %#08x != %#08x\n" , |
2246 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2247 | lip++, lm++, ld++; |
2248 | i |= ((*lip & *lm) != *ld); |
2249 | FR_DEBUG(("2d. %#08x & %#08x != %#08x\n" , |
2250 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2251 | } else { |
2252 | lip += 3; |
2253 | lm += 3; |
2254 | ld += 3; |
2255 | } |
2256 | } |
2257 | i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; |
2258 | if (i != 0) |
2259 | return 1; |
2260 | |
2261 | /* |
2262 | * Check the destination address. |
2263 | */ |
2264 | lip++, lm++, ld++; |
2265 | if (fr->fr_datype == FRI_LOOKUP) { |
2266 | i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr, |
2267 | fi->fi_v, lip, fin->fin_plen); |
2268 | if (i == -1) |
2269 | return 1; |
2270 | lip += 3; |
2271 | lm += 3; |
2272 | ld += 3; |
2273 | } else { |
2274 | i = ((*lip & *lm) != *ld); |
2275 | FR_DEBUG(("3a. %#08x & %#08x != %#08x\n" , |
2276 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2277 | if (fi->fi_v == 6) { |
2278 | lip++, lm++, ld++; |
2279 | i |= ((*lip & *lm) != *ld); |
2280 | FR_DEBUG(("3b. %#08x & %#08x != %#08x\n" , |
2281 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2282 | lip++, lm++, ld++; |
2283 | i |= ((*lip & *lm) != *ld); |
2284 | FR_DEBUG(("3c. %#08x & %#08x != %#08x\n" , |
2285 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2286 | lip++, lm++, ld++; |
2287 | i |= ((*lip & *lm) != *ld); |
2288 | FR_DEBUG(("3d. %#08x & %#08x != %#08x\n" , |
2289 | ntohl(*lip), ntohl(*lm), ntohl(*ld))); |
2290 | } else { |
2291 | lip += 3; |
2292 | lm += 3; |
2293 | ld += 3; |
2294 | } |
2295 | } |
2296 | i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; |
2297 | if (i != 0) |
2298 | return 1; |
2299 | /* |
2300 | * IP addresses matched. The next 32bits contains: |
2301 | * mast of old IP header security & authentication bits. |
2302 | */ |
2303 | lip++, lm++, ld++; |
2304 | i = (*ld - (*lip & *lm)); |
2305 | FR_DEBUG(("4. %#08x & %#08x != %#08x\n" , *lip, *lm, *ld)); |
2306 | |
2307 | /* |
2308 | * Next we have 32 bits of packet flags. |
2309 | */ |
2310 | lip++, lm++, ld++; |
2311 | i |= (*ld - (*lip & *lm)); |
2312 | FR_DEBUG(("5. %#08x & %#08x != %#08x\n" , *lip, *lm, *ld)); |
2313 | |
2314 | if (i == 0) { |
2315 | /* |
2316 | * If a fragment, then only the first has what we're |
2317 | * looking for here... |
2318 | */ |
2319 | if (portcmp) { |
2320 | if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc)) |
2321 | i = 1; |
2322 | } else { |
2323 | if (fr->fr_dcmp || fr->fr_scmp || |
2324 | fr->fr_tcpf || fr->fr_tcpfm) |
2325 | i = 1; |
2326 | if (fr->fr_icmpm || fr->fr_icmp) { |
2327 | if (((fi->fi_p != IPPROTO_ICMP) && |
2328 | (fi->fi_p != IPPROTO_ICMPV6)) || |
2329 | fin->fin_off || (fin->fin_dlen < 2)) |
2330 | i = 1; |
2331 | else if ((fin->fin_data[0] & fr->fr_icmpm) != |
2332 | fr->fr_icmp) { |
2333 | FR_DEBUG(("i. %#x & %#x != %#x\n" , |
2334 | fin->fin_data[0], |
2335 | fr->fr_icmpm, fr->fr_icmp)); |
2336 | i = 1; |
2337 | } |
2338 | } |
2339 | } |
2340 | } |
2341 | return i; |
2342 | } |
2343 | |
2344 | |
2345 | /* ------------------------------------------------------------------------ */ |
2346 | /* Function: ipf_scanlist */ |
2347 | /* Returns: int - result flags of scanning filter list */ |
2348 | /* Parameters: fin(I) - pointer to packet information */ |
2349 | /* pass(I) - default result to return for filtering */ |
2350 | /* */ |
2351 | /* Check the input/output list of rules for a match to the current packet. */ |
2352 | /* If a match is found, the value of fr_flags from the rule becomes the */ |
2353 | /* return value and fin->fin_fr points to the matched rule. */ |
2354 | /* */ |
2355 | /* This function may be called recusively upto 16 times (limit inbuilt.) */ |
2356 | /* When unwinding, it should finish up with fin_depth as 0. */ |
2357 | /* */ |
2358 | /* Could be per interface, but this gets real nasty when you don't have, */ |
2359 | /* or can't easily change, the kernel source code to . */ |
2360 | /* ------------------------------------------------------------------------ */ |
2361 | int |
2362 | ipf_scanlist(fr_info_t *fin, u_32_t pass) |
2363 | { |
2364 | ipf_main_softc_t *softc = fin->fin_main_soft; |
2365 | int rulen, portcmp, off, skip; |
2366 | struct frentry *fr, *fnext; |
2367 | u_32_t passt, passo; |
2368 | |
2369 | /* |
2370 | * Do not allow nesting deeper than 16 levels. |
2371 | */ |
2372 | if (fin->fin_depth >= 16) |
2373 | return pass; |
2374 | |
2375 | fr = fin->fin_fr; |
2376 | |
2377 | /* |
2378 | * If there are no rules in this list, return now. |
2379 | */ |
2380 | if (fr == NULL) |
2381 | return pass; |
2382 | |
2383 | skip = 0; |
2384 | portcmp = 0; |
2385 | fin->fin_depth++; |
2386 | fin->fin_fr = NULL; |
2387 | off = fin->fin_off; |
2388 | |
2389 | if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) |
2390 | portcmp = 1; |
2391 | |
2392 | for (rulen = 0; fr; fr = fnext, rulen++) { |
2393 | fnext = fr->fr_next; |
2394 | if (skip != 0) { |
2395 | FR_VERBOSE(("SKIP %d (%#x)\n" , skip, fr->fr_flags)); |
2396 | skip--; |
2397 | continue; |
2398 | } |
2399 | |
2400 | /* |
2401 | * In all checks below, a null (zero) value in the |
2402 | * filter struture is taken to mean a wildcard. |
2403 | * |
2404 | * check that we are working for the right interface |
2405 | */ |
2406 | #ifdef _KERNEL |
2407 | if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) |
2408 | continue; |
2409 | #else |
2410 | if (opts & (OPT_VERBOSE|OPT_DEBUG)) |
2411 | printf("\n" ); |
2412 | FR_VERBOSE(("%c" , FR_ISSKIP(pass) ? 's' : |
2413 | FR_ISPASS(pass) ? 'p' : |
2414 | FR_ISACCOUNT(pass) ? 'A' : |
2415 | FR_ISAUTH(pass) ? 'a' : |
2416 | (pass & FR_NOMATCH) ? 'n' :'b')); |
2417 | if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) |
2418 | continue; |
2419 | FR_VERBOSE((":i" )); |
2420 | #endif |
2421 | |
2422 | switch (fr->fr_type) |
2423 | { |
2424 | case FR_T_IPF : |
2425 | case FR_T_IPF_BUILTIN : |
2426 | if (ipf_check_ipf(fin, fr, portcmp)) |
2427 | continue; |
2428 | break; |
2429 | #if defined(IPFILTER_BPF) |
2430 | case FR_T_BPFOPC : |
2431 | case FR_T_BPFOPC_BUILTIN : |
2432 | { |
2433 | u_char *mc; |
2434 | int wlen; |
2435 | |
2436 | if (*fin->fin_mp == NULL) |
2437 | continue; |
2438 | if (fin->fin_family != fr->fr_family) |
2439 | continue; |
2440 | mc = (u_char *)fin->fin_m; |
2441 | wlen = fin->fin_dlen + fin->fin_hlen; |
2442 | if (!bpf_filter(fr->fr_data, mc, wlen, 0)) |
2443 | continue; |
2444 | break; |
2445 | } |
2446 | #endif |
2447 | case FR_T_CALLFUNC_BUILTIN : |
2448 | { |
2449 | frentry_t *f; |
2450 | |
2451 | f = (*fr->fr_func)(fin, &pass); |
2452 | if (f != NULL) |
2453 | fr = f; |
2454 | else |
2455 | continue; |
2456 | break; |
2457 | } |
2458 | |
2459 | case FR_T_IPFEXPR : |
2460 | case FR_T_IPFEXPR_BUILTIN : |
2461 | if (fin->fin_family != fr->fr_family) |
2462 | continue; |
2463 | if (ipf_fr_matcharray(fin, fr->fr_data) == 0) |
2464 | continue; |
2465 | break; |
2466 | |
2467 | default : |
2468 | break; |
2469 | } |
2470 | |
2471 | if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { |
2472 | if (fin->fin_nattag == NULL) |
2473 | continue; |
2474 | if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) |
2475 | continue; |
2476 | } |
2477 | FR_VERBOSE(("=%d/%d.%d *" , fr->fr_grhead, fr->fr_group, rulen)); |
2478 | |
2479 | passt = fr->fr_flags; |
2480 | |
2481 | /* |
2482 | * If the rule is a "call now" rule, then call the function |
2483 | * in the rule, if it exists and use the results from that. |
2484 | * If the function pointer is bad, just make like we ignore |
2485 | * it, except for increasing the hit counter. |
2486 | */ |
2487 | if ((passt & FR_CALLNOW) != 0) { |
2488 | frentry_t *frs; |
2489 | |
2490 | ATOMIC_INC64(fr->fr_hits); |
2491 | if ((fr->fr_func == NULL) || |
2492 | (fr->fr_func == (ipfunc_t)-1)) |
2493 | continue; |
2494 | |
2495 | frs = fin->fin_fr; |
2496 | fin->fin_fr = fr; |
2497 | fr = (*fr->fr_func)(fin, &passt); |
2498 | if (fr == NULL) { |
2499 | fin->fin_fr = frs; |
2500 | continue; |
2501 | } |
2502 | passt = fr->fr_flags; |
2503 | } |
2504 | fin->fin_fr = fr; |
2505 | |
2506 | #ifdef IPFILTER_LOG |
2507 | /* |
2508 | * Just log this packet... |
2509 | */ |
2510 | if ((passt & FR_LOGMASK) == FR_LOG) { |
2511 | if (ipf_log_pkt(fin, passt) == -1) { |
2512 | if (passt & FR_LOGORBLOCK) { |
2513 | DT(frb_logfail); |
2514 | passt &= ~FR_CMDMASK; |
2515 | passt |= FR_BLOCK|FR_QUICK; |
2516 | fin->fin_reason = FRB_LOGFAIL; |
2517 | } |
2518 | } |
2519 | } |
2520 | #endif /* IPFILTER_LOG */ |
2521 | |
2522 | MUTEX_ENTER(&fr->fr_lock); |
2523 | fr->fr_bytes += (U_QUAD_T)fin->fin_plen; |
2524 | fr->fr_hits++; |
2525 | MUTEX_EXIT(&fr->fr_lock); |
2526 | fin->fin_rule = rulen; |
2527 | |
2528 | passo = pass; |
2529 | if (FR_ISSKIP(passt)) { |
2530 | skip = fr->fr_arg; |
2531 | continue; |
2532 | } else if (((passt & FR_LOGMASK) != FR_LOG) && |
2533 | ((passt & FR_LOGMASK) != FR_DECAPSULATE)) { |
2534 | pass = passt; |
2535 | } |
2536 | |
2537 | if (passt & (FR_RETICMP|FR_FAKEICMP)) |
2538 | fin->fin_icode = fr->fr_icode; |
2539 | |
2540 | if (fr->fr_group != -1) { |
2541 | (void) strncpy(fin->fin_group, |
2542 | FR_NAME(fr, fr_group), |
2543 | strlen(FR_NAME(fr, fr_group))); |
2544 | } else { |
2545 | fin->fin_group[0] = '\0'; |
2546 | } |
2547 | |
2548 | FR_DEBUG(("pass %#x/%#x/%x\n" , passo, pass, passt)); |
2549 | |
2550 | if (fr->fr_grphead != NULL) { |
2551 | fin->fin_fr = fr->fr_grphead->fg_start; |
2552 | FR_VERBOSE(("group %s\n" , FR_NAME(fr, fr_grhead))); |
2553 | |
2554 | if (FR_ISDECAPS(passt)) |
2555 | passt = ipf_decaps(fin, pass, fr->fr_icode); |
2556 | else |
2557 | passt = ipf_scanlist(fin, pass); |
2558 | |
2559 | if (fin->fin_fr == NULL) { |
2560 | fin->fin_rule = rulen; |
2561 | if (fr->fr_group != -1) |
2562 | (void) strncpy(fin->fin_group, |
2563 | fr->fr_names + |
2564 | fr->fr_group, |
2565 | strlen(fr->fr_names + |
2566 | fr->fr_group)); |
2567 | fin->fin_fr = fr; |
2568 | passt = pass; |
2569 | } |
2570 | pass = passt; |
2571 | } |
2572 | |
2573 | if (pass & FR_QUICK) { |
2574 | /* |
2575 | * Finally, if we've asked to track state for this |
2576 | * packet, set it up. Add state for "quick" rules |
2577 | * here so that if the action fails we can consider |
2578 | * the rule to "not match" and keep on processing |
2579 | * filter rules. |
2580 | */ |
2581 | if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) && |
2582 | !(fin->fin_flx & FI_STATE)) { |
2583 | int out = fin->fin_out; |
2584 | |
2585 | fin->fin_fr = fr; |
2586 | if (ipf_state_add(softc, fin, NULL, 0) == 0) { |
2587 | LBUMPD(ipf_stats[out], fr_ads); |
2588 | } else { |
2589 | LBUMPD(ipf_stats[out], fr_bads); |
2590 | pass = passo; |
2591 | continue; |
2592 | } |
2593 | } |
2594 | break; |
2595 | } |
2596 | } |
2597 | fin->fin_depth--; |
2598 | return pass; |
2599 | } |
2600 | |
2601 | |
2602 | /* ------------------------------------------------------------------------ */ |
2603 | /* Function: ipf_acctpkt */ |
2604 | /* Returns: frentry_t* - always returns NULL */ |
2605 | /* Parameters: fin(I) - pointer to packet information */ |
2606 | /* passp(IO) - pointer to current/new filter decision (unused) */ |
2607 | /* */ |
2608 | /* Checks a packet against accounting rules, if there are any for the given */ |
2609 | /* IP protocol version. */ |
2610 | /* */ |
2611 | /* N.B.: this function returns NULL to match the prototype used by other */ |
2612 | /* functions called from the IPFilter "mainline" in ipf_check(). */ |
2613 | /* ------------------------------------------------------------------------ */ |
2614 | frentry_t * |
2615 | ipf_acctpkt(fr_info_t *fin, u_32_t *passp) |
2616 | { |
2617 | ipf_main_softc_t *softc = fin->fin_main_soft; |
2618 | char group[FR_GROUPLEN]; |
2619 | frentry_t *fr, *frsave; |
2620 | u_32_t pass, rulen; |
2621 | |
2622 | passp = passp; |
2623 | fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; |
2624 | |
2625 | if (fr != NULL) { |
2626 | frsave = fin->fin_fr; |
2627 | bcopy(fin->fin_group, group, FR_GROUPLEN); |
2628 | rulen = fin->fin_rule; |
2629 | fin->fin_fr = fr; |
2630 | pass = ipf_scanlist(fin, FR_NOMATCH); |
2631 | if (FR_ISACCOUNT(pass)) { |
2632 | LBUMPD(ipf_stats[0], fr_acct); |
2633 | } |
2634 | fin->fin_fr = frsave; |
2635 | bcopy(group, fin->fin_group, FR_GROUPLEN); |
2636 | fin->fin_rule = rulen; |
2637 | } |
2638 | return NULL; |
2639 | } |
2640 | |
2641 | |
2642 | /* ------------------------------------------------------------------------ */ |
2643 | /* Function: ipf_firewall */ |
2644 | /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ |
2645 | /* were found, returns NULL. */ |
2646 | /* Parameters: fin(I) - pointer to packet information */ |
2647 | /* passp(IO) - pointer to current/new filter decision (unused) */ |
2648 | /* */ |
2649 | /* Applies an appropriate set of firewall rules to the packet, to see if */ |
2650 | /* there are any matches. The first check is to see if a match can be seen */ |
2651 | /* in the cache. If not, then search an appropriate list of rules. Once a */ |
2652 | /* matching rule is found, take any appropriate actions as defined by the */ |
2653 | /* rule - except logging. */ |
2654 | /* ------------------------------------------------------------------------ */ |
2655 | static frentry_t * |
2656 | ipf_firewall(fr_info_t *fin, u_32_t *passp) |
2657 | { |
2658 | ipf_main_softc_t *softc = fin->fin_main_soft; |
2659 | frentry_t *fr; |
2660 | u_32_t pass; |
2661 | int out; |
2662 | |
2663 | out = fin->fin_out; |
2664 | pass = *passp; |
2665 | |
2666 | /* |
2667 | * This rule cache will only affect packets that are not being |
2668 | * statefully filtered. |
2669 | */ |
2670 | fin->fin_fr = softc->ipf_rules[out][softc->ipf_active]; |
2671 | if (fin->fin_fr != NULL) |
2672 | pass = ipf_scanlist(fin, softc->ipf_pass); |
2673 | |
2674 | if ((pass & FR_NOMATCH)) { |
2675 | LBUMPD(ipf_stats[out], fr_nom); |
2676 | } |
2677 | fr = fin->fin_fr; |
2678 | |
2679 | /* |
2680 | * Apply packets per second rate-limiting to a rule as required. |
2681 | */ |
2682 | if ((fr != NULL) && (fr->fr_pps != 0) && |
2683 | !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { |
2684 | DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr); |
2685 | pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST); |
2686 | pass |= FR_BLOCK; |
2687 | LBUMPD(ipf_stats[out], fr_ppshit); |
2688 | fin->fin_reason = FRB_PPSRATE; |
2689 | } |
2690 | |
2691 | /* |
2692 | * If we fail to add a packet to the authorization queue, then we |
2693 | * drop the packet later. However, if it was added then pretend |
2694 | * we've dropped it already. |
2695 | */ |
2696 | if (FR_ISAUTH(pass)) { |
2697 | if (ipf_auth_new(fin->fin_m, fin) != 0) { |
2698 | DT1(frb_authnew, fr_info_t *, fin); |
2699 | fin->fin_m = *fin->fin_mp = NULL; |
2700 | fin->fin_reason = FRB_AUTHNEW; |
2701 | fin->fin_error = 0; |
2702 | } else { |
2703 | IPFERROR(1); |
2704 | fin->fin_error = ENOSPC; |
2705 | } |
2706 | } |
2707 | |
2708 | if ((fr != NULL) && (fr->fr_func != NULL) && |
2709 | (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) |
2710 | (void) (*fr->fr_func)(fin, &pass); |
2711 | |
2712 | /* |
2713 | * If a rule is a pre-auth rule, check again in the list of rules |
2714 | * loaded for authenticated use. It does not particulary matter |
2715 | * if this search fails because a "preauth" result, from a rule, |
2716 | * is treated as "not a pass", hence the packet is blocked. |
2717 | */ |
2718 | if (FR_ISPREAUTH(pass)) { |
2719 | pass = ipf_auth_pre_scanlist(softc, fin, pass); |
2720 | } |
2721 | |
2722 | /* |
2723 | * If the rule has "keep frag" and the packet is actually a fragment, |
2724 | * then create a fragment state entry. |
2725 | */ |
2726 | if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { |
2727 | if (fin->fin_flx & FI_FRAG) { |
2728 | if (ipf_frag_new(softc, fin, pass) == -1) { |
2729 | LBUMP(ipf_stats[out].fr_bnfr); |
2730 | } else { |
2731 | LBUMP(ipf_stats[out].fr_nfr); |
2732 | } |
2733 | } else { |
2734 | LBUMP(ipf_stats[out].fr_cfr); |
2735 | } |
2736 | } |
2737 | |
2738 | fr = fin->fin_fr; |
2739 | *passp = pass; |
2740 | |
2741 | return fr; |
2742 | } |
2743 | |
2744 | |
2745 | /* ------------------------------------------------------------------------ */ |
2746 | /* Function: ipf_check */ |
2747 | /* Returns: int - 0 == packet allowed through, */ |
2748 | /* User space: */ |
2749 | /* -1 == packet blocked */ |
2750 | /* 1 == packet not matched */ |
2751 | /* -2 == requires authentication */ |
2752 | /* Kernel: */ |
2753 | /* > 0 == filter error # for packet */ |
2754 | /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ |
2755 | /* hlen(I) - length of header */ |
2756 | /* ifp(I) - pointer to interface this packet is on */ |
2757 | /* out(I) - 0 == packet going in, 1 == packet going out */ |
2758 | /* mp(IO) - pointer to caller's buffer pointer that holds this */ |
2759 | /* IP packet. */ |
2760 | /* Solaris & HP-UX ONLY : */ |
2761 | /* qpi(I) - pointer to STREAMS queue information for this */ |
2762 | /* interface & direction. */ |
2763 | /* */ |
2764 | /* ipf_check() is the master function for all IPFilter packet processing. */ |
2765 | /* It orchestrates: Network Address Translation (NAT), checking for packet */ |
2766 | /* authorisation (or pre-authorisation), presence of related state info., */ |
2767 | /* generating log entries, IP packet accounting, routing of packets as */ |
2768 | /* directed by firewall rules and of course whether or not to allow the */ |
2769 | /* packet to be further processed by the kernel. */ |
2770 | /* */ |
2771 | /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ |
2772 | /* freed. Packets passed may be returned with the pointer pointed to by */ |
2773 | /* by "mp" changed to a new buffer. */ |
2774 | /* ------------------------------------------------------------------------ */ |
2775 | int |
2776 | ipf_check(void *ctx, ip_t *ip, int hlen, void *ifp, int out, |
2777 | #if defined(_KERNEL) && defined(MENTAT) |
2778 | void *qif, |
2779 | #endif |
2780 | mb_t **mp) |
2781 | { |
2782 | /* |
2783 | * The above really sucks, but short of writing a diff |
2784 | */ |
2785 | ipf_main_softc_t *softc = ctx; |
2786 | fr_info_t frinfo; |
2787 | fr_info_t *fin = &frinfo; |
2788 | u_32_t pass = softc->ipf_pass; |
2789 | frentry_t *fr = NULL; |
2790 | int v = IP_V(ip); |
2791 | mb_t *mc = NULL; |
2792 | mb_t *m; |
2793 | /* |
2794 | * The first part of ipf_check() deals with making sure that what goes |
2795 | * into the filtering engine makes some sense. Information about the |
2796 | * the packet is distilled, collected into a fr_info_t structure and |
2797 | * the an attempt to ensure the buffer the packet is in is big enough |
2798 | * to hold all the required packet headers. |
2799 | */ |
2800 | #ifdef _KERNEL |
2801 | # ifdef MENTAT |
2802 | qpktinfo_t *qpi = qif; |
2803 | |
2804 | # ifdef __sparc |
2805 | if ((u_int)ip & 0x3) |
2806 | return 2; |
2807 | # endif |
2808 | # else |
2809 | SPL_INT(s); |
2810 | # endif |
2811 | |
2812 | if (softc->ipf_running <= 0) { |
2813 | return 0; |
2814 | } |
2815 | |
2816 | bzero((char *)fin, sizeof(*fin)); |
2817 | |
2818 | # ifdef MENTAT |
2819 | if (qpi->qpi_flags & QF_BROADCAST) |
2820 | fin->fin_flx |= FI_MBCAST|FI_BROADCAST; |
2821 | if (qpi->qpi_flags & QF_MULTICAST) |
2822 | fin->fin_flx |= FI_MBCAST|FI_MULTICAST; |
2823 | m = qpi->qpi_m; |
2824 | fin->fin_qfm = m; |
2825 | fin->fin_qpi = qpi; |
2826 | # else /* MENTAT */ |
2827 | |
2828 | m = *mp; |
2829 | |
2830 | # if defined(M_MCAST) |
2831 | if ((m->m_flags & M_MCAST) != 0) |
2832 | fin->fin_flx |= FI_MBCAST|FI_MULTICAST; |
2833 | # endif |
2834 | # if defined(M_MLOOP) |
2835 | if ((m->m_flags & M_MLOOP) != 0) |
2836 | fin->fin_flx |= FI_MBCAST|FI_MULTICAST; |
2837 | # endif |
2838 | # if defined(M_BCAST) |
2839 | if ((m->m_flags & M_BCAST) != 0) |
2840 | fin->fin_flx |= FI_MBCAST|FI_BROADCAST; |
2841 | # endif |
2842 | # ifdef M_CANFASTFWD |
2843 | /* |
2844 | * XXX For now, IP Filter and fast-forwarding of cached flows |
2845 | * XXX are mutually exclusive. Eventually, IP Filter should |
2846 | * XXX get a "can-fast-forward" filter rule. |
2847 | */ |
2848 | m->m_flags &= ~M_CANFASTFWD; |
2849 | # endif /* M_CANFASTFWD */ |
2850 | # if defined(CSUM_DELAY_DATA) && (!defined(__FreeBSD_version) || \ |
2851 | (__FreeBSD_version < 501108)) |
2852 | /* |
2853 | * disable delayed checksums. |
2854 | */ |
2855 | if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { |
2856 | in_delayed_cksum(m); |
2857 | m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; |
2858 | } |
2859 | # endif /* CSUM_DELAY_DATA */ |
2860 | # endif /* MENTAT */ |
2861 | #else |
2862 | bzero((char *)fin, sizeof(*fin)); |
2863 | m = *mp; |
2864 | # if defined(M_MCAST) |
2865 | if ((m->m_flags & M_MCAST) != 0) |
2866 | fin->fin_flx |= FI_MBCAST|FI_MULTICAST; |
2867 | # endif |
2868 | # if defined(M_MLOOP) |
2869 | if ((m->m_flags & M_MLOOP) != 0) |
2870 | fin->fin_flx |= FI_MBCAST|FI_MULTICAST; |
2871 | # endif |
2872 | # if defined(M_BCAST) |
2873 | if ((m->m_flags & M_BCAST) != 0) |
2874 | fin->fin_flx |= FI_MBCAST|FI_BROADCAST; |
2875 | # endif |
2876 | #endif /* _KERNEL */ |
2877 | |
2878 | fin->fin_v = v; |
2879 | fin->fin_m = m; |
2880 | fin->fin_ip = ip; |
2881 | fin->fin_mp = mp; |
2882 | fin->fin_out = out; |
2883 | fin->fin_ifp = ifp; |
2884 | fin->fin_error = ENETUNREACH; |
2885 | fin->fin_hlen = (u_short)hlen; |
2886 | fin->fin_dp = (char *)ip + hlen; |
2887 | fin->fin_main_soft = softc; |
2888 | |
2889 | fin->fin_ipoff = (char *)ip - MTOD(m, char *); |
2890 | |
2891 | SPL_NET(s); |
2892 | |
2893 | #ifdef USE_INET6 |
2894 | if (v == 6) { |
2895 | LBUMP(ipf_stats[out].fr_ipv6); |
2896 | /* |
2897 | * Jumbo grams are quite likely too big for internal buffer |
2898 | * structures to handle comfortably, for now, so just drop |
2899 | * them. |
2900 | */ |
2901 | if (((ip6_t *)ip)->ip6_plen == 0) { |
2902 | DT1(frb_jumbo, ip6_t *, (ip6_t *)ip); |
2903 | pass = FR_BLOCK|FR_NOMATCH; |
2904 | fin->fin_reason = FRB_JUMBO; |
2905 | goto finished; |
2906 | } |
2907 | fin->fin_family = AF_INET6; |
2908 | } else |
2909 | #endif |
2910 | { |
2911 | fin->fin_family = AF_INET; |
2912 | } |
2913 | |
2914 | if (ipf_makefrip(hlen, ip, fin) == -1) { |
2915 | DT1(frb_makefrip, fr_info_t *, fin); |
2916 | pass = FR_BLOCK|FR_NOMATCH; |
2917 | fin->fin_reason = FRB_MAKEFRIP; |
2918 | goto finished; |
2919 | } |
2920 | |
2921 | /* |
2922 | * For at least IPv6 packets, if a m_pullup() fails then this pointer |
2923 | * becomes NULL and so we have no packet to free. |
2924 | */ |
2925 | if (*fin->fin_mp == NULL) |
2926 | goto finished; |
2927 | |
2928 | if (!out) { |
2929 | if (v == 4) { |
2930 | if (softc->ipf_chksrc && !ipf_verifysrc(fin)) { |
2931 | LBUMPD(ipf_stats[0], fr_v4_badsrc); |
2932 | fin->fin_flx |= FI_BADSRC; |
2933 | } |
2934 | if (fin->fin_ip->ip_ttl < softc->ipf_minttl) { |
2935 | LBUMPD(ipf_stats[0], fr_v4_badttl); |
2936 | fin->fin_flx |= FI_LOWTTL; |
2937 | } |
2938 | } |
2939 | #ifdef USE_INET6 |
2940 | else if (v == 6) { |
2941 | if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) { |
2942 | LBUMPD(ipf_stats[0], fr_v6_badttl); |
2943 | fin->fin_flx |= FI_LOWTTL; |
2944 | } |
2945 | } |
2946 | #endif |
2947 | } |
2948 | |
2949 | if (fin->fin_flx & FI_SHORT) { |
2950 | LBUMPD(ipf_stats[out], fr_short); |
2951 | } |
2952 | |
2953 | READ_ENTER(&softc->ipf_mutex); |
2954 | |
2955 | if (!out) { |
2956 | switch (fin->fin_v) |
2957 | { |
2958 | case 4 : |
2959 | if (ipf_nat_checkin(fin, &pass) == -1) { |
2960 | goto filterdone; |
2961 | } |
2962 | break; |
2963 | #ifdef USE_INET6 |
2964 | case 6 : |
2965 | if (ipf_nat6_checkin(fin, &pass) == -1) { |
2966 | goto filterdone; |
2967 | } |
2968 | break; |
2969 | #endif |
2970 | default : |
2971 | break; |
2972 | } |
2973 | } |
2974 | /* |
2975 | * Check auth now. |
2976 | * If a packet is found in the auth table, then skip checking |
2977 | * the access lists for permission but we do need to consider |
2978 | * the result as if it were from the ACL's. In addition, being |
2979 | * found in the auth table means it has been seen before, so do |
2980 | * not pass it through accounting (again), lest it be counted twice. |
2981 | */ |
2982 | fr = ipf_auth_check(fin, &pass); |
2983 | if (!out && (fr == NULL)) |
2984 | (void) ipf_acctpkt(fin, NULL); |
2985 | |
2986 | if (fr == NULL) { |
2987 | if ((fin->fin_flx & FI_FRAG) != 0) |
2988 | fr = ipf_frag_known(fin, &pass); |
2989 | |
2990 | if (fr == NULL) |
2991 | fr = ipf_state_check(fin, &pass); |
2992 | } |
2993 | |
2994 | if ((pass & FR_NOMATCH) || (fr == NULL)) |
2995 | fr = ipf_firewall(fin, &pass); |
2996 | |
2997 | /* |
2998 | * If we've asked to track state for this packet, set it up. |
2999 | * Here rather than ipf_firewall because ipf_checkauth may decide |
3000 | * to return a packet for "keep state" |
3001 | */ |
3002 | if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) && |
3003 | !(fin->fin_flx & FI_STATE)) { |
3004 | if (ipf_state_add(softc, fin, NULL, 0) == 0) { |
3005 | LBUMP(ipf_stats[out].fr_ads); |
3006 | } else { |
3007 | LBUMP(ipf_stats[out].fr_bads); |
3008 | if (FR_ISPASS(pass)) { |
3009 | DT(frb_stateadd); |
3010 | pass &= ~FR_CMDMASK; |
3011 | pass |= FR_BLOCK; |
3012 | fin->fin_reason = FRB_STATEADD; |
3013 | } |
3014 | } |
3015 | } |
3016 | |
3017 | fin->fin_fr = fr; |
3018 | if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) { |
3019 | fin->fin_dif = &fr->fr_dif; |
3020 | fin->fin_tif = &fr->fr_tifs[fin->fin_rev]; |
3021 | } |
3022 | |
3023 | /* |
3024 | * Only count/translate packets which will be passed on, out the |
3025 | * interface. |
3026 | */ |
3027 | if (out && FR_ISPASS(pass)) { |
3028 | (void) ipf_acctpkt(fin, NULL); |
3029 | |
3030 | switch (fin->fin_v) |
3031 | { |
3032 | case 4 : |
3033 | if (ipf_nat_checkout(fin, &pass) == -1) { |
3034 | ; |
3035 | } else if ((softc->ipf_update_ipid != 0) && (v == 4)) { |
3036 | if (ipf_updateipid(fin) == -1) { |
3037 | DT(frb_updateipid); |
3038 | LBUMP(ipf_stats[1].fr_ipud); |
3039 | pass &= ~FR_CMDMASK; |
3040 | pass |= FR_BLOCK; |
3041 | fin->fin_reason = FRB_UPDATEIPID; |
3042 | } else { |
3043 | LBUMP(ipf_stats[0].fr_ipud); |
3044 | } |
3045 | } |
3046 | break; |
3047 | #ifdef USE_INET6 |
3048 | case 6 : |
3049 | (void) ipf_nat6_checkout(fin, &pass); |
3050 | break; |
3051 | #endif |
3052 | default : |
3053 | break; |
3054 | } |
3055 | } |
3056 | |
3057 | filterdone: |
3058 | #ifdef IPFILTER_LOG |
3059 | if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { |
3060 | (void) ipf_dolog(fin, &pass); |
3061 | } |
3062 | #endif |
3063 | |
3064 | /* |
3065 | * The FI_STATE flag is cleared here so that calling ipf_state_check |
3066 | * will work when called from inside of fr_fastroute. Although |
3067 | * there is a similar flag, FI_NATED, for NAT, it does have the same |
3068 | * impact on code execution. |
3069 | */ |
3070 | fin->fin_flx &= ~FI_STATE; |
3071 | |
3072 | #if defined(FASTROUTE_RECURSION) |
3073 | /* |
3074 | * Up the reference on fr_lock and exit ipf_mutex. The generation of |
3075 | * a packet below can sometimes cause a recursive call into IPFilter. |
3076 | * On those platforms where that does happen, we need to hang onto |
3077 | * the filter rule just in case someone decides to remove or flush it |
3078 | * in the meantime. |
3079 | */ |
3080 | if (fr != NULL) { |
3081 | MUTEX_ENTER(&fr->fr_lock); |
3082 | fr->fr_ref++; |
3083 | MUTEX_EXIT(&fr->fr_lock); |
3084 | } |
3085 | |
3086 | RWLOCK_EXIT(&softc->ipf_mutex); |
3087 | #endif |
3088 | |
3089 | if ((pass & FR_RETMASK) != 0) { |
3090 | /* |
3091 | * Should we return an ICMP packet to indicate error |
3092 | * status passing through the packet filter ? |
3093 | * WARNING: ICMP error packets AND TCP RST packets should |
3094 | * ONLY be sent in repsonse to incoming packets. Sending |
3095 | * them in response to outbound packets can result in a |
3096 | * panic on some operating systems. |
3097 | */ |
3098 | if (!out) { |
3099 | if (pass & FR_RETICMP) { |
3100 | int dst; |
3101 | |
3102 | if ((pass & FR_RETMASK) == FR_FAKEICMP) |
3103 | dst = 1; |
3104 | else |
3105 | dst = 0; |
3106 | (void) ipf_send_icmp_err(ICMP_UNREACH, fin, |
3107 | dst); |
3108 | LBUMP(ipf_stats[0].fr_ret); |
3109 | } else if (((pass & FR_RETMASK) == FR_RETRST) && |
3110 | !(fin->fin_flx & FI_SHORT)) { |
3111 | if (((fin->fin_flx & FI_OOW) != 0) || |
3112 | (ipf_send_reset(fin) == 0)) { |
3113 | LBUMP(ipf_stats[1].fr_ret); |
3114 | } |
3115 | } |
3116 | |
3117 | /* |
3118 | * When using return-* with auth rules, the auth code |
3119 | * takes over disposing of this packet. |
3120 | */ |
3121 | if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { |
3122 | DT1(frb_authcapture, fr_info_t *, fin); |
3123 | fin->fin_m = *fin->fin_mp = NULL; |
3124 | fin->fin_reason = FRB_AUTHCAPTURE; |
3125 | m = NULL; |
3126 | } |
3127 | } else { |
3128 | if (pass & FR_RETRST) { |
3129 | fin->fin_error = ECONNRESET; |
3130 | } |
3131 | } |
3132 | } |
3133 | |
3134 | /* |
3135 | * After the above so that ICMP unreachables and TCP RSTs get |
3136 | * created properly. |
3137 | */ |
3138 | if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) |
3139 | ipf_nat_uncreate(fin); |
3140 | |
3141 | /* |
3142 | * If we didn't drop off the bottom of the list of rules (and thus |
3143 | * the 'current' rule fr is not NULL), then we may have some extra |
3144 | * instructions about what to do with a packet. |
3145 | * Once we're finished return to our caller, freeing the packet if |
3146 | * we are dropping it. |
3147 | */ |
3148 | if (fr != NULL) { |
3149 | frdest_t *fdp; |
3150 | |
3151 | /* |
3152 | * Generate a duplicated packet first because ipf_fastroute |
3153 | * can lead to fin_m being free'd... not good. |
3154 | */ |
3155 | fdp = fin->fin_dif; |
3156 | if ((fdp != NULL) && (fdp->fd_ptr != NULL) && |
3157 | (fdp->fd_ptr != (void *)-1) && (fin->fin_m != NULL)) { |
3158 | mc = M_COPY(fin->fin_m); |
3159 | if (mc != NULL) |
3160 | ipf_fastroute(mc, &mc, fin, fdp); |
3161 | } |
3162 | |
3163 | fdp = fin->fin_tif; |
3164 | if (!out && (pass & FR_FASTROUTE)) { |
3165 | /* |
3166 | * For fastroute rule, no destination interface defined |
3167 | * so pass NULL as the frdest_t parameter |
3168 | */ |
3169 | (void) ipf_fastroute(fin->fin_m, mp, fin, NULL); |
3170 | m = *mp = NULL; |
3171 | } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) && |
3172 | (fdp->fd_ptr != (struct ifnet *)-1)) { |
3173 | /* this is for to rules: */ |
3174 | ipf_fastroute(fin->fin_m, mp, fin, fdp); |
3175 | m = *mp = NULL; |
3176 | } |
3177 | |
3178 | #if defined(FASTROUTE_RECURSION) |
3179 | (void) ipf_derefrule(softc, &fr); |
3180 | #endif |
3181 | } |
3182 | #if !defined(FASTROUTE_RECURSION) |
3183 | RWLOCK_EXIT(&softc->ipf_mutex); |
3184 | #endif |
3185 | |
3186 | finished: |
3187 | if (!FR_ISPASS(pass)) { |
3188 | LBUMP(ipf_stats[out].fr_block); |
3189 | if (*mp != NULL) { |
3190 | #ifdef _KERNEL |
3191 | FREE_MB_T(*mp); |
3192 | #endif |
3193 | m = *mp = NULL; |
3194 | } |
3195 | } else { |
3196 | LBUMP(ipf_stats[out].fr_pass); |
3197 | #if defined(_KERNEL) && defined(__sgi) |
3198 | if ((fin->fin_hbuf != NULL) && |
3199 | (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { |
3200 | COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf); |
3201 | } |
3202 | #endif |
3203 | } |
3204 | |
3205 | SPL_X(s); |
3206 | |
3207 | #ifdef _KERNEL |
3208 | if (FR_ISPASS(pass)) |
3209 | return 0; |
3210 | LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); |
3211 | return fin->fin_error; |
3212 | #else /* _KERNEL */ |
3213 | if (*mp != NULL) |
3214 | (*mp)->mb_ifp = fin->fin_ifp; |
3215 | blockreason = fin->fin_reason; |
3216 | FR_VERBOSE(("fin_flx %#x pass %#x " , fin->fin_flx, pass)); |
3217 | /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/ |
3218 | if ((pass & FR_NOMATCH) != 0) |
3219 | return 1; |
3220 | |
3221 | if ((pass & FR_RETMASK) != 0) |
3222 | switch (pass & FR_RETMASK) |
3223 | { |
3224 | case FR_RETRST : |
3225 | return 3; |
3226 | case FR_RETICMP : |
3227 | return 4; |
3228 | case FR_FAKEICMP : |
3229 | return 5; |
3230 | } |
3231 | |
3232 | switch (pass & FR_CMDMASK) |
3233 | { |
3234 | case FR_PASS : |
3235 | return 0; |
3236 | case FR_BLOCK : |
3237 | return -1; |
3238 | case FR_AUTH : |
3239 | return -2; |
3240 | case FR_ACCOUNT : |
3241 | return -3; |
3242 | case FR_PREAUTH : |
3243 | return -4; |
3244 | } |
3245 | return 2; |
3246 | #endif /* _KERNEL */ |
3247 | } |
3248 | |
3249 | |
3250 | #ifdef IPFILTER_LOG |
3251 | /* ------------------------------------------------------------------------ */ |
3252 | /* Function: ipf_dolog */ |
3253 | /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ |
3254 | /* Parameters: fin(I) - pointer to packet information */ |
3255 | /* passp(IO) - pointer to current/new filter decision (unused) */ |
3256 | /* */ |
3257 | /* Checks flags set to see how a packet should be logged, if it is to be */ |
3258 | /* logged. Adjust statistics based on its success or not. */ |
3259 | /* ------------------------------------------------------------------------ */ |
3260 | frentry_t * |
3261 | ipf_dolog(fr_info_t *fin, u_32_t *passp) |
3262 | { |
3263 | ipf_main_softc_t *softc = fin->fin_main_soft; |
3264 | u_32_t pass; |
3265 | int out; |
3266 | |
3267 | out = fin->fin_out; |
3268 | pass = *passp; |
3269 | |
3270 | if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { |
3271 | pass |= FF_LOGNOMATCH; |
3272 | LBUMPD(ipf_stats[out], fr_npkl); |
3273 | goto logit; |
3274 | |
3275 | } else if (((pass & FR_LOGMASK) == FR_LOGP) || |
3276 | (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) { |
3277 | if ((pass & FR_LOGMASK) != FR_LOGP) |
3278 | pass |= FF_LOGPASS; |
3279 | LBUMPD(ipf_stats[out], fr_ppkl); |
3280 | goto logit; |
3281 | |
3282 | } else if (((pass & FR_LOGMASK) == FR_LOGB) || |
3283 | (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) { |
3284 | if ((pass & FR_LOGMASK) != FR_LOGB) |
3285 | pass |= FF_LOGBLOCK; |
3286 | LBUMPD(ipf_stats[out], fr_bpkl); |
3287 | |
3288 | logit: |
3289 | if (ipf_log_pkt(fin, pass) == -1) { |
3290 | /* |
3291 | * If the "or-block" option has been used then |
3292 | * block the packet if we failed to log it. |
3293 | */ |
3294 | if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) { |
3295 | DT1(frb_logfail2, u_int, pass); |
3296 | pass &= ~FR_CMDMASK; |
3297 | pass |= FR_BLOCK; |
3298 | fin->fin_reason = FRB_LOGFAIL2; |
3299 | } |
3300 | } |
3301 | *passp = pass; |
3302 | } |
3303 | |
3304 | return fin->fin_fr; |
3305 | } |
3306 | #endif /* IPFILTER_LOG */ |
3307 | |
3308 | |
3309 | /* ------------------------------------------------------------------------ */ |
3310 | /* Function: ipf_cksum */ |
3311 | /* Returns: u_short - IP header checksum */ |
3312 | /* Parameters: addr(I) - pointer to start of buffer to checksum */ |
3313 | /* len(I) - length of buffer in bytes */ |
3314 | /* */ |
3315 | /* Calculate the two's complement 16 bit checksum of the buffer passed. */ |
3316 | /* */ |
3317 | /* N.B.: addr should be 16bit aligned. */ |
3318 | /* ------------------------------------------------------------------------ */ |
3319 | u_short |
3320 | ipf_cksum(u_short *addr, int len) |
3321 | { |
3322 | u_32_t sum = 0; |
3323 | |
3324 | for (sum = 0; len > 1; len -= 2) |
3325 | sum += *addr++; |
3326 | |
3327 | /* mop up an odd byte, if necessary */ |
3328 | if (len == 1) |
3329 | sum += *(u_char *)addr; |
3330 | |
3331 | /* |
3332 | * add back carry outs from top 16 bits to low 16 bits |
3333 | */ |
3334 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ |
3335 | sum += (sum >> 16); /* add carry */ |
3336 | return (u_short)(~sum); |
3337 | } |
3338 | |
3339 | |
3340 | /* ------------------------------------------------------------------------ */ |
3341 | /* Function: fr_cksum */ |
3342 | /* Returns: u_short - layer 4 checksum */ |
3343 | /* Parameters: fin(I) - pointer to packet information */ |
3344 | /* ip(I) - pointer to IP header */ |
3345 | /* l4proto(I) - protocol to caclulate checksum for */ |
3346 | /* l4hdr(I) - pointer to layer 4 header */ |
3347 | /* */ |
3348 | /* Calculates the TCP checksum for the packet held in "m", using the data */ |
3349 | /* in the IP header "ip" to seed it. */ |
3350 | /* */ |
3351 | /* NB: This function assumes we've pullup'd enough for all of the IP header */ |
3352 | /* and the TCP header. We also assume that data blocks aren't allocated in */ |
3353 | /* odd sizes. */ |
3354 | /* */ |
3355 | /* Expects ip_len and ip_off to be in network byte order when called. */ |
3356 | /* ------------------------------------------------------------------------ */ |
3357 | u_short |
3358 | fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr) |
3359 | { |
3360 | u_short *sp, slen, sumsave, *csump; |
3361 | u_int sum, sum2; |
3362 | int hlen; |
3363 | int off; |
3364 | #ifdef USE_INET6 |
3365 | ip6_t *ip6; |
3366 | #endif |
3367 | |
3368 | csump = NULL; |
3369 | sumsave = 0; |
3370 | sp = NULL; |
3371 | slen = 0; |
3372 | hlen = 0; |
3373 | sum = 0; |
3374 | |
3375 | sum = htons((u_short)l4proto); |
3376 | /* |
3377 | * Add up IP Header portion |
3378 | */ |
3379 | #ifdef USE_INET6 |
3380 | if (IP_V(ip) == 4) { |
3381 | #endif |
3382 | hlen = IP_HL(ip) << 2; |
3383 | off = hlen; |
3384 | sp = (u_short *)&ip->ip_src; |
3385 | sum += *sp++; /* ip_src */ |
3386 | sum += *sp++; |
3387 | sum += *sp++; /* ip_dst */ |
3388 | sum += *sp++; |
3389 | #ifdef USE_INET6 |
3390 | } else if (IP_V(ip) == 6) { |
3391 | ip6 = (ip6_t *)ip; |
3392 | hlen = sizeof(*ip6); |
3393 | off = ((char *)fin->fin_dp - (char *)fin->fin_ip); |
3394 | sp = (u_short *)&ip6->ip6_src; |
3395 | sum += *sp++; /* ip6_src */ |
3396 | sum += *sp++; |
3397 | sum += *sp++; |
3398 | sum += *sp++; |
3399 | sum += *sp++; |
3400 | sum += *sp++; |
3401 | sum += *sp++; |
3402 | sum += *sp++; |
3403 | /* This needs to be routing header aware. */ |
3404 | sum += *sp++; /* ip6_dst */ |
3405 | sum += *sp++; |
3406 | sum += *sp++; |
3407 | sum += *sp++; |
3408 | sum += *sp++; |
3409 | sum += *sp++; |
3410 | sum += *sp++; |
3411 | sum += *sp++; |
3412 | } else { |
3413 | return 0xffff; |
3414 | } |
3415 | #endif |
3416 | slen = fin->fin_plen - off; |
3417 | sum += htons(slen); |
3418 | |
3419 | switch (l4proto) |
3420 | { |
3421 | case IPPROTO_UDP : |
3422 | csump = &((udphdr_t *)l4hdr)->uh_sum; |
3423 | break; |
3424 | |
3425 | case IPPROTO_TCP : |
3426 | csump = &((tcphdr_t *)l4hdr)->th_sum; |
3427 | break; |
3428 | case IPPROTO_ICMP : |
3429 | csump = &((icmphdr_t *)l4hdr)->icmp_cksum; |
3430 | sum = 0; /* Pseudo-checksum is not included */ |
3431 | break; |
3432 | #ifdef USE_INET6 |
3433 | case IPPROTO_ICMPV6 : |
3434 | csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum; |
3435 | break; |
3436 | #endif |
3437 | default : |
3438 | break; |
3439 | } |
3440 | |
3441 | if (csump != NULL) { |
3442 | sumsave = *csump; |
3443 | *csump = 0; |
3444 | } |
3445 | |
3446 | sum2 = ipf_pcksum(fin, off, sum); |
3447 | if (csump != NULL) |
3448 | *csump = sumsave; |
3449 | return sum2; |
3450 | } |
3451 | |
3452 | |
3453 | /* ------------------------------------------------------------------------ */ |
3454 | /* Function: ipf_findgroup */ |
3455 | /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ |
3456 | /* Parameters: softc(I) - pointer to soft context main structure */ |
3457 | /* group(I) - group name to search for */ |
3458 | /* unit(I) - device to which this group belongs */ |
3459 | /* set(I) - which set of rules (inactive/inactive) this is */ |
3460 | /* fgpp(O) - pointer to place to store pointer to the pointer */ |
3461 | /* to where to add the next (last) group or where */ |
3462 | /* to delete group from. */ |
3463 | /* */ |
3464 | /* Search amongst the defined groups for a particular group number. */ |
3465 | /* ------------------------------------------------------------------------ */ |
3466 | frgroup_t * |
3467 | ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set, |
3468 | frgroup_t ***fgpp) |
3469 | { |
3470 | frgroup_t *fg, **fgp; |
3471 | |
3472 | /* |
3473 | * Which list of groups to search in is dependent on which list of |
3474 | * rules are being operated on. |
3475 | */ |
3476 | fgp = &softc->ipf_groups[unit][set]; |
3477 | |
3478 | while ((fg = *fgp) != NULL) { |
3479 | if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) |
3480 | break; |
3481 | else |
3482 | fgp = &fg->fg_next; |
3483 | } |
3484 | if (fgpp != NULL) |
3485 | *fgpp = fgp; |
3486 | return fg; |
3487 | } |
3488 | |
3489 | |
3490 | /* ------------------------------------------------------------------------ */ |
3491 | /* Function: ipf_group_add */ |
3492 | /* Returns: frgroup_t * - NULL == did not create group, */ |
3493 | /* != NULL == pointer to the group */ |
3494 | /* Parameters: softc(I) - pointer to soft context main structure */ |
3495 | /* num(I) - group number to add */ |
3496 | /* head(I) - rule pointer that is using this as the head */ |
3497 | /* flags(I) - rule flags which describe the type of rule it is */ |
3498 | /* unit(I) - device to which this group will belong to */ |
3499 | /* set(I) - which set of rules (inactive/inactive) this is */ |
3500 | /* Write Locks: ipf_mutex */ |
3501 | /* */ |
3502 | /* Add a new group head, or if it already exists, increase the reference */ |
3503 | /* count to it. */ |
3504 | /* ------------------------------------------------------------------------ */ |
3505 | frgroup_t * |
3506 | ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags, |
3507 | minor_t unit, int set) |
3508 | { |
3509 | frgroup_t *fg, **fgp; |
3510 | u_32_t gflags; |
3511 | |
3512 | if (group == NULL) |
3513 | return NULL; |
3514 | |
3515 | if (unit == IPL_LOGIPF && *group == '\0') |
3516 | return NULL; |
3517 | |
3518 | fgp = NULL; |
3519 | gflags = flags & FR_INOUT; |
3520 | |
3521 | fg = ipf_findgroup(softc, group, unit, set, &fgp); |
3522 | if (fg != NULL) { |
3523 | if (fg->fg_head == NULL && head != NULL) |
3524 | fg->fg_head = head; |
3525 | if (fg->fg_flags == 0) |
3526 | fg->fg_flags = gflags; |
3527 | else if (gflags != fg->fg_flags) |
3528 | return NULL; |
3529 | fg->fg_ref++; |
3530 | return fg; |
3531 | } |
3532 | |
3533 | KMALLOC(fg, frgroup_t *); |
3534 | if (fg != NULL) { |
3535 | fg->fg_head = head; |
3536 | fg->fg_start = NULL; |
3537 | fg->fg_next = *fgp; |
3538 | bcopy(group, fg->fg_name, strlen(group) + 1); |
3539 | fg->fg_flags = gflags; |
3540 | fg->fg_ref = 1; |
3541 | fg->fg_set = &softc->ipf_groups[unit][set]; |
3542 | *fgp = fg; |
3543 | } |
3544 | return fg; |
3545 | } |
3546 | |
3547 | |
3548 | /* ------------------------------------------------------------------------ */ |
3549 | /* Function: ipf_group_del */ |
3550 | /* Returns: int - number of rules deleted */ |
3551 | /* Parameters: softc(I) - pointer to soft context main structure */ |
3552 | /* group(I) - group name to delete */ |
3553 | /* fr(I) - filter rule from which group is referenced */ |
3554 | /* Write Locks: ipf_mutex */ |
3555 | /* */ |
3556 | /* This function is called whenever a reference to a group is to be dropped */ |
3557 | /* and thus its reference count needs to be lowered and the group free'd if */ |
3558 | /* the reference count reaches zero. Passing in fr is really for the sole */ |
3559 | /* purpose of knowing when the head rule is being deleted. */ |
3560 | /* ------------------------------------------------------------------------ */ |
3561 | void |
3562 | ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr) |
3563 | { |
3564 | |
3565 | if (group->fg_head == fr) |
3566 | group->fg_head = NULL; |
3567 | |
3568 | group->fg_ref--; |
3569 | if ((group->fg_ref == 0) && (group->fg_start == NULL)) |
3570 | ipf_group_free(group); |
3571 | } |
3572 | |
3573 | |
3574 | /* ------------------------------------------------------------------------ */ |
3575 | /* Function: ipf_group_free */ |
3576 | /* Returns: Nil */ |
3577 | /* Parameters: group(I) - pointer to filter rule group */ |
3578 | /* */ |
3579 | /* Remove the group from the list of groups and free it. */ |
3580 | /* ------------------------------------------------------------------------ */ |
3581 | static void |
3582 | ipf_group_free(frgroup_t *group) |
3583 | { |
3584 | frgroup_t **gp; |
3585 | |
3586 | for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) { |
3587 | if (*gp == group) { |
3588 | *gp = group->fg_next; |
3589 | break; |
3590 | } |
3591 | } |
3592 | KFREE(group); |
3593 | } |
3594 | |
3595 | |
3596 | /* ------------------------------------------------------------------------ */ |
3597 | /* Function: ipf_group_flush */ |
3598 | /* Returns: int - number of rules flush from group */ |
3599 | /* Parameters: softc(I) - pointer to soft context main structure */ |
3600 | /* Parameters: group(I) - pointer to filter rule group */ |
3601 | /* */ |
3602 | /* Remove all of the rules that currently are listed under the given group. */ |
3603 | /* ------------------------------------------------------------------------ */ |
3604 | static int |
3605 | ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group) |
3606 | { |
3607 | int gone = 0; |
3608 | |
3609 | (void) ipf_flushlist(softc, &gone, &group->fg_start); |
3610 | |
3611 | return gone; |
3612 | } |
3613 | |
3614 | |
3615 | /* ------------------------------------------------------------------------ */ |
3616 | /* Function: ipf_getrulen */ |
3617 | /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ |
3618 | /* Parameters: softc(I) - pointer to soft context main structure */ |
3619 | /* Parameters: unit(I) - device for which to count the rule's number */ |
3620 | /* flags(I) - which set of rules to find the rule in */ |
3621 | /* group(I) - group name */ |
3622 | /* n(I) - rule number to find */ |
3623 | /* */ |
3624 | /* Find rule # n in group # g and return a pointer to it. Return NULl if */ |
3625 | /* group # g doesn't exist or there are less than n rules in the group. */ |
3626 | /* ------------------------------------------------------------------------ */ |
3627 | frentry_t * |
3628 | ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n) |
3629 | { |
3630 | frentry_t *fr; |
3631 | frgroup_t *fg; |
3632 | |
3633 | fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL); |
3634 | if (fg == NULL) |
3635 | return NULL; |
3636 | for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--) |
3637 | ; |
3638 | if (n != 0) |
3639 | return NULL; |
3640 | return fr; |
3641 | } |
3642 | |
3643 | |
3644 | /* ------------------------------------------------------------------------ */ |
3645 | /* Function: ipf_flushlist */ |
3646 | /* Returns: int - >= 0 - number of flushed rules */ |
3647 | /* Parameters: softc(I) - pointer to soft context main structure */ |
3648 | /* nfreedp(O) - pointer to int where flush count is stored */ |
3649 | /* listp(I) - pointer to list to flush pointer */ |
3650 | /* Write Locks: ipf_mutex */ |
3651 | /* */ |
3652 | /* Recursively flush rules from the list, descending groups as they are */ |
3653 | /* encountered. if a rule is the head of a group and it has lost all its */ |
3654 | /* group members, then also delete the group reference. nfreedp is needed */ |
3655 | /* to store the accumulating count of rules removed, whereas the returned */ |
3656 | /* value is just the number removed from the current list. The latter is */ |
3657 | /* needed to correctly adjust reference counts on rules that define groups. */ |
3658 | /* */ |
3659 | /* NOTE: Rules not loaded from user space cannot be flushed. */ |
3660 | /* ------------------------------------------------------------------------ */ |
3661 | static int |
3662 | ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp) |
3663 | { |
3664 | int freed = 0; |
3665 | frentry_t *fp; |
3666 | |
3667 | while ((fp = *listp) != NULL) { |
3668 | if ((fp->fr_type & FR_T_BUILTIN) || |
3669 | !(fp->fr_flags & FR_COPIED)) { |
3670 | listp = &fp->fr_next; |
3671 | continue; |
3672 | } |
3673 | *listp = fp->fr_next; |
3674 | if (fp->fr_next != NULL) |
3675 | fp->fr_next->fr_pnext = fp->fr_pnext; |
3676 | fp->fr_pnext = NULL; |
3677 | |
3678 | if (fp->fr_grphead != NULL) { |
3679 | freed += ipf_group_flush(softc, fp->fr_grphead); |
3680 | fp->fr_names[fp->fr_grhead] = '\0'; |
3681 | } |
3682 | |
3683 | if (fp->fr_icmpgrp != NULL) { |
3684 | freed += ipf_group_flush(softc, fp->fr_icmpgrp); |
3685 | fp->fr_names[fp->fr_icmphead] = '\0'; |
3686 | } |
3687 | |
3688 | if (fp->fr_srctrack.ht_max_nodes) |
3689 | ipf_rb_ht_flush(&fp->fr_srctrack); |
3690 | |
3691 | fp->fr_next = NULL; |
3692 | |
3693 | ASSERT(fp->fr_ref > 0); |
3694 | if (ipf_derefrule(softc, &fp) == 0) |
3695 | freed++; |
3696 | } |
3697 | *nfreedp += freed; |
3698 | return freed; |
3699 | } |
3700 | |
3701 | |
3702 | /* ------------------------------------------------------------------------ */ |
3703 | /* Function: ipf_flush */ |
3704 | /* Returns: int - >= 0 - number of flushed rules */ |
3705 | /* Parameters: softc(I) - pointer to soft context main structure */ |
3706 | /* unit(I) - device for which to flush rules */ |
3707 | /* flags(I) - which set of rules to flush */ |
3708 | /* */ |
3709 | /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ |
3710 | /* and IPv6) as defined by the value of flags. */ |
3711 | /* ------------------------------------------------------------------------ */ |
3712 | int |
3713 | ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags) |
3714 | { |
3715 | int flushed = 0, set; |
3716 | |
3717 | WRITE_ENTER(&softc->ipf_mutex); |
3718 | |
3719 | set = softc->ipf_active; |
3720 | if ((flags & FR_INACTIVE) == FR_INACTIVE) |
3721 | set = 1 - set; |
3722 | |
3723 | if (flags & FR_OUTQUE) { |
3724 | ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]); |
3725 | ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]); |
3726 | } |
3727 | if (flags & FR_INQUE) { |
3728 | ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]); |
3729 | ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]); |
3730 | } |
3731 | |
3732 | flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set], |
3733 | flags & (FR_INQUE|FR_OUTQUE)); |
3734 | |
3735 | RWLOCK_EXIT(&softc->ipf_mutex); |
3736 | |
3737 | if (unit == IPL_LOGIPF) { |
3738 | int tmp; |
3739 | |
3740 | tmp = ipf_flush(softc, IPL_LOGCOUNT, flags); |
3741 | if (tmp >= 0) |
3742 | flushed += tmp; |
3743 | } |
3744 | return flushed; |
3745 | } |
3746 | |
3747 | |
3748 | /* ------------------------------------------------------------------------ */ |
3749 | /* Function: ipf_flush_groups */ |
3750 | /* Returns: int - >= 0 - number of flushed rules */ |
3751 | /* Parameters: softc(I) - soft context pointerto work with */ |
3752 | /* grhead(I) - pointer to the start of the group list to flush */ |
3753 | /* flags(I) - which set of rules to flush */ |
3754 | /* */ |
3755 | /* Walk through all of the groups under the given group head and remove all */ |
3756 | /* of those that match the flags passed in. The for loop here is bit more */ |
3757 | /* complicated than usual because the removal of a rule with ipf_derefrule */ |
3758 | /* may end up removing not only the structure pointed to by "fg" but also */ |
3759 | /* what is fg_next and fg_next after that. So if a filter rule is actually */ |
3760 | /* removed from the group then it is necessary to start again. */ |
3761 | /* ------------------------------------------------------------------------ */ |
3762 | static int |
3763 | ipf_flush_groups( ipf_main_softc_t *softc, frgroup_t **grhead, int flags) |
3764 | { |
3765 | frentry_t *fr, **frp; |
3766 | frgroup_t *fg, **fgp; |
3767 | int flushed = 0; |
3768 | int removed = 0; |
3769 | |
3770 | for (fgp = grhead; (fg = *fgp) != NULL; ) { |
3771 | while ((fg != NULL) && ((fg->fg_flags & flags) == 0)) |
3772 | fg = fg->fg_next; |
3773 | if (fg == NULL) |
3774 | break; |
3775 | removed = 0; |
3776 | frp = &fg->fg_start; |
3777 | while ((removed == 0) && ((fr = *frp) != NULL)) { |
3778 | if ((fr->fr_flags & flags) == 0) { |
3779 | frp = &fr->fr_next; |
3780 | } else { |
3781 | if (fr->fr_next != NULL) |
3782 | fr->fr_next->fr_pnext = fr->fr_pnext; |
3783 | *frp = fr->fr_next; |
3784 | fr->fr_pnext = NULL; |
3785 | fr->fr_next = NULL; |
3786 | (void) ipf_derefrule(softc, &fr); |
3787 | flushed++; |
3788 | removed++; |
3789 | } |
3790 | } |
3791 | if (removed == 0) |
3792 | fgp = &fg->fg_next; |
3793 | } |
3794 | return flushed; |
3795 | } |
3796 | |
3797 | |
3798 | /* ------------------------------------------------------------------------ */ |
3799 | /* Function: memstr */ |
3800 | /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ |
3801 | /* Parameters: src(I) - pointer to byte sequence to match */ |
3802 | /* dst(I) - pointer to byte sequence to search */ |
3803 | /* slen(I) - match length */ |
3804 | /* dlen(I) - length available to search in */ |
3805 | /* */ |
3806 | /* Search dst for a sequence of bytes matching those at src and extend for */ |
3807 | /* slen bytes. */ |
3808 | /* ------------------------------------------------------------------------ */ |
3809 | char * |
3810 | memstr(const char *src, char *dst, size_t slen, size_t dlen) |
3811 | { |
3812 | char *s = NULL; |
3813 | |
3814 | while (dlen >= slen) { |
3815 | if (memcmp(src, dst, slen) == 0) { |
3816 | s = dst; |
3817 | break; |
3818 | } |
3819 | dst++; |
3820 | dlen--; |
3821 | } |
3822 | return s; |
3823 | } |
3824 | |
3825 | |
3826 | /* ------------------------------------------------------------------------ */ |
3827 | /* Function: ipf_fixskip */ |
3828 | /* Returns: Nil */ |
3829 | /* Parameters: listp(IO) - pointer to start of list with skip rule */ |
3830 | /* rp(I) - rule added/removed with skip in it. */ |
3831 | /* addremove(I) - adjustment (-1/+1) to make to skip count, */ |
3832 | /* depending on whether a rule was just added */ |
3833 | /* or removed. */ |
3834 | /* */ |
3835 | /* Adjust all the rules in a list which would have skip'd past the position */ |
3836 | /* where we are inserting to skip to the right place given the change. */ |
3837 | /* ------------------------------------------------------------------------ */ |
3838 | void |
3839 | ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove) |
3840 | { |
3841 | int rules, rn; |
3842 | frentry_t *fp; |
3843 | |
3844 | rules = 0; |
3845 | for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) |
3846 | rules++; |
3847 | |
3848 | if (!fp) |
3849 | return; |
3850 | |
3851 | for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) |
3852 | if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) |
3853 | fp->fr_arg += addremove; |
3854 | } |
3855 | |
3856 | |
3857 | #ifdef _KERNEL |
3858 | /* ------------------------------------------------------------------------ */ |
3859 | /* Function: count4bits */ |
3860 | /* Returns: int - >= 0 - number of consecutive bits in input */ |
3861 | /* Parameters: ip(I) - 32bit IP address */ |
3862 | /* */ |
3863 | /* IPv4 ONLY */ |
3864 | /* count consecutive 1's in bit mask. If the mask generated by counting */ |
3865 | /* consecutive 1's is different to that passed, return -1, else return # */ |
3866 | /* of bits. */ |
3867 | /* ------------------------------------------------------------------------ */ |
3868 | int |
3869 | count4bits(u_32_t ip) |
3870 | { |
3871 | u_32_t ipn; |
3872 | int cnt = 0, i, j; |
3873 | |
3874 | ip = ipn = ntohl(ip); |
3875 | for (i = 32; i; i--, ipn *= 2) |
3876 | if (ipn & 0x80000000) |
3877 | cnt++; |
3878 | else |
3879 | break; |
3880 | ipn = 0; |
3881 | for (i = 32, j = cnt; i; i--, j--) { |
3882 | ipn *= 2; |
3883 | if (j > 0) |
3884 | ipn++; |
3885 | } |
3886 | if (ipn == ip) |
3887 | return cnt; |
3888 | return -1; |
3889 | } |
3890 | |
3891 | |
3892 | /* ------------------------------------------------------------------------ */ |
3893 | /* Function: count6bits */ |
3894 | /* Returns: int - >= 0 - number of consecutive bits in input */ |
3895 | /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ |
3896 | /* */ |
3897 | /* IPv6 ONLY */ |
3898 | /* count consecutive 1's in bit mask. */ |
3899 | /* ------------------------------------------------------------------------ */ |
3900 | # ifdef USE_INET6 |
3901 | int |
3902 | count6bits(u_32_t *msk) |
3903 | { |
3904 | int i = 0, k; |
3905 | u_32_t j; |
3906 | |
3907 | for (k = 3; k >= 0; k--) |
3908 | if (msk[k] == 0xffffffff) |
3909 | i += 32; |
3910 | else { |
3911 | for (j = msk[k]; j; j <<= 1) |
3912 | if (j & 0x80000000) |
3913 | i++; |
3914 | } |
3915 | return i; |
3916 | } |
3917 | # endif |
3918 | #endif /* _KERNEL */ |
3919 | |
3920 | |
3921 | /* ------------------------------------------------------------------------ */ |
3922 | /* Function: ipf_synclist */ |
3923 | /* Returns: int - 0 = no failures, else indication of first failure */ |
3924 | /* Parameters: fr(I) - start of filter list to sync interface names for */ |
3925 | /* ifp(I) - interface pointer for limiting sync lookups */ |
3926 | /* Write Locks: ipf_mutex */ |
3927 | /* */ |
3928 | /* Walk through a list of filter rules and resolve any interface names into */ |
3929 | /* pointers. Where dynamic addresses are used, also update the IP address */ |
3930 | /* used in the rule. The interface pointer is used to limit the lookups to */ |
3931 | /* a specific set of matching names if it is non-NULL. */ |
3932 | /* Errors can occur when resolving the destination name of to/dup-to fields */ |
3933 | /* when the name points to a pool and that pool doest not exist. If this */ |
3934 | /* does happen then it is necessary to check if there are any lookup refs */ |
3935 | /* that need to be dropped before returning with an error. */ |
3936 | /* ------------------------------------------------------------------------ */ |
3937 | static int |
3938 | ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp) |
3939 | { |
3940 | frentry_t *frt, *start = fr; |
3941 | frdest_t *fdp; |
3942 | char *name; |
3943 | int error; |
3944 | void *ifa; |
3945 | int v, i; |
3946 | |
3947 | error = 0; |
3948 | |
3949 | for (; fr; fr = fr->fr_next) { |
3950 | if (fr->fr_family == AF_INET) |
3951 | v = 4; |
3952 | else if (fr->fr_family == AF_INET6) |
3953 | v = 6; |
3954 | else |
3955 | v = 0; |
3956 | |
3957 | /* |
3958 | * Lookup all the interface names that are part of the rule. |
3959 | */ |
3960 | for (i = 0; i < 4; i++) { |
3961 | if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) |
3962 | continue; |
3963 | if (fr->fr_ifnames[i] == -1) |
3964 | continue; |
3965 | name = FR_NAME(fr, fr_ifnames[i]); |
3966 | fr->fr_ifas[i] = ipf_resolvenic(softc, name, v); |
3967 | } |
3968 | |
3969 | if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { |
3970 | if (fr->fr_satype != FRI_NORMAL && |
3971 | fr->fr_satype != FRI_LOOKUP) { |
3972 | ifa = ipf_resolvenic(softc, fr->fr_names + |
3973 | fr->fr_sifpidx, v); |
3974 | ipf_ifpaddr(softc, v, fr->fr_satype, ifa, |
3975 | &fr->fr_src6, &fr->fr_smsk6); |
3976 | } |
3977 | if (fr->fr_datype != FRI_NORMAL && |
3978 | fr->fr_datype != FRI_LOOKUP) { |
3979 | ifa = ipf_resolvenic(softc, fr->fr_names + |
3980 | fr->fr_sifpidx, v); |
3981 | ipf_ifpaddr(softc, v, fr->fr_datype, ifa, |
3982 | &fr->fr_dst6, &fr->fr_dmsk6); |
3983 | } |
3984 | } |
3985 | |
3986 | fdp = &fr->fr_tifs[0]; |
3987 | if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { |
3988 | error = ipf_resolvedest(softc, fr->fr_names, fdp, v); |
3989 | if (error != 0) |
3990 | goto unwind; |
3991 | } |
3992 | |
3993 | fdp = &fr->fr_tifs[1]; |
3994 | if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { |
3995 | error = ipf_resolvedest(softc, fr->fr_names, fdp, v); |
3996 | if (error != 0) |
3997 | goto unwind; |
3998 | } |
3999 | |
4000 | fdp = &fr->fr_dif; |
4001 | if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { |
4002 | error = ipf_resolvedest(softc, fr->fr_names, fdp, v); |
4003 | if (error != 0) |
4004 | goto unwind; |
4005 | } |
4006 | |
4007 | if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && |
4008 | (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) { |
4009 | fr->fr_srcptr = ipf_lookup_res_num(softc, |
4010 | fr->fr_srctype, |
4011 | IPL_LOGIPF, |
4012 | fr->fr_srcnum, |
4013 | &fr->fr_srcfunc); |
4014 | } |
4015 | if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && |
4016 | (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) { |
4017 | fr->fr_dstptr = ipf_lookup_res_num(softc, |
4018 | fr->fr_dsttype, |
4019 | IPL_LOGIPF, |
4020 | fr->fr_dstnum, |
4021 | &fr->fr_dstfunc); |
4022 | } |
4023 | } |
4024 | return 0; |
4025 | |
4026 | unwind: |
4027 | for (frt = start; frt != fr; fr = fr->fr_next) { |
4028 | if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && |
4029 | (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL)) |
4030 | ipf_lookup_deref(softc, frt->fr_srctype, |
4031 | frt->fr_srcptr); |
4032 | if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && |
4033 | (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL)) |
4034 | ipf_lookup_deref(softc, frt->fr_dsttype, |
4035 | frt->fr_dstptr); |
4036 | } |
4037 | return error; |
4038 | } |
4039 | |
4040 | |
4041 | /* ------------------------------------------------------------------------ */ |
4042 | /* Function: ipf_sync */ |
4043 | /* Returns: void */ |
4044 | /* Parameters: Nil */ |
4045 | /* */ |
4046 | /* ipf_sync() is called when we suspect that the interface list or */ |
4047 | /* information about interfaces (like IP#) has changed. Go through all */ |
4048 | /* filter rules, NAT entries and the state table and check if anything */ |
4049 | /* needs to be changed/updated. */ |
4050 | /* ------------------------------------------------------------------------ */ |
4051 | int |
4052 | ipf_sync(ipf_main_softc_t *softc, void *ifp) |
4053 | { |
4054 | int i; |
4055 | |
4056 | # if !SOLARIS |
4057 | ipf_nat_sync(softc, ifp); |
4058 | ipf_state_sync(softc, ifp); |
4059 | ipf_lookup_sync(softc, ifp); |
4060 | # endif |
4061 | |
4062 | WRITE_ENTER(&softc->ipf_mutex); |
4063 | (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp); |
4064 | (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp); |
4065 | (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp); |
4066 | (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp); |
4067 | |
4068 | for (i = 0; i < IPL_LOGSIZE; i++) { |
4069 | frgroup_t *g; |
4070 | |
4071 | for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next) |
4072 | (void) ipf_synclist(softc, g->fg_start, ifp); |
4073 | for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next) |
4074 | (void) ipf_synclist(softc, g->fg_start, ifp); |
4075 | } |
4076 | RWLOCK_EXIT(&softc->ipf_mutex); |
4077 | |
4078 | return 0; |
4079 | } |
4080 | |
4081 | |
4082 | /* |
4083 | * In the functions below, bcopy() is called because the pointer being |
4084 | * copied _from_ in this instance is a pointer to a char buf (which could |
4085 | * end up being unaligned) and on the kernel's local stack. |
4086 | */ |
4087 | /* ------------------------------------------------------------------------ */ |
4088 | /* Function: copyinptr */ |
4089 | /* Returns: int - 0 = success, else failure */ |
4090 | /* Parameters: src(I) - pointer to the source address */ |
4091 | /* dst(I) - destination address */ |
4092 | /* size(I) - number of bytes to copy */ |
4093 | /* */ |
4094 | /* Copy a block of data in from user space, given a pointer to the pointer */ |
4095 | /* to start copying from (src) and a pointer to where to store it (dst). */ |
4096 | /* NB: src - pointer to user space pointer, dst - kernel space pointer */ |
4097 | /* ------------------------------------------------------------------------ */ |
4098 | int |
4099 | copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) |
4100 | { |
4101 | void *ca; |
4102 | int error; |
4103 | |
4104 | # if SOLARIS |
4105 | error = COPYIN(src, &ca, sizeof(ca)); |
4106 | if (error != 0) |
4107 | return error; |
4108 | # else |
4109 | bcopy(src, (void *)&ca, sizeof(ca)); |
4110 | # endif |
4111 | error = COPYIN(ca, dst, size); |
4112 | if (error != 0) { |
4113 | IPFERROR(3); |
4114 | error = EFAULT; |
4115 | } |
4116 | return error; |
4117 | } |
4118 | |
4119 | |
4120 | /* ------------------------------------------------------------------------ */ |
4121 | /* Function: copyoutptr */ |
4122 | /* Returns: int - 0 = success, else failure */ |
4123 | /* Parameters: src(I) - pointer to the source address */ |
4124 | /* dst(I) - destination address */ |
4125 | /* size(I) - number of bytes to copy */ |
4126 | /* */ |
4127 | /* Copy a block of data out to user space, given a pointer to the pointer */ |
4128 | /* to start copying from (src) and a pointer to where to store it (dst). */ |
4129 | /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ |
4130 | /* ------------------------------------------------------------------------ */ |
4131 | int |
4132 | copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) |
4133 | { |
4134 | void *ca; |
4135 | int error; |
4136 | |
4137 | bcopy(dst, &ca, sizeof(ca)); |
4138 | error = COPYOUT(src, ca, size); |
4139 | if (error != 0) { |
4140 | IPFERROR(4); |
4141 | error = EFAULT; |
4142 | } |
4143 | return error; |
4144 | } |
4145 | #ifdef _KERNEL |
4146 | #endif |
4147 | |
4148 | |
4149 | /* ------------------------------------------------------------------------ */ |
4150 | /* Function: ipf_lock */ |
4151 | /* Returns: int - 0 = success, else error */ |
4152 | /* Parameters: data(I) - pointer to lock value to set */ |
4153 | /* lockp(O) - pointer to location to store old lock value */ |
4154 | /* */ |
4155 | /* Get the new value for the lock integer, set it and return the old value */ |
4156 | /* in *lockp. */ |
4157 | /* ------------------------------------------------------------------------ */ |
4158 | int |
4159 | ipf_lock(void *data, int *lockp) |
4160 | { |
4161 | int arg, err; |
4162 | |
4163 | err = BCOPYIN(data, &arg, sizeof(arg)); |
4164 | if (err != 0) |
4165 | return EFAULT; |
4166 | err = BCOPYOUT(lockp, data, sizeof(*lockp)); |
4167 | if (err != 0) |
4168 | return EFAULT; |
4169 | *lockp = arg; |
4170 | return 0; |
4171 | } |
4172 | |
4173 | |
4174 | /* ------------------------------------------------------------------------ */ |
4175 | /* Function: ipf_getstat */ |
4176 | /* Returns: Nil */ |
4177 | /* Parameters: softc(I) - pointer to soft context main structure */ |
4178 | /* fiop(I) - pointer to ipfilter stats structure */ |
4179 | /* rev(I) - version claim by program doing ioctl */ |
4180 | /* */ |
4181 | /* Stores a copy of current pointers, counters, etc, in the friostat */ |
4182 | /* structure. */ |
4183 | /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */ |
4184 | /* program is looking for. This ensure that validation of the version it */ |
4185 | /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */ |
4186 | /* allow older binaries to work but kernels without it will not. */ |
4187 | /* ------------------------------------------------------------------------ */ |
4188 | /*ARGSUSED*/ |
4189 | static void |
4190 | ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) |
4191 | { |
4192 | int i; |
4193 | |
4194 | bcopy((char *)softc->ipf_stats, (char *)fiop->f_st, |
4195 | sizeof(ipf_statistics_t) * 2); |
4196 | fiop->f_locks[IPL_LOGSTATE] = -1; |
4197 | fiop->f_locks[IPL_LOGNAT] = -1; |
4198 | fiop->f_locks[IPL_LOGIPF] = -1; |
4199 | fiop->f_locks[IPL_LOGAUTH] = -1; |
4200 | |
4201 | fiop->f_ipf[0][0] = softc->ipf_rules[0][0]; |
4202 | fiop->f_acct[0][0] = softc->ipf_acct[0][0]; |
4203 | fiop->f_ipf[0][1] = softc->ipf_rules[0][1]; |
4204 | fiop->f_acct[0][1] = softc->ipf_acct[0][1]; |
4205 | fiop->f_ipf[1][0] = softc->ipf_rules[1][0]; |
4206 | fiop->f_acct[1][0] = softc->ipf_acct[1][0]; |
4207 | fiop->f_ipf[1][1] = softc->ipf_rules[1][1]; |
4208 | fiop->f_acct[1][1] = softc->ipf_acct[1][1]; |
4209 | |
4210 | fiop->f_ticks = softc->ipf_ticks; |
4211 | fiop->f_active = softc->ipf_active; |
4212 | fiop->f_froute[0] = softc->ipf_frouteok[0]; |
4213 | fiop->f_froute[1] = softc->ipf_frouteok[1]; |
4214 | fiop->f_rb_no_mem = softc->ipf_rb_no_mem; |
4215 | fiop->f_rb_node_max = softc->ipf_rb_node_max; |
4216 | |
4217 | fiop->f_running = softc->ipf_running; |
4218 | for (i = 0; i < IPL_LOGSIZE; i++) { |
4219 | fiop->f_groups[i][0] = softc->ipf_groups[i][0]; |
4220 | fiop->f_groups[i][1] = softc->ipf_groups[i][1]; |
4221 | } |
4222 | #ifdef IPFILTER_LOG |
4223 | fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF); |
4224 | fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF); |
4225 | fiop->f_logging = 1; |
4226 | #else |
4227 | fiop->f_log_ok = 0; |
4228 | fiop->f_log_fail = 0; |
4229 | fiop->f_logging = 0; |
4230 | #endif |
4231 | fiop->f_defpass = softc->ipf_pass; |
4232 | fiop->f_features = ipf_features; |
4233 | |
4234 | #ifdef IPFILTER_COMPAT |
4235 | snprintf(fiop->f_version, sizeof(fiop->f_version), |
4236 | "IP Filter: v%d.%d.%d" , (rev / 1000000) % 100, |
4237 | (rev / 10000) % 100, (rev / 100) % 100); |
4238 | #else |
4239 | rev = rev; |
4240 | (void) strncpy(fiop->f_version, ipfilter_version, |
4241 | sizeof(fiop->f_version)); |
4242 | fiop->f_version[sizeof(fiop->f_version) - 1] = '\0'; |
4243 | #endif |
4244 | } |
4245 | |
4246 | |
4247 | #ifdef USE_INET6 |
4248 | int icmptoicmp6types[ICMP_MAXTYPE+1] = { |
4249 | ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ |
4250 | -1, /* 1: UNUSED */ |
4251 | -1, /* 2: UNUSED */ |
4252 | ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ |
4253 | -1, /* 4: ICMP_SOURCEQUENCH */ |
4254 | ND_REDIRECT, /* 5: ICMP_REDIRECT */ |
4255 | -1, /* 6: UNUSED */ |
4256 | -1, /* 7: UNUSED */ |
4257 | ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ |
4258 | -1, /* 9: UNUSED */ |
4259 | -1, /* 10: UNUSED */ |
4260 | ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ |
4261 | ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ |
4262 | -1, /* 13: ICMP_TSTAMP */ |
4263 | -1, /* 14: ICMP_TSTAMPREPLY */ |
4264 | -1, /* 15: ICMP_IREQ */ |
4265 | -1, /* 16: ICMP_IREQREPLY */ |
4266 | -1, /* 17: ICMP_MASKREQ */ |
4267 | -1, /* 18: ICMP_MASKREPLY */ |
4268 | }; |
4269 | |
4270 | |
4271 | int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { |
4272 | ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ |
4273 | ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ |
4274 | -1, /* 2: ICMP_UNREACH_PROTOCOL */ |
4275 | ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ |
4276 | -1, /* 4: ICMP_UNREACH_NEEDFRAG */ |
4277 | ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ |
4278 | ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ |
4279 | ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ |
4280 | -1, /* 8: ICMP_UNREACH_ISOLATED */ |
4281 | ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ |
4282 | ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ |
4283 | -1, /* 11: ICMP_UNREACH_TOSNET */ |
4284 | -1, /* 12: ICMP_UNREACH_TOSHOST */ |
4285 | ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ |
4286 | }; |
4287 | int icmpreplytype6[ICMP6_MAXTYPE + 1]; |
4288 | #endif |
4289 | |
4290 | int icmpreplytype4[ICMP_MAXTYPE + 1]; |
4291 | |
4292 | |
4293 | /* ------------------------------------------------------------------------ */ |
4294 | /* Function: ipf_matchicmpqueryreply */ |
4295 | /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ |
4296 | /* Parameters: v(I) - IP protocol version (4 or 6) */ |
4297 | /* ic(I) - ICMP information */ |
4298 | /* icmp(I) - ICMP packet header */ |
4299 | /* rev(I) - direction (0 = forward/1 = reverse) of packet */ |
4300 | /* */ |
4301 | /* Check if the ICMP packet defined by the header pointed to by icmp is a */ |
4302 | /* reply to one as described by what's in ic. If it is a match, return 1, */ |
4303 | /* else return 0 for no match. */ |
4304 | /* ------------------------------------------------------------------------ */ |
4305 | int |
4306 | ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev) |
4307 | { |
4308 | int ictype; |
4309 | |
4310 | ictype = ic->ici_type; |
4311 | |
4312 | if (v == 4) { |
4313 | /* |
4314 | * If we matched its type on the way in, then when going out |
4315 | * it will still be the same type. |
4316 | */ |
4317 | if ((!rev && (icmp->icmp_type == ictype)) || |
4318 | (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { |
4319 | if (icmp->icmp_type != ICMP_ECHOREPLY) |
4320 | return 1; |
4321 | if (icmp->icmp_id == ic->ici_id) |
4322 | return 1; |
4323 | } |
4324 | } |
4325 | #ifdef USE_INET6 |
4326 | else if (v == 6) { |
4327 | if ((!rev && (icmp->icmp_type == ictype)) || |
4328 | (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { |
4329 | if (icmp->icmp_type != ICMP6_ECHO_REPLY) |
4330 | return 1; |
4331 | if (icmp->icmp_id == ic->ici_id) |
4332 | return 1; |
4333 | } |
4334 | } |
4335 | #endif |
4336 | return 0; |
4337 | } |
4338 | |
4339 | /* ------------------------------------------------------------------------ */ |
4340 | /* Function: ipf_rule_compare */ |
4341 | /* Parameters: fr1(I) - first rule structure to compare */ |
4342 | /* fr2(I) - second rule structure to compare */ |
4343 | /* Returns: int - 0 == rules are the same, else mismatch */ |
4344 | /* */ |
4345 | /* Compare two rules and return 0 if they match or a number indicating */ |
4346 | /* which of the individual checks failed. */ |
4347 | /* ------------------------------------------------------------------------ */ |
4348 | static int |
4349 | ipf_rule_compare(frentry_t *fr1, frentry_t *fr2) |
4350 | { |
4351 | if (fr1->fr_cksum != fr2->fr_cksum) |
4352 | return 1; |
4353 | if (fr1->fr_size != fr2->fr_size) |
4354 | return 2; |
4355 | if (fr1->fr_dsize != fr2->fr_dsize) |
4356 | return 3; |
4357 | if (memcmp(&fr1->fr_func, &fr2->fr_func, |
4358 | fr1->fr_size - offsetof(struct frentry, fr_func)) != 0) |
4359 | return 4; |
4360 | if (fr1->fr_data && !fr2->fr_data) |
4361 | return 5; |
4362 | if (!fr1->fr_data && fr2->fr_data) |
4363 | return 6; |
4364 | if (fr1->fr_data) { |
4365 | if (memcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize)) |
4366 | return 7; |
4367 | } |
4368 | return 0; |
4369 | } |
4370 | |
4371 | |
4372 | /* ------------------------------------------------------------------------ */ |
4373 | /* Function: frrequest */ |
4374 | /* Returns: int - 0 == success, > 0 == errno value */ |
4375 | /* Parameters: unit(I) - device for which this is for */ |
4376 | /* req(I) - ioctl command (SIOC*) */ |
4377 | /* data(I) - pointr to ioctl data */ |
4378 | /* set(I) - 1 or 0 (filter set) */ |
4379 | /* makecopy(I) - flag indicating whether data points to a rule */ |
4380 | /* in kernel space & hence doesn't need copying. */ |
4381 | /* */ |
4382 | /* This function handles all the requests which operate on the list of */ |
4383 | /* filter rules. This includes adding, deleting, insertion. It is also */ |
4384 | /* responsible for creating groups when a "head" rule is loaded. Interface */ |
4385 | /* names are resolved here and other sanity checks are made on the content */ |
4386 | /* of the rule structure being loaded. If a rule has user defined timeouts */ |
4387 | /* then make sure they are created and initialised before exiting. */ |
4388 | /* ------------------------------------------------------------------------ */ |
4389 | int |
4390 | frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, void *data, |
4391 | int set, int makecopy) |
4392 | { |
4393 | int error = 0, in, family, addrem, need_free = 0; |
4394 | frentry_t frd, *fp, *f, **fprev, **ftail; |
4395 | void *ptr, *uptr; |
4396 | u_int *p, *pp; |
4397 | frgroup_t *fg; |
4398 | char *group; |
4399 | |
4400 | ptr = NULL; |
4401 | fg = NULL; |
4402 | fp = &frd; |
4403 | if (makecopy != 0) { |
4404 | bzero(fp, sizeof(frd)); |
4405 | error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY); |
4406 | if (error) { |
4407 | return error; |
4408 | } |
4409 | if ((fp->fr_type & FR_T_BUILTIN) != 0) { |
4410 | IPFERROR(6); |
4411 | return EINVAL; |
4412 | } |
4413 | KMALLOCS(f, frentry_t *, fp->fr_size); |
4414 | if (f == NULL) { |
4415 | IPFERROR(131); |
4416 | return ENOMEM; |
4417 | } |
4418 | bzero(f, fp->fr_size); |
4419 | error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY, |
4420 | fp->fr_size); |
4421 | if (error) { |
4422 | KFREES(f, fp->fr_size); |
4423 | return error; |
4424 | } |
4425 | |
4426 | fp = f; |
4427 | f = NULL; |
4428 | fp->fr_next = NULL; |
4429 | fp->fr_dnext = NULL; |
4430 | fp->fr_pnext = NULL; |
4431 | fp->fr_pdnext = NULL; |
4432 | fp->fr_grp = NULL; |
4433 | fp->fr_grphead = NULL; |
4434 | fp->fr_icmpgrp = NULL; |
4435 | fp->fr_isc = (void *)-1; |
4436 | fp->fr_ptr = NULL; |
4437 | fp->fr_ref = 0; |
4438 | fp->fr_flags |= FR_COPIED; |
4439 | } else { |
4440 | fp = (frentry_t *)data; |
4441 | if ((fp->fr_type & FR_T_BUILTIN) == 0) { |
4442 | IPFERROR(7); |
4443 | return EINVAL; |
4444 | } |
4445 | fp->fr_flags &= ~FR_COPIED; |
4446 | } |
4447 | |
4448 | if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || |
4449 | ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) { |
4450 | IPFERROR(8); |
4451 | error = EINVAL; |
4452 | goto donenolock; |
4453 | } |
4454 | |
4455 | family = fp->fr_family; |
4456 | uptr = fp->fr_data; |
4457 | |
4458 | if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR || |
4459 | req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR) |
4460 | addrem = 0; |
4461 | else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) |
4462 | addrem = 1; |
4463 | else if (req == (ioctlcmd_t)SIOCZRLST) |
4464 | addrem = 2; |
4465 | else { |
4466 | IPFERROR(9); |
4467 | error = EINVAL; |
4468 | goto donenolock; |
4469 | } |
4470 | |
4471 | /* |
4472 | * Only filter rules for IPv4 or IPv6 are accepted. |
4473 | */ |
4474 | if (family == AF_INET) { |
4475 | /*EMPTY*/; |
4476 | #ifdef USE_INET6 |
4477 | } else if (family == AF_INET6) { |
4478 | /*EMPTY*/; |
4479 | #endif |
4480 | } else if (family != 0) { |
4481 | IPFERROR(10); |
4482 | error = EINVAL; |
4483 | goto donenolock; |
4484 | } |
4485 | |
4486 | /* |
4487 | * If the rule is being loaded from user space, i.e. we had to copy it |
4488 | * into kernel space, then do not trust the function pointer in the |
4489 | * rule. |
4490 | */ |
4491 | if ((makecopy == 1) && (fp->fr_func != NULL)) { |
4492 | if (ipf_findfunc(fp->fr_func) == NULL) { |
4493 | IPFERROR(11); |
4494 | error = ESRCH; |
4495 | goto donenolock; |
4496 | } |
4497 | |
4498 | if (addrem == 0) { |
4499 | error = ipf_funcinit(softc, fp); |
4500 | if (error != 0) |
4501 | goto donenolock; |
4502 | } |
4503 | } |
4504 | if ((fp->fr_flags & FR_CALLNOW) && |
4505 | ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { |
4506 | IPFERROR(142); |
4507 | error = ESRCH; |
4508 | goto donenolock; |
4509 | } |
4510 | if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) && |
4511 | ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { |
4512 | IPFERROR(143); |
4513 | error = ESRCH; |
4514 | goto donenolock; |
4515 | } |
4516 | |
4517 | ptr = NULL; |
4518 | |
4519 | if (FR_ISACCOUNT(fp->fr_flags)) |
4520 | unit = IPL_LOGCOUNT; |
4521 | |
4522 | /* |
4523 | * Check that each group name in the rule has a start index that |
4524 | * is valid. |
4525 | */ |
4526 | if (fp->fr_icmphead != -1) { |
4527 | if ((fp->fr_icmphead < 0) || |
4528 | (fp->fr_icmphead >= fp->fr_namelen)) { |
4529 | IPFERROR(136); |
4530 | error = EINVAL; |
4531 | goto donenolock; |
4532 | } |
4533 | if (!strcmp(FR_NAME(fp, fr_icmphead), "0" )) |
4534 | fp->fr_names[fp->fr_icmphead] = '\0'; |
4535 | } |
4536 | |
4537 | if (fp->fr_grhead != -1) { |
4538 | if ((fp->fr_grhead < 0) || |
4539 | (fp->fr_grhead >= fp->fr_namelen)) { |
4540 | IPFERROR(137); |
4541 | error = EINVAL; |
4542 | goto donenolock; |
4543 | } |
4544 | if (!strcmp(FR_NAME(fp, fr_grhead), "0" )) |
4545 | fp->fr_names[fp->fr_grhead] = '\0'; |
4546 | } |
4547 | |
4548 | if (fp->fr_group != -1) { |
4549 | if ((fp->fr_group < 0) || |
4550 | (fp->fr_group >= fp->fr_namelen)) { |
4551 | IPFERROR(138); |
4552 | error = EINVAL; |
4553 | goto donenolock; |
4554 | } |
4555 | if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) { |
4556 | /* |
4557 | * Allow loading rules that are in groups to cause |
4558 | * them to be created if they don't already exit. |
4559 | */ |
4560 | group = FR_NAME(fp, fr_group); |
4561 | if (addrem == 0) { |
4562 | fg = ipf_group_add(softc, group, NULL, |
4563 | fp->fr_flags, unit, set); |
4564 | if (fg == NULL) { |
4565 | IPFERROR(152); |
4566 | error = ESRCH; |
4567 | goto donenolock; |
4568 | } |
4569 | fp->fr_grp = fg; |
4570 | } else { |
4571 | fg = ipf_findgroup(softc, group, unit, |
4572 | set, NULL); |
4573 | if (fg == NULL) { |
4574 | IPFERROR(12); |
4575 | error = ESRCH; |
4576 | goto donenolock; |
4577 | } |
4578 | } |
4579 | |
4580 | if (fg->fg_flags == 0) { |
4581 | fg->fg_flags = fp->fr_flags & FR_INOUT; |
4582 | } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) { |
4583 | IPFERROR(13); |
4584 | error = ESRCH; |
4585 | goto donenolock; |
4586 | } |
4587 | } |
4588 | } else { |
4589 | /* |
4590 | * If a rule is going to be part of a group then it does |
4591 | * not matter whether it is an in or out rule, but if it |
4592 | * isn't in a group, then it does... |
4593 | */ |
4594 | if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) { |
4595 | IPFERROR(14); |
4596 | error = EINVAL; |
4597 | goto donenolock; |
4598 | } |
4599 | } |
4600 | in = (fp->fr_flags & FR_INQUE) ? 0 : 1; |
4601 | |
4602 | /* |
4603 | * Work out which rule list this change is being applied to. |
4604 | */ |
4605 | ftail = NULL; |
4606 | fprev = NULL; |
4607 | if (unit == IPL_LOGAUTH) { |
4608 | if ((fp->fr_tifs[0].fd_ptr != NULL) || |
4609 | (fp->fr_tifs[1].fd_ptr != NULL) || |
4610 | (fp->fr_dif.fd_ptr != NULL) || |
4611 | (fp->fr_flags & FR_FASTROUTE)) { |
4612 | IPFERROR(145); |
4613 | error = EINVAL; |
4614 | goto donenolock; |
4615 | } |
4616 | fprev = ipf_auth_rulehead(softc); |
4617 | } else { |
4618 | if (FR_ISACCOUNT(fp->fr_flags)) |
4619 | fprev = &softc->ipf_acct[in][set]; |
4620 | else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) |
4621 | fprev = &softc->ipf_rules[in][set]; |
4622 | } |
4623 | if (fprev == NULL) { |
4624 | IPFERROR(15); |
4625 | error = ESRCH; |
4626 | goto donenolock; |
4627 | } |
4628 | |
4629 | if (fg != NULL) |
4630 | fprev = &fg->fg_start; |
4631 | |
4632 | /* |
4633 | * Copy in extra data for the rule. |
4634 | */ |
4635 | if (fp->fr_dsize != 0) { |
4636 | if (makecopy != 0) { |
4637 | KMALLOCS(ptr, void *, fp->fr_dsize); |
4638 | if (ptr == NULL) { |
4639 | IPFERROR(16); |
4640 | error = ENOMEM; |
4641 | goto donenolock; |
4642 | } |
4643 | |
4644 | /* |
4645 | * The bcopy case is for when the data is appended |
4646 | * to the rule by ipf_in_compat(). |
4647 | */ |
4648 | if (uptr >= (void *)fp && |
4649 | uptr < (void *)((char *)fp + fp->fr_size)) { |
4650 | bcopy(uptr, ptr, fp->fr_dsize); |
4651 | error = 0; |
4652 | } else { |
4653 | error = COPYIN(uptr, ptr, fp->fr_dsize); |
4654 | if (error != 0) { |
4655 | IPFERROR(17); |
4656 | error = EFAULT; |
4657 | goto donenolock; |
4658 | } |
4659 | } |
4660 | } else { |
4661 | ptr = uptr; |
4662 | } |
4663 | fp->fr_data = ptr; |
4664 | } else { |
4665 | fp->fr_data = NULL; |
4666 | } |
4667 | |
4668 | /* |
4669 | * Perform per-rule type sanity checks of their members. |
4670 | * All code after this needs to be aware that allocated memory |
4671 | * may need to be free'd before exiting. |
4672 | */ |
4673 | switch (fp->fr_type & ~FR_T_BUILTIN) |
4674 | { |
4675 | #if defined(IPFILTER_BPF) |
4676 | case FR_T_BPFOPC : |
4677 | if (fp->fr_dsize == 0) { |
4678 | IPFERROR(19); |
4679 | error = EINVAL; |
4680 | break; |
4681 | } |
4682 | if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { |
4683 | IPFERROR(20); |
4684 | error = EINVAL; |
4685 | break; |
4686 | } |
4687 | break; |
4688 | #endif |
4689 | case FR_T_IPF : |
4690 | /* |
4691 | * Preparation for error case at the bottom of this function. |
4692 | */ |
4693 | if (fp->fr_datype == FRI_LOOKUP) |
4694 | fp->fr_dstptr = NULL; |
4695 | if (fp->fr_satype == FRI_LOOKUP) |
4696 | fp->fr_srcptr = NULL; |
4697 | |
4698 | if (fp->fr_dsize != sizeof(fripf_t)) { |
4699 | IPFERROR(21); |
4700 | error = EINVAL; |
4701 | break; |
4702 | } |
4703 | |
4704 | /* |
4705 | * Allowing a rule with both "keep state" and "with oow" is |
4706 | * pointless because adding a state entry to the table will |
4707 | * fail with the out of window (oow) flag set. |
4708 | */ |
4709 | if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { |
4710 | IPFERROR(22); |
4711 | error = EINVAL; |
4712 | break; |
4713 | } |
4714 | |
4715 | switch (fp->fr_satype) |
4716 | { |
4717 | case FRI_BROADCAST : |
4718 | case FRI_DYNAMIC : |
4719 | case FRI_NETWORK : |
4720 | case FRI_NETMASKED : |
4721 | case FRI_PEERADDR : |
4722 | if (fp->fr_sifpidx < 0) { |
4723 | IPFERROR(23); |
4724 | error = EINVAL; |
4725 | } |
4726 | break; |
4727 | case FRI_LOOKUP : |
4728 | fp->fr_srcptr = ipf_findlookup(softc, unit, fp, |
4729 | &fp->fr_src6, |
4730 | &fp->fr_smsk6); |
4731 | if (fp->fr_srcfunc == NULL) { |
4732 | IPFERROR(132); |
4733 | error = ESRCH; |
4734 | break; |
4735 | } |
4736 | break; |
4737 | case FRI_NORMAL : |
4738 | break; |
4739 | default : |
4740 | IPFERROR(133); |
4741 | error = EINVAL; |
4742 | break; |
4743 | } |
4744 | if (error != 0) |
4745 | break; |
4746 | |
4747 | switch (fp->fr_datype) |
4748 | { |
4749 | case FRI_BROADCAST : |
4750 | case FRI_DYNAMIC : |
4751 | case FRI_NETWORK : |
4752 | case FRI_NETMASKED : |
4753 | case FRI_PEERADDR : |
4754 | if (fp->fr_difpidx < 0) { |
4755 | IPFERROR(24); |
4756 | error = EINVAL; |
4757 | } |
4758 | break; |
4759 | case FRI_LOOKUP : |
4760 | fp->fr_dstptr = ipf_findlookup(softc, unit, fp, |
4761 | &fp->fr_dst6, |
4762 | &fp->fr_dmsk6); |
4763 | if (fp->fr_dstfunc == NULL) { |
4764 | IPFERROR(134); |
4765 | error = ESRCH; |
4766 | } |
4767 | break; |
4768 | case FRI_NORMAL : |
4769 | break; |
4770 | default : |
4771 | IPFERROR(135); |
4772 | error = EINVAL; |
4773 | } |
4774 | break; |
4775 | |
4776 | case FR_T_NONE : |
4777 | case FR_T_CALLFUNC : |
4778 | case FR_T_COMPIPF : |
4779 | break; |
4780 | |
4781 | case FR_T_IPFEXPR : |
4782 | if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) { |
4783 | IPFERROR(25); |
4784 | error = EINVAL; |
4785 | } |
4786 | break; |
4787 | |
4788 | default : |
4789 | IPFERROR(26); |
4790 | error = EINVAL; |
4791 | break; |
4792 | } |
4793 | if (error != 0) |
4794 | goto donenolock; |
4795 | |
4796 | if (fp->fr_tif.fd_name != -1) { |
4797 | if ((fp->fr_tif.fd_name < 0) || |
4798 | (fp->fr_tif.fd_name >= fp->fr_namelen)) { |
4799 | IPFERROR(139); |
4800 | error = EINVAL; |
4801 | goto donenolock; |
4802 | } |
4803 | } |
4804 | |
4805 | if (fp->fr_dif.fd_name != -1) { |
4806 | if ((fp->fr_dif.fd_name < 0) || |
4807 | (fp->fr_dif.fd_name >= fp->fr_namelen)) { |
4808 | IPFERROR(140); |
4809 | error = EINVAL; |
4810 | goto donenolock; |
4811 | } |
4812 | } |
4813 | |
4814 | if (fp->fr_rif.fd_name != -1) { |
4815 | if ((fp->fr_rif.fd_name < 0) || |
4816 | (fp->fr_rif.fd_name >= fp->fr_namelen)) { |
4817 | IPFERROR(141); |
4818 | error = EINVAL; |
4819 | goto donenolock; |
4820 | } |
4821 | } |
4822 | |
4823 | /* |
4824 | * Lookup all the interface names that are part of the rule. |
4825 | */ |
4826 | error = ipf_synclist(softc, fp, NULL); |
4827 | if (error != 0) |
4828 | goto donenolock; |
4829 | fp->fr_statecnt = 0; |
4830 | if (fp->fr_srctrack.ht_max_nodes != 0) |
4831 | ipf_rb_ht_init(&fp->fr_srctrack); |
4832 | |
4833 | /* |
4834 | * Look for an existing matching filter rule, but don't include the |
4835 | * next or interface pointer in the comparison (fr_next, fr_ifa). |
4836 | * This elminates rules which are indentical being loaded. Checksum |
4837 | * the constant part of the filter rule to make comparisons quicker |
4838 | * (this meaning no pointers are included). |
4839 | */ |
4840 | for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; |
4841 | p < pp; p++) |
4842 | fp->fr_cksum += *p; |
4843 | pp = (u_int *)((char *)fp->fr_caddr + fp->fr_dsize); |
4844 | for (p = (u_int *)fp->fr_data; p < pp; p++) |
4845 | fp->fr_cksum += *p; |
4846 | |
4847 | WRITE_ENTER(&softc->ipf_mutex); |
4848 | |
4849 | /* |
4850 | * Now that the filter rule lists are locked, we can walk the |
4851 | * chain of them without fear. |
4852 | */ |
4853 | ftail = fprev; |
4854 | for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { |
4855 | if (fp->fr_collect <= f->fr_collect) { |
4856 | ftail = fprev; |
4857 | f = NULL; |
4858 | break; |
4859 | } |
4860 | fprev = ftail; |
4861 | } |
4862 | |
4863 | for (; (f = *ftail) != NULL; ftail = &f->fr_next) { |
4864 | DT2(rule_cmp, frentry_t *, fp, frentry_t *, f); |
4865 | if (ipf_rule_compare(fp, f) == 0) |
4866 | break; |
4867 | } |
4868 | |
4869 | /* |
4870 | * If zero'ing statistics, copy current to caller and zero. |
4871 | */ |
4872 | if (addrem == 2) { |
4873 | if (f == NULL) { |
4874 | IPFERROR(27); |
4875 | error = ESRCH; |
4876 | } else { |
4877 | /* |
4878 | * Copy and reduce lock because of impending copyout. |
4879 | * Well we should, but if we do then the atomicity of |
4880 | * this call and the correctness of fr_hits and |
4881 | * fr_bytes cannot be guaranteed. As it is, this code |
4882 | * only resets them to 0 if they are successfully |
4883 | * copied out into user space. |
4884 | */ |
4885 | bcopy((char *)f, (char *)fp, f->fr_size); |
4886 | /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */ |
4887 | |
4888 | /* |
4889 | * When we copy this rule back out, set the data |
4890 | * pointer to be what it was in user space. |
4891 | */ |
4892 | fp->fr_data = uptr; |
4893 | error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY); |
4894 | |
4895 | if (error == 0) { |
4896 | if ((f->fr_dsize != 0) && (uptr != NULL)) |
4897 | error = COPYOUT(f->fr_data, uptr, |
4898 | f->fr_dsize); |
4899 | if (error != 0) { |
4900 | IPFERROR(28); |
4901 | error = EFAULT; |
4902 | } |
4903 | if (error == 0) { |
4904 | f->fr_hits = 0; |
4905 | f->fr_bytes = 0; |
4906 | } |
4907 | } |
4908 | } |
4909 | |
4910 | if (makecopy != 0) { |
4911 | if (ptr != NULL) { |
4912 | KFREES(ptr, fp->fr_dsize); |
4913 | } |
4914 | KFREES(fp, fp->fr_size); |
4915 | } |
4916 | RWLOCK_EXIT(&softc->ipf_mutex); |
4917 | return error; |
4918 | } |
4919 | |
4920 | if (!f) { |
4921 | /* |
4922 | * At the end of this, ftail must point to the place where the |
4923 | * new rule is to be saved/inserted/added. |
4924 | * For SIOCAD*FR, this should be the last rule in the group of |
4925 | * rules that have equal fr_collect fields. |
4926 | * For SIOCIN*FR, ... |
4927 | */ |
4928 | if (req == (ioctlcmd_t)SIOCADAFR || |
4929 | req == (ioctlcmd_t)SIOCADIFR) { |
4930 | |
4931 | for (ftail = fprev; (f = *ftail) != NULL; ) { |
4932 | if (f->fr_collect > fp->fr_collect) |
4933 | break; |
4934 | ftail = &f->fr_next; |
4935 | fprev = ftail; |
4936 | } |
4937 | ftail = fprev; |
4938 | f = NULL; |
4939 | ptr = NULL; |
4940 | } else if (req == (ioctlcmd_t)SIOCINAFR || |
4941 | req == (ioctlcmd_t)SIOCINIFR) { |
4942 | while ((f = *fprev) != NULL) { |
4943 | if (f->fr_collect >= fp->fr_collect) |
4944 | break; |
4945 | fprev = &f->fr_next; |
4946 | } |
4947 | ftail = fprev; |
4948 | if (fp->fr_hits != 0) { |
4949 | while (fp->fr_hits && (f = *ftail)) { |
4950 | if (f->fr_collect != fp->fr_collect) |
4951 | break; |
4952 | fprev = ftail; |
4953 | ftail = &f->fr_next; |
4954 | fp->fr_hits--; |
4955 | } |
4956 | } |
4957 | f = NULL; |
4958 | ptr = NULL; |
4959 | } |
4960 | } |
4961 | |
4962 | /* |
4963 | * Request to remove a rule. |
4964 | */ |
4965 | if (addrem == 1) { |
4966 | if (!f) { |
4967 | IPFERROR(29); |
4968 | error = ESRCH; |
4969 | } else { |
4970 | /* |
4971 | * Do not allow activity from user space to interfere |
4972 | * with rules not loaded that way. |
4973 | */ |
4974 | if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { |
4975 | IPFERROR(30); |
4976 | error = EPERM; |
4977 | goto done; |
4978 | } |
4979 | |
4980 | /* |
4981 | * Return EBUSY if the rule is being reference by |
4982 | * something else (eg state information.) |
4983 | */ |
4984 | if (f->fr_ref > 1) { |
4985 | IPFERROR(31); |
4986 | error = EBUSY; |
4987 | goto done; |
4988 | } |
4989 | #ifdef IPFILTER_SCAN |
4990 | if (f->fr_isctag != -1 && |
4991 | (f->fr_isc != (struct ipscan *)-1)) |
4992 | ipf_scan_detachfr(f); |
4993 | #endif |
4994 | |
4995 | if (unit == IPL_LOGAUTH) { |
4996 | error = ipf_auth_precmd(softc, req, f, ftail); |
4997 | goto done; |
4998 | } |
4999 | |
5000 | ipf_rule_delete(softc, f, unit, set); |
5001 | |
5002 | need_free = makecopy; |
5003 | } |
5004 | } else { |
5005 | /* |
5006 | * Not removing, so we must be adding/inserting a rule. |
5007 | */ |
5008 | if (f != NULL) { |
5009 | IPFERROR(32); |
5010 | error = EEXIST; |
5011 | goto done; |
5012 | } |
5013 | if (unit == IPL_LOGAUTH) { |
5014 | error = ipf_auth_precmd(softc, req, fp, ftail); |
5015 | goto done; |
5016 | } |
5017 | |
5018 | MUTEX_NUKE(&fp->fr_lock); |
5019 | MUTEX_INIT(&fp->fr_lock, "filter rule lock" ); |
5020 | if (fp->fr_die != 0) |
5021 | ipf_rule_expire_insert(softc, fp, set); |
5022 | |
5023 | fp->fr_hits = 0; |
5024 | if (makecopy != 0) |
5025 | fp->fr_ref = 1; |
5026 | fp->fr_pnext = ftail; |
5027 | fp->fr_next = *ftail; |
5028 | if (fp->fr_next != NULL) |
5029 | fp->fr_next->fr_pnext = &fp->fr_next; |
5030 | *ftail = fp; |
5031 | if (addrem == 0) |
5032 | ipf_fixskip(ftail, fp, 1); |
5033 | |
5034 | fp->fr_icmpgrp = NULL; |
5035 | if (fp->fr_icmphead != -1) { |
5036 | group = FR_NAME(fp, fr_icmphead); |
5037 | fg = ipf_group_add(softc, group, fp, 0, unit, set); |
5038 | fp->fr_icmpgrp = fg; |
5039 | } |
5040 | |
5041 | fp->fr_grphead = NULL; |
5042 | if (fp->fr_grhead != -1) { |
5043 | group = FR_NAME(fp, fr_grhead); |
5044 | fg = ipf_group_add(softc, group, fp, fp->fr_flags, |
5045 | unit, set); |
5046 | fp->fr_grphead = fg; |
5047 | } |
5048 | } |
5049 | done: |
5050 | RWLOCK_EXIT(&softc->ipf_mutex); |
5051 | donenolock: |
5052 | if (need_free || (error != 0)) { |
5053 | if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { |
5054 | if ((fp->fr_satype == FRI_LOOKUP) && |
5055 | (fp->fr_srcptr != NULL)) |
5056 | ipf_lookup_deref(softc, fp->fr_srctype, |
5057 | fp->fr_srcptr); |
5058 | if ((fp->fr_datype == FRI_LOOKUP) && |
5059 | (fp->fr_dstptr != NULL)) |
5060 | ipf_lookup_deref(softc, fp->fr_dsttype, |
5061 | fp->fr_dstptr); |
5062 | } |
5063 | if (fp->fr_grp != NULL) { |
5064 | WRITE_ENTER(&softc->ipf_mutex); |
5065 | ipf_group_del(softc, fp->fr_grp, fp); |
5066 | RWLOCK_EXIT(&softc->ipf_mutex); |
5067 | } |
5068 | if ((ptr != NULL) && (makecopy != 0)) { |
5069 | KFREES(ptr, fp->fr_dsize); |
5070 | } |
5071 | KFREES(fp, fp->fr_size); |
5072 | } |
5073 | return (error); |
5074 | } |
5075 | |
5076 | |
5077 | /* ------------------------------------------------------------------------ */ |
5078 | /* Function: ipf_rule_delete */ |
5079 | /* Returns: Nil */ |
5080 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5081 | /* f(I) - pointer to the rule being deleted */ |
5082 | /* ftail(I) - pointer to the pointer to f */ |
5083 | /* unit(I) - device for which this is for */ |
5084 | /* set(I) - 1 or 0 (filter set) */ |
5085 | /* */ |
5086 | /* This function attempts to do what it can to delete a filter rule: remove */ |
5087 | /* it from any linked lists and remove any groups it is responsible for. */ |
5088 | /* But in the end, removing a rule can only drop the reference count - we */ |
5089 | /* must use that as the guide for whether or not it can be freed. */ |
5090 | /* ------------------------------------------------------------------------ */ |
5091 | static void |
5092 | ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set) |
5093 | { |
5094 | |
5095 | /* |
5096 | * If fr_pdnext is set, then the rule is on the expire list, so |
5097 | * remove it from there. |
5098 | */ |
5099 | if (f->fr_pdnext != NULL) { |
5100 | *f->fr_pdnext = f->fr_dnext; |
5101 | if (f->fr_dnext != NULL) |
5102 | f->fr_dnext->fr_pdnext = f->fr_pdnext; |
5103 | f->fr_pdnext = NULL; |
5104 | f->fr_dnext = NULL; |
5105 | } |
5106 | |
5107 | ipf_fixskip(f->fr_pnext, f, -1); |
5108 | if (f->fr_pnext != NULL) |
5109 | *f->fr_pnext = f->fr_next; |
5110 | if (f->fr_next != NULL) |
5111 | f->fr_next->fr_pnext = f->fr_pnext; |
5112 | f->fr_pnext = NULL; |
5113 | f->fr_next = NULL; |
5114 | |
5115 | (void) ipf_derefrule(softc, &f); |
5116 | } |
5117 | |
5118 | /* ------------------------------------------------------------------------ */ |
5119 | /* Function: ipf_rule_expire_insert */ |
5120 | /* Returns: Nil */ |
5121 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5122 | /* f(I) - pointer to rule to be added to expire list */ |
5123 | /* set(I) - 1 or 0 (filter set) */ |
5124 | /* */ |
5125 | /* If the new rule has a given expiration time, insert it into the list of */ |
5126 | /* expiring rules with the ones to be removed first added to the front of */ |
5127 | /* the list. The insertion is O(n) but it is kept sorted for quick scans at */ |
5128 | /* expiration interval checks. */ |
5129 | /* ------------------------------------------------------------------------ */ |
5130 | static void |
5131 | ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set) |
5132 | { |
5133 | frentry_t *fr; |
5134 | |
5135 | /* |
5136 | */ |
5137 | |
5138 | f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die); |
5139 | for (fr = softc->ipf_rule_explist[set]; fr != NULL; |
5140 | fr = fr->fr_dnext) { |
5141 | if (f->fr_die < fr->fr_die) |
5142 | break; |
5143 | if (fr->fr_dnext == NULL) { |
5144 | /* |
5145 | * We've got to the last rule and everything |
5146 | * wanted to be expired before this new node, |
5147 | * so we have to tack it on the end... |
5148 | */ |
5149 | fr->fr_dnext = f; |
5150 | f->fr_pdnext = &fr->fr_dnext; |
5151 | fr = NULL; |
5152 | break; |
5153 | } |
5154 | } |
5155 | |
5156 | if (softc->ipf_rule_explist[set] == NULL) { |
5157 | softc->ipf_rule_explist[set] = f; |
5158 | f->fr_pdnext = &softc->ipf_rule_explist[set]; |
5159 | } else if (fr != NULL) { |
5160 | f->fr_dnext = fr; |
5161 | f->fr_pdnext = fr->fr_pdnext; |
5162 | fr->fr_pdnext = &f->fr_dnext; |
5163 | } |
5164 | } |
5165 | |
5166 | |
5167 | /* ------------------------------------------------------------------------ */ |
5168 | /* Function: ipf_findlookup */ |
5169 | /* Returns: NULL = failure, else success */ |
5170 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5171 | /* unit(I) - ipf device we want to find match for */ |
5172 | /* fp(I) - rule for which lookup is for */ |
5173 | /* addrp(I) - pointer to lookup information in address struct */ |
5174 | /* maskp(O) - pointer to lookup information for storage */ |
5175 | /* */ |
5176 | /* When using pools and hash tables to store addresses for matching in */ |
5177 | /* rules, it is necessary to resolve both the object referred to by the */ |
5178 | /* name or address (and return that pointer) and also provide the means by */ |
5179 | /* which to determine if an address belongs to that object to make the */ |
5180 | /* packet matching quicker. */ |
5181 | /* ------------------------------------------------------------------------ */ |
5182 | static void * |
5183 | ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr, |
5184 | i6addr_t *addrp, i6addr_t *maskp) |
5185 | { |
5186 | void *ptr = NULL; |
5187 | |
5188 | switch (addrp->iplookupsubtype) |
5189 | { |
5190 | case 0 : |
5191 | ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype, |
5192 | addrp->iplookupnum, |
5193 | &maskp->iplookupfunc); |
5194 | break; |
5195 | case 1 : |
5196 | if (addrp->iplookupname < 0) |
5197 | break; |
5198 | if (addrp->iplookupname >= fr->fr_namelen) |
5199 | break; |
5200 | ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype, |
5201 | fr->fr_names + addrp->iplookupname, |
5202 | &maskp->iplookupfunc); |
5203 | break; |
5204 | default : |
5205 | break; |
5206 | } |
5207 | |
5208 | return ptr; |
5209 | } |
5210 | |
5211 | |
5212 | /* ------------------------------------------------------------------------ */ |
5213 | /* Function: ipf_funcinit */ |
5214 | /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ |
5215 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5216 | /* fr(I) - pointer to filter rule */ |
5217 | /* */ |
5218 | /* If a rule is a call rule, then check if the function it points to needs */ |
5219 | /* an init function to be called now the rule has been loaded. */ |
5220 | /* ------------------------------------------------------------------------ */ |
5221 | static int |
5222 | ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr) |
5223 | { |
5224 | ipfunc_resolve_t *ft; |
5225 | int err; |
5226 | |
5227 | IPFERROR(34); |
5228 | err = ESRCH; |
5229 | |
5230 | for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) |
5231 | if (ft->ipfu_addr == fr->fr_func) { |
5232 | err = 0; |
5233 | if (ft->ipfu_init != NULL) |
5234 | err = (*ft->ipfu_init)(softc, fr); |
5235 | break; |
5236 | } |
5237 | return err; |
5238 | } |
5239 | |
5240 | |
5241 | /* ------------------------------------------------------------------------ */ |
5242 | /* Function: ipf_funcfini */ |
5243 | /* Returns: Nil */ |
5244 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5245 | /* fr(I) - pointer to filter rule */ |
5246 | /* */ |
5247 | /* For a given filter rule, call the matching "fini" function if the rule */ |
5248 | /* is using a known function that would have resulted in the "init" being */ |
5249 | /* called for ealier. */ |
5250 | /* ------------------------------------------------------------------------ */ |
5251 | static void |
5252 | ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr) |
5253 | { |
5254 | ipfunc_resolve_t *ft; |
5255 | |
5256 | for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) |
5257 | if (ft->ipfu_addr == fr->fr_func) { |
5258 | if (ft->ipfu_fini != NULL) |
5259 | (void) (*ft->ipfu_fini)(softc, fr); |
5260 | break; |
5261 | } |
5262 | } |
5263 | |
5264 | |
5265 | /* ------------------------------------------------------------------------ */ |
5266 | /* Function: ipf_findfunc */ |
5267 | /* Returns: ipfunc_t - pointer to function if found, else NULL */ |
5268 | /* Parameters: funcptr(I) - function pointer to lookup */ |
5269 | /* */ |
5270 | /* Look for a function in the table of known functions. */ |
5271 | /* ------------------------------------------------------------------------ */ |
5272 | static ipfunc_t |
5273 | ipf_findfunc(ipfunc_t funcptr) |
5274 | { |
5275 | ipfunc_resolve_t *ft; |
5276 | |
5277 | for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) |
5278 | if (ft->ipfu_addr == funcptr) |
5279 | return funcptr; |
5280 | return NULL; |
5281 | } |
5282 | |
5283 | |
5284 | /* ------------------------------------------------------------------------ */ |
5285 | /* Function: ipf_resolvefunc */ |
5286 | /* Returns: int - 0 == success, else error */ |
5287 | /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ |
5288 | /* */ |
5289 | /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ |
5290 | /* This will either be the function name (if the pointer is set) or the */ |
5291 | /* function pointer if the name is set. When found, fill in the other one */ |
5292 | /* so that the entire, complete, structure can be copied back to user space.*/ |
5293 | /* ------------------------------------------------------------------------ */ |
5294 | int |
5295 | ipf_resolvefunc(ipf_main_softc_t *softc, void *data) |
5296 | { |
5297 | ipfunc_resolve_t res, *ft; |
5298 | int error; |
5299 | |
5300 | error = BCOPYIN(data, &res, sizeof(res)); |
5301 | if (error != 0) { |
5302 | IPFERROR(123); |
5303 | return EFAULT; |
5304 | } |
5305 | |
5306 | if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { |
5307 | for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) |
5308 | if (strncmp(res.ipfu_name, ft->ipfu_name, |
5309 | sizeof(res.ipfu_name)) == 0) { |
5310 | res.ipfu_addr = ft->ipfu_addr; |
5311 | res.ipfu_init = ft->ipfu_init; |
5312 | if (COPYOUT(&res, data, sizeof(res)) != 0) { |
5313 | IPFERROR(35); |
5314 | return EFAULT; |
5315 | } |
5316 | return 0; |
5317 | } |
5318 | } |
5319 | if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { |
5320 | for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) |
5321 | if (ft->ipfu_addr == res.ipfu_addr) { |
5322 | (void) strncpy(res.ipfu_name, ft->ipfu_name, |
5323 | sizeof(res.ipfu_name)); |
5324 | res.ipfu_init = ft->ipfu_init; |
5325 | if (COPYOUT(&res, data, sizeof(res)) != 0) { |
5326 | IPFERROR(36); |
5327 | return EFAULT; |
5328 | } |
5329 | return 0; |
5330 | } |
5331 | } |
5332 | IPFERROR(37); |
5333 | return ESRCH; |
5334 | } |
5335 | |
5336 | |
5337 | #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \ |
5338 | !defined(__FreeBSD__)) || \ |
5339 | FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \ |
5340 | OPENBSD_LT_REV(200006) |
5341 | /* |
5342 | * From: NetBSD |
5343 | * ppsratecheck(): packets (or events) per second limitation. |
5344 | */ |
5345 | int |
5346 | ppsratecheck(lasttime, curpps, maxpps) |
5347 | struct timeval *lasttime; |
5348 | int *curpps; |
5349 | int maxpps; /* maximum pps allowed */ |
5350 | { |
5351 | struct timeval tv, delta; |
5352 | int rv; |
5353 | |
5354 | GETKTIME(&tv); |
5355 | |
5356 | delta.tv_sec = tv.tv_sec - lasttime->tv_sec; |
5357 | delta.tv_usec = tv.tv_usec - lasttime->tv_usec; |
5358 | if (delta.tv_usec < 0) { |
5359 | delta.tv_sec--; |
5360 | delta.tv_usec += 1000000; |
5361 | } |
5362 | |
5363 | /* |
5364 | * check for 0,0 is so that the message will be seen at least once. |
5365 | * if more than one second have passed since the last update of |
5366 | * lasttime, reset the counter. |
5367 | * |
5368 | * we do increment *curpps even in *curpps < maxpps case, as some may |
5369 | * try to use *curpps for stat purposes as well. |
5370 | */ |
5371 | if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || |
5372 | delta.tv_sec >= 1) { |
5373 | *lasttime = tv; |
5374 | *curpps = 0; |
5375 | rv = 1; |
5376 | } else if (maxpps < 0) |
5377 | rv = 1; |
5378 | else if (*curpps < maxpps) |
5379 | rv = 1; |
5380 | else |
5381 | rv = 0; |
5382 | *curpps = *curpps + 1; |
5383 | |
5384 | return (rv); |
5385 | } |
5386 | #endif |
5387 | |
5388 | |
5389 | /* ------------------------------------------------------------------------ */ |
5390 | /* Function: ipf_derefrule */ |
5391 | /* Returns: int - 0 == rule freed up, else rule not freed */ |
5392 | /* Parameters: fr(I) - pointer to filter rule */ |
5393 | /* */ |
5394 | /* Decrement the reference counter to a rule by one. If it reaches zero, */ |
5395 | /* free it and any associated storage space being used by it. */ |
5396 | /* ------------------------------------------------------------------------ */ |
5397 | int |
5398 | ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp) |
5399 | { |
5400 | frentry_t *fr; |
5401 | frdest_t *fdp; |
5402 | |
5403 | fr = *frp; |
5404 | *frp = NULL; |
5405 | |
5406 | MUTEX_ENTER(&fr->fr_lock); |
5407 | fr->fr_ref--; |
5408 | if (fr->fr_ref == 0) { |
5409 | MUTEX_EXIT(&fr->fr_lock); |
5410 | MUTEX_DESTROY(&fr->fr_lock); |
5411 | |
5412 | ipf_funcfini(softc, fr); |
5413 | |
5414 | fdp = &fr->fr_tif; |
5415 | if (fdp->fd_type == FRD_DSTLIST) |
5416 | ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); |
5417 | |
5418 | fdp = &fr->fr_rif; |
5419 | if (fdp->fd_type == FRD_DSTLIST) |
5420 | ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); |
5421 | |
5422 | fdp = &fr->fr_dif; |
5423 | if (fdp->fd_type == FRD_DSTLIST) |
5424 | ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); |
5425 | |
5426 | if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && |
5427 | fr->fr_satype == FRI_LOOKUP) |
5428 | ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr); |
5429 | if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && |
5430 | fr->fr_datype == FRI_LOOKUP) |
5431 | ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr); |
5432 | |
5433 | if (fr->fr_grp != NULL) |
5434 | ipf_group_del(softc, fr->fr_grp, fr); |
5435 | |
5436 | if (fr->fr_grphead != NULL) |
5437 | ipf_group_del(softc, fr->fr_grphead, fr); |
5438 | |
5439 | if (fr->fr_icmpgrp != NULL) |
5440 | ipf_group_del(softc, fr->fr_icmpgrp, fr); |
5441 | |
5442 | if ((fr->fr_flags & FR_COPIED) != 0) { |
5443 | if (fr->fr_dsize) { |
5444 | KFREES(fr->fr_data, fr->fr_dsize); |
5445 | } |
5446 | KFREES(fr, fr->fr_size); |
5447 | return 0; |
5448 | } |
5449 | return 1; |
5450 | } else { |
5451 | MUTEX_EXIT(&fr->fr_lock); |
5452 | } |
5453 | return -1; |
5454 | } |
5455 | |
5456 | |
5457 | /* ------------------------------------------------------------------------ */ |
5458 | /* Function: ipf_grpmapinit */ |
5459 | /* Returns: int - 0 == success, else ESRCH because table entry not found*/ |
5460 | /* Parameters: fr(I) - pointer to rule to find hash table for */ |
5461 | /* */ |
5462 | /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ |
5463 | /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */ |
5464 | /* ------------------------------------------------------------------------ */ |
5465 | static int |
5466 | ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr) |
5467 | { |
5468 | char name[FR_GROUPLEN]; |
5469 | iphtable_t *iph; |
5470 | |
5471 | (void) snprintf(name, sizeof(name), "%d" , fr->fr_arg); |
5472 | iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name); |
5473 | if (iph == NULL) { |
5474 | IPFERROR(38); |
5475 | return ESRCH; |
5476 | } |
5477 | if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) { |
5478 | IPFERROR(39); |
5479 | return ESRCH; |
5480 | } |
5481 | iph->iph_ref++; |
5482 | fr->fr_ptr = iph; |
5483 | return 0; |
5484 | } |
5485 | |
5486 | |
5487 | /* ------------------------------------------------------------------------ */ |
5488 | /* Function: ipf_grpmapfini */ |
5489 | /* Returns: int - 0 == success, else ESRCH because table entry not found*/ |
5490 | /* Parameters: softc(I) - pointer to soft context main structure */ |
5491 | /* fr(I) - pointer to rule to release hash table for */ |
5492 | /* */ |
5493 | /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */ |
5494 | /* be called to undo what ipf_grpmapinit caused to be done. */ |
5495 | /* ------------------------------------------------------------------------ */ |
5496 | static int |
5497 | ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr) |
5498 | { |
5499 | iphtable_t *iph; |
5500 | iph = fr->fr_ptr; |
5501 | if (iph != NULL) |
5502 | ipf_lookup_deref(softc, IPLT_HASH, iph); |
5503 | return 0; |
5504 | } |
5505 | |
5506 | |
5507 | /* ------------------------------------------------------------------------ */ |
5508 | /* Function: ipf_srcgrpmap */ |
5509 | /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ |
5510 | /* Parameters: fin(I) - pointer to packet information */ |
5511 | /* passp(IO) - pointer to current/new filter decision (unused) */ |
5512 | /* */ |
5513 | /* Look for a rule group head in a hash table, using the source address as */ |
5514 | /* the key, and descend into that group and continue matching rules against */ |
5515 | /* the packet. */ |
5516 | /* ------------------------------------------------------------------------ */ |
5517 | frentry_t * |
5518 | ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp) |
5519 | { |
5520 | frgroup_t *fg; |
5521 | void *rval; |
5522 | |
5523 | rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, |
5524 | &fin->fin_src); |
5525 | if (rval == NULL) |
5526 | return NULL; |
5527 | |
5528 | fg = rval; |
5529 | fin->fin_fr = fg->fg_start; |
5530 | (void) ipf_scanlist(fin, *passp); |
5531 | return fin->fin_fr; |
5532 | } |
5533 | |
5534 | |
5535 | /* ------------------------------------------------------------------------ */ |
5536 | /* Function: ipf_dstgrpmap */ |
5537 | /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ |
5538 | /* Parameters: fin(I) - pointer to packet information */ |
5539 | /* passp(IO) - pointer to current/new filter decision (unused) */ |
5540 | /* */ |
5541 | /* Look for a rule group head in a hash table, using the destination */ |
5542 | /* address as the key, and descend into that group and continue matching */ |
5543 | /* rules against the packet. */ |
5544 | /* ------------------------------------------------------------------------ */ |
5545 | frentry_t * |
5546 | ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp) |
5547 | { |
5548 | frgroup_t *fg; |
5549 | void *rval; |
5550 | |
5551 | rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, |
5552 | &fin->fin_dst); |
5553 | if (rval == NULL) |
5554 | return NULL; |
5555 | |
5556 | fg = rval; |
5557 | fin->fin_fr = fg->fg_start; |
5558 | (void) ipf_scanlist(fin, *passp); |
5559 | return fin->fin_fr; |
5560 | } |
5561 | |
5562 | /* |
5563 | * Queue functions |
5564 | * =============== |
5565 | * These functions manage objects on queues for efficient timeouts. There |
5566 | * are a number of system defined queues as well as user defined timeouts. |
5567 | * It is expected that a lock is held in the domain in which the queue |
5568 | * belongs (i.e. either state or NAT) when calling any of these functions |
5569 | * that prevents ipf_freetimeoutqueue() from being called at the same time |
5570 | * as any other. |
5571 | */ |
5572 | |
5573 | |
5574 | /* ------------------------------------------------------------------------ */ |
5575 | /* Function: ipf_addtimeoutqueue */ |
5576 | /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ |
5577 | /* timeout queue with given interval. */ |
5578 | /* Parameters: parent(I) - pointer to pointer to parent node of this list */ |
5579 | /* of interface queues. */ |
5580 | /* seconds(I) - timeout value in seconds for this queue. */ |
5581 | /* */ |
5582 | /* This routine first looks for a timeout queue that matches the interval */ |
5583 | /* being requested. If it finds one, increments the reference counter and */ |
5584 | /* returns a pointer to it. If none are found, it allocates a new one and */ |
5585 | /* inserts it at the top of the list. */ |
5586 | /* */ |
5587 | /* Locking. */ |
5588 | /* It is assumed that the caller of this function has an appropriate lock */ |
5589 | /* held (exclusively) in the domain that encompases 'parent'. */ |
5590 | /* ------------------------------------------------------------------------ */ |
5591 | ipftq_t * |
5592 | ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds) |
5593 | { |
5594 | ipftq_t *ifq; |
5595 | u_int period; |
5596 | |
5597 | period = seconds * IPF_HZ_DIVIDE; |
5598 | |
5599 | MUTEX_ENTER(&softc->ipf_timeoutlock); |
5600 | for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { |
5601 | if (ifq->ifq_ttl == period) { |
5602 | /* |
5603 | * Reset the delete flag, if set, so the structure |
5604 | * gets reused rather than freed and reallocated. |
5605 | */ |
5606 | MUTEX_ENTER(&ifq->ifq_lock); |
5607 | ifq->ifq_flags &= ~IFQF_DELETE; |
5608 | ifq->ifq_ref++; |
5609 | MUTEX_EXIT(&ifq->ifq_lock); |
5610 | MUTEX_EXIT(&softc->ipf_timeoutlock); |
5611 | |
5612 | return ifq; |
5613 | } |
5614 | } |
5615 | |
5616 | KMALLOC(ifq, ipftq_t *); |
5617 | if (ifq != NULL) { |
5618 | MUTEX_NUKE(&ifq->ifq_lock); |
5619 | IPFTQ_INIT(ifq, period, "ipftq mutex" ); |
5620 | ifq->ifq_next = *parent; |
5621 | ifq->ifq_pnext = parent; |
5622 | ifq->ifq_flags = IFQF_USER; |
5623 | ifq->ifq_ref++; |
5624 | *parent = ifq; |
5625 | softc->ipf_userifqs++; |
5626 | } |
5627 | MUTEX_EXIT(&softc->ipf_timeoutlock); |
5628 | return ifq; |
5629 | } |
5630 | |
5631 | |
5632 | /* ------------------------------------------------------------------------ */ |
5633 | /* Function: ipf_deletetimeoutqueue */ |
5634 | /* Returns: int - new reference count value of the timeout queue */ |
5635 | /* Parameters: ifq(I) - timeout queue which is losing a reference. */ |
5636 | /* Locks: ifq->ifq_lock */ |
5637 | /* */ |
5638 | /* This routine must be called when we're discarding a pointer to a timeout */ |
5639 | /* queue object, taking care of the reference counter. */ |
5640 | /* */ |
5641 | /* Now that this just sets a DELETE flag, it requires the expire code to */ |
5642 | /* check the list of user defined timeout queues and call the free function */ |
5643 | /* below (currently commented out) to stop memory leaking. It is done this */ |
5644 | /* way because the locking may not be sufficient to safely do a free when */ |
5645 | /* this function is called. */ |
5646 | /* ------------------------------------------------------------------------ */ |
5647 | int |
5648 | ipf_deletetimeoutqueue(ipftq_t *ifq) |
5649 | { |
5650 | |
5651 | ifq->ifq_ref--; |
5652 | if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { |
5653 | ifq->ifq_flags |= IFQF_DELETE; |
5654 | } |
5655 | |
5656 | return ifq->ifq_ref; |
5657 | } |
5658 | |
5659 | |
5660 | /* ------------------------------------------------------------------------ */ |
5661 | /* Function: ipf_freetimeoutqueue */ |
5662 | /* Parameters: ifq(I) - timeout queue which is losing a reference. */ |
5663 | /* Returns: Nil */ |
5664 | /* */ |
5665 | /* Locking: */ |
5666 | /* It is assumed that the caller of this function has an appropriate lock */ |
5667 | /* held (exclusively) in the domain that encompases the callers "domain". */ |
5668 | /* The ifq_lock for this structure should not be held. */ |
5669 | /* */ |
5670 | /* Remove a user defined timeout queue from the list of queues it is in and */ |
5671 | /* tidy up after this is done. */ |
5672 | /* ------------------------------------------------------------------------ */ |
5673 | void |
5674 | ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq) |
5675 | { |
5676 | |
5677 | if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || |
5678 | ((ifq->ifq_flags & IFQF_USER) == 0)) { |
5679 | printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n" , |
5680 | (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, |
5681 | ifq->ifq_ref); |
5682 | return; |
5683 | } |
5684 | |
5685 | /* |
5686 | * Remove from its position in the list. |
5687 | */ |
5688 | *ifq->ifq_pnext = ifq->ifq_next; |
5689 | if (ifq->ifq_next != NULL) |
5690 | ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; |
5691 | ifq->ifq_next = NULL; |
5692 | ifq->ifq_pnext = NULL; |
5693 | |
5694 | MUTEX_DESTROY(&ifq->ifq_lock); |
5695 | ATOMIC_DEC(softc->ipf_userifqs); |
5696 | KFREE(ifq); |
5697 | } |
5698 | |
5699 | |
5700 | /* ------------------------------------------------------------------------ */ |
5701 | /* Function: ipf_deletequeueentry */ |
5702 | /* Returns: Nil */ |
5703 | /* Parameters: tqe(I) - timeout queue entry to delete */ |
5704 | /* */ |
5705 | /* Remove a tail queue entry from its queue and make it an orphan. */ |
5706 | /* ipf_deletetimeoutqueue is called to make sure the reference count on the */ |
5707 | /* queue is correct. We can't, however, call ipf_freetimeoutqueue because */ |
5708 | /* the correct lock(s) may not be held that would make it safe to do so. */ |
5709 | /* ------------------------------------------------------------------------ */ |
5710 | void |
5711 | ipf_deletequeueentry(ipftqent_t *tqe) |
5712 | { |
5713 | ipftq_t *ifq; |
5714 | |
5715 | ifq = tqe->tqe_ifq; |
5716 | |
5717 | MUTEX_ENTER(&ifq->ifq_lock); |
5718 | |
5719 | if (tqe->tqe_pnext != NULL) { |
5720 | *tqe->tqe_pnext = tqe->tqe_next; |
5721 | if (tqe->tqe_next != NULL) |
5722 | tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; |
5723 | else /* we must be the tail anyway */ |
5724 | ifq->ifq_tail = tqe->tqe_pnext; |
5725 | |
5726 | tqe->tqe_pnext = NULL; |
5727 | tqe->tqe_ifq = NULL; |
5728 | } |
5729 | |
5730 | (void) ipf_deletetimeoutqueue(ifq); |
5731 | ASSERT(ifq->ifq_ref > 0); |
5732 | |
5733 | MUTEX_EXIT(&ifq->ifq_lock); |
5734 | } |
5735 | |
5736 | |
5737 | /* ------------------------------------------------------------------------ */ |
5738 | /* Function: ipf_queuefront */ |
5739 | /* Returns: Nil */ |
5740 | /* Parameters: tqe(I) - pointer to timeout queue entry */ |
5741 | /* */ |
5742 | /* Move a queue entry to the front of the queue, if it isn't already there. */ |
5743 | /* ------------------------------------------------------------------------ */ |
5744 | void |
5745 | ipf_queuefront(ipftqent_t *tqe) |
5746 | { |
5747 | ipftq_t *ifq; |
5748 | |
5749 | ifq = tqe->tqe_ifq; |
5750 | if (ifq == NULL) |
5751 | return; |
5752 | |
5753 | MUTEX_ENTER(&ifq->ifq_lock); |
5754 | if (ifq->ifq_head != tqe) { |
5755 | *tqe->tqe_pnext = tqe->tqe_next; |
5756 | if (tqe->tqe_next) |
5757 | tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; |
5758 | else |
5759 | ifq->ifq_tail = tqe->tqe_pnext; |
5760 | |
5761 | tqe->tqe_next = ifq->ifq_head; |
5762 | ifq->ifq_head->tqe_pnext = &tqe->tqe_next; |
5763 | ifq->ifq_head = tqe; |
5764 | tqe->tqe_pnext = &ifq->ifq_head; |
5765 | } |
5766 | MUTEX_EXIT(&ifq->ifq_lock); |
5767 | } |
5768 | |
5769 | |
5770 | /* ------------------------------------------------------------------------ */ |
5771 | /* Function: ipf_queueback */ |
5772 | /* Returns: Nil */ |
5773 | /* Parameters: ticks(I) - ipf tick time to use with this call */ |
5774 | /* tqe(I) - pointer to timeout queue entry */ |
5775 | /* */ |
5776 | /* Move a queue entry to the back of the queue, if it isn't already there. */ |
5777 | /* We use use ticks to calculate the expiration and mark for when we last */ |
5778 | /* touched the structure. */ |
5779 | /* ------------------------------------------------------------------------ */ |
5780 | void |
5781 | ipf_queueback(u_long ticks, ipftqent_t *tqe) |
5782 | { |
5783 | ipftq_t *ifq; |
5784 | |
5785 | ifq = tqe->tqe_ifq; |
5786 | if (ifq == NULL) |
5787 | return; |
5788 | tqe->tqe_die = ticks + ifq->ifq_ttl; |
5789 | tqe->tqe_touched = ticks; |
5790 | |
5791 | MUTEX_ENTER(&ifq->ifq_lock); |
5792 | if (tqe->tqe_next != NULL) { /* at the end already ? */ |
5793 | /* |
5794 | * Remove from list |
5795 | */ |
5796 | *tqe->tqe_pnext = tqe->tqe_next; |
5797 | tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; |
5798 | |
5799 | /* |
5800 | * Make it the last entry. |
5801 | */ |
5802 | tqe->tqe_next = NULL; |
5803 | tqe->tqe_pnext = ifq->ifq_tail; |
5804 | *ifq->ifq_tail = tqe; |
5805 | ifq->ifq_tail = &tqe->tqe_next; |
5806 | } |
5807 | MUTEX_EXIT(&ifq->ifq_lock); |
5808 | } |
5809 | |
5810 | |
5811 | /* ------------------------------------------------------------------------ */ |
5812 | /* Function: ipf_queueappend */ |
5813 | /* Returns: Nil */ |
5814 | /* Parameters: ticks(I) - ipf tick time to use with this call */ |
5815 | /* tqe(I) - pointer to timeout queue entry */ |
5816 | /* ifq(I) - pointer to timeout queue */ |
5817 | /* parent(I) - owing object pointer */ |
5818 | /* */ |
5819 | /* Add a new item to this queue and put it on the very end. */ |
5820 | /* We use use ticks to calculate the expiration and mark for when we last */ |
5821 | /* touched the structure. */ |
5822 | /* ------------------------------------------------------------------------ */ |
5823 | void |
5824 | ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent) |
5825 | { |
5826 | |
5827 | MUTEX_ENTER(&ifq->ifq_lock); |
5828 | tqe->tqe_parent = parent; |
5829 | tqe->tqe_pnext = ifq->ifq_tail; |
5830 | *ifq->ifq_tail = tqe; |
5831 | ifq->ifq_tail = &tqe->tqe_next; |
5832 | tqe->tqe_next = NULL; |
5833 | tqe->tqe_ifq = ifq; |
5834 | tqe->tqe_die = ticks + ifq->ifq_ttl; |
5835 | tqe->tqe_touched = ticks; |
5836 | ifq->ifq_ref++; |
5837 | MUTEX_EXIT(&ifq->ifq_lock); |
5838 | } |
5839 | |
5840 | |
5841 | /* ------------------------------------------------------------------------ */ |
5842 | /* Function: ipf_movequeue */ |
5843 | /* Returns: Nil */ |
5844 | /* Parameters: tq(I) - pointer to timeout queue information */ |
5845 | /* oifp(I) - old timeout queue entry was on */ |
5846 | /* nifp(I) - new timeout queue to put entry on */ |
5847 | /* */ |
5848 | /* Move a queue entry from one timeout queue to another timeout queue. */ |
5849 | /* If it notices that the current entry is already last and does not need */ |
5850 | /* to move queue, the return. */ |
5851 | /* ------------------------------------------------------------------------ */ |
5852 | void |
5853 | ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq) |
5854 | { |
5855 | |
5856 | /* |
5857 | * If the queue hasn't changed and we last touched this entry at the |
5858 | * same ipf time, then we're not going to achieve anything by either |
5859 | * changing the ttl or moving it on the queue. |
5860 | */ |
5861 | if (oifq == nifq && tqe->tqe_touched == ticks) |
5862 | return; |
5863 | |
5864 | /* |
5865 | * For any of this to be outside the lock, there is a risk that two |
5866 | * packets entering simultaneously, with one changing to a different |
5867 | * queue and one not, could end up with things in a bizarre state. |
5868 | */ |
5869 | MUTEX_ENTER(&oifq->ifq_lock); |
5870 | |
5871 | tqe->tqe_touched = ticks; |
5872 | tqe->tqe_die = ticks + nifq->ifq_ttl; |
5873 | /* |
5874 | * Is the operation here going to be a no-op ? |
5875 | */ |
5876 | if (oifq == nifq) { |
5877 | if ((tqe->tqe_next == NULL) || |
5878 | (tqe->tqe_next->tqe_die == tqe->tqe_die)) { |
5879 | MUTEX_EXIT(&oifq->ifq_lock); |
5880 | return; |
5881 | } |
5882 | } |
5883 | |
5884 | /* |
5885 | * Remove from the old queue |
5886 | */ |
5887 | *tqe->tqe_pnext = tqe->tqe_next; |
5888 | if (tqe->tqe_next) |
5889 | tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; |
5890 | else |
5891 | oifq->ifq_tail = tqe->tqe_pnext; |
5892 | tqe->tqe_next = NULL; |
5893 | |
5894 | /* |
5895 | * If we're moving from one queue to another, release the |
5896 | * lock on the old queue and get a lock on the new queue. |
5897 | * For user defined queues, if we're moving off it, call |
5898 | * delete in case it can now be freed. |
5899 | */ |
5900 | if (oifq != nifq) { |
5901 | tqe->tqe_ifq = NULL; |
5902 | |
5903 | (void) ipf_deletetimeoutqueue(oifq); |
5904 | |
5905 | MUTEX_EXIT(&oifq->ifq_lock); |
5906 | |
5907 | MUTEX_ENTER(&nifq->ifq_lock); |
5908 | |
5909 | tqe->tqe_ifq = nifq; |
5910 | nifq->ifq_ref++; |
5911 | } |
5912 | |
5913 | /* |
5914 | * Add to the bottom of the new queue |
5915 | */ |
5916 | tqe->tqe_pnext = nifq->ifq_tail; |
5917 | *nifq->ifq_tail = tqe; |
5918 | nifq->ifq_tail = &tqe->tqe_next; |
5919 | MUTEX_EXIT(&nifq->ifq_lock); |
5920 | } |
5921 | |
5922 | |
5923 | /* ------------------------------------------------------------------------ */ |
5924 | /* Function: ipf_updateipid */ |
5925 | /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ |
5926 | /* Parameters: fin(I) - pointer to packet information */ |
5927 | /* */ |
5928 | /* When we are doing NAT, change the IP of every packet to represent a */ |
5929 | /* single sequence of packets coming from the host, hiding any host */ |
5930 | /* specific sequencing that might otherwise be revealed. If the packet is */ |
5931 | /* a fragment, then store the 'new' IPid in the fragment cache and look up */ |
5932 | /* the fragment cache for non-leading fragments. If a non-leading fragment */ |
5933 | /* has no match in the cache, return an error. */ |
5934 | /* ------------------------------------------------------------------------ */ |
5935 | static int |
5936 | ipf_updateipid(fr_info_t *fin) |
5937 | { |
5938 | u_short id, ido, sums; |
5939 | u_32_t sumd, sum; |
5940 | ip_t *ip; |
5941 | |
5942 | if (fin->fin_off != 0) { |
5943 | sum = ipf_frag_ipidknown(fin); |
5944 | if (sum == 0xffffffff) |
5945 | return -1; |
5946 | sum &= 0xffff; |
5947 | id = (u_short)sum; |
5948 | } else { |
5949 | id = ipf_nextipid(fin); |
5950 | if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) |
5951 | (void) ipf_frag_ipidnew(fin, (u_32_t)id); |
5952 | } |
5953 | |
5954 | ip = fin->fin_ip; |
5955 | ido = ntohs(ip->ip_id); |
5956 | if (id == ido) |
5957 | return 0; |
5958 | ip->ip_id = htons(id); |
5959 | CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ |
5960 | sum = (~ntohs(ip->ip_sum)) & 0xffff; |
5961 | sum += sumd; |
5962 | sum = (sum >> 16) + (sum & 0xffff); |
5963 | sum = (sum >> 16) + (sum & 0xffff); |
5964 | sums = ~(u_short)sum; |
5965 | ip->ip_sum = htons(sums); |
5966 | return 0; |
5967 | } |
5968 | |
5969 | |
5970 | #ifdef NEED_FRGETIFNAME |
5971 | /* ------------------------------------------------------------------------ */ |
5972 | /* Function: ipf_getifname */ |
5973 | /* Returns: char * - pointer to interface name */ |
5974 | /* Parameters: ifp(I) - pointer to network interface */ |
5975 | /* buffer(O) - pointer to where to store interface name */ |
5976 | /* */ |
5977 | /* Constructs an interface name in the buffer passed. The buffer passed is */ |
5978 | /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ |
5979 | /* as a NULL pointer then return a pointer to a static array. */ |
5980 | /* ------------------------------------------------------------------------ */ |
5981 | char * |
5982 | ipf_getifname(ifp, buffer) |
5983 | struct ifnet *ifp; |
5984 | char *buffer; |
5985 | { |
5986 | static char namebuf[LIFNAMSIZ]; |
5987 | # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ |
5988 | defined(__sgi) || defined(linux) || defined(_AIX51) || \ |
5989 | (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) |
5990 | int unit, space; |
5991 | char temp[20]; |
5992 | char *s; |
5993 | # endif |
5994 | |
5995 | if (buffer == NULL) |
5996 | buffer = namebuf; |
5997 | (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); |
5998 | buffer[LIFNAMSIZ - 1] = '\0'; |
5999 | # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ |
6000 | defined(__sgi) || defined(_AIX51) || \ |
6001 | (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) |
6002 | for (s = buffer; *s; s++) |
6003 | ; |
6004 | unit = ifp->if_unit; |
6005 | space = LIFNAMSIZ - (s - buffer); |
6006 | if ((space > 0) && (unit >= 0)) { |
6007 | snprintf(temp, sizeof(temp), "%d" , unit); |
6008 | (void) strncpy(s, temp, space); |
6009 | s[space - 1] = '\0'; |
6010 | } |
6011 | # endif |
6012 | return buffer; |
6013 | } |
6014 | #endif |
6015 | |
6016 | |
6017 | /* ------------------------------------------------------------------------ */ |
6018 | /* Function: ipf_ioctlswitch */ |
6019 | /* Returns: int - -1 continue processing, else ioctl return value */ |
6020 | /* Parameters: unit(I) - device unit opened */ |
6021 | /* data(I) - pointer to ioctl data */ |
6022 | /* cmd(I) - ioctl command */ |
6023 | /* mode(I) - mode value */ |
6024 | /* uid(I) - uid making the ioctl call */ |
6025 | /* ctx(I) - pointer to context data */ |
6026 | /* */ |
6027 | /* Based on the value of unit, call the appropriate ioctl handler or return */ |
6028 | /* EIO if ipfilter is not running. Also checks if write perms are req'd */ |
6029 | /* for the device in order to execute the ioctl. A special case is made */ |
6030 | /* SIOCIPFINTERROR so that the same code isn't required in every handler. */ |
6031 | /* The context data pointer is passed through as this is used as the key */ |
6032 | /* for locating a matching token for continued access for walking lists, */ |
6033 | /* etc. */ |
6034 | /* ------------------------------------------------------------------------ */ |
6035 | int |
6036 | ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd, |
6037 | int mode, int uid, void *ctx) |
6038 | { |
6039 | int error = 0; |
6040 | |
6041 | switch (cmd) |
6042 | { |
6043 | case SIOCIPFINTERROR : |
6044 | error = BCOPYOUT(&softc->ipf_interror, data, |
6045 | sizeof(softc->ipf_interror)); |
6046 | if (error != 0) { |
6047 | IPFERROR(40); |
6048 | error = EFAULT; |
6049 | } |
6050 | return error; |
6051 | default : |
6052 | break; |
6053 | } |
6054 | |
6055 | switch (unit) |
6056 | { |
6057 | case IPL_LOGIPF : |
6058 | error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx); |
6059 | break; |
6060 | case IPL_LOGNAT : |
6061 | if (softc->ipf_running > 0) { |
6062 | error = ipf_nat_ioctl(softc, data, cmd, mode, |
6063 | uid, ctx); |
6064 | } else { |
6065 | IPFERROR(42); |
6066 | error = EIO; |
6067 | } |
6068 | break; |
6069 | case IPL_LOGSTATE : |
6070 | if (softc->ipf_running > 0) { |
6071 | error = ipf_state_ioctl(softc, data, cmd, mode, |
6072 | uid, ctx); |
6073 | } else { |
6074 | IPFERROR(43); |
6075 | error = EIO; |
6076 | } |
6077 | break; |
6078 | case IPL_LOGAUTH : |
6079 | if (softc->ipf_running > 0) { |
6080 | error = ipf_auth_ioctl(softc, data, cmd, mode, |
6081 | uid, ctx); |
6082 | } else { |
6083 | IPFERROR(44); |
6084 | error = EIO; |
6085 | } |
6086 | break; |
6087 | case IPL_LOGSYNC : |
6088 | if (softc->ipf_running > 0) { |
6089 | error = ipf_sync_ioctl(softc, data, cmd, mode, |
6090 | uid, ctx); |
6091 | } else { |
6092 | error = EIO; |
6093 | IPFERROR(45); |
6094 | } |
6095 | break; |
6096 | case IPL_LOGSCAN : |
6097 | #ifdef IPFILTER_SCAN |
6098 | if (softc->ipf_running > 0) |
6099 | error = ipf_scan_ioctl(softc, data, cmd, mode, |
6100 | uid, ctx); |
6101 | else |
6102 | #endif |
6103 | { |
6104 | error = EIO; |
6105 | IPFERROR(46); |
6106 | } |
6107 | break; |
6108 | case IPL_LOGLOOKUP : |
6109 | if (softc->ipf_running > 0) { |
6110 | error = ipf_lookup_ioctl(softc, data, cmd, mode, |
6111 | uid, ctx); |
6112 | } else { |
6113 | error = EIO; |
6114 | IPFERROR(47); |
6115 | } |
6116 | break; |
6117 | default : |
6118 | IPFERROR(48); |
6119 | error = EIO; |
6120 | break; |
6121 | } |
6122 | |
6123 | return error; |
6124 | } |
6125 | |
6126 | |
6127 | /* |
6128 | * This array defines the expected size of objects coming into the kernel |
6129 | * for the various recognised object types. The first column is flags (see |
6130 | * below), 2nd column is current size, 3rd column is the version number of |
6131 | * when the current size became current. |
6132 | * Flags: |
6133 | * 1 = minimum size, not absolute size |
6134 | */ |
6135 | static int ipf_objbytes[IPFOBJ_COUNT][3] = { |
6136 | { 1, sizeof(struct frentry), 5010000 }, /* 0 */ |
6137 | { 1, sizeof(struct friostat), 5010000 }, |
6138 | { 0, sizeof(struct fr_info), 5010000 }, |
6139 | { 0, sizeof(struct ipf_authstat), 4010100 }, |
6140 | { 0, sizeof(struct ipfrstat), 5010000 }, |
6141 | { 1, sizeof(struct ipnat), 5010000 }, /* 5 */ |
6142 | { 0, sizeof(struct natstat), 5010000 }, |
6143 | { 0, sizeof(struct ipstate_save), 5010000 }, |
6144 | { 1, sizeof(struct nat_save), 5010000 }, |
6145 | { 0, sizeof(struct natlookup), 5010000 }, |
6146 | { 1, sizeof(struct ipstate), 5010000 }, /* 10 */ |
6147 | { 0, sizeof(struct ips_stat), 5010000 }, |
6148 | { 0, sizeof(struct frauth), 5010000 }, |
6149 | { 0, sizeof(struct ipftune), 4010100 }, |
6150 | { 0, sizeof(struct nat), 5010000 }, |
6151 | { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */ |
6152 | { 0, sizeof(struct ipfgeniter), 4011400 }, |
6153 | { 0, sizeof(struct ipftable), 4011400 }, |
6154 | { 0, sizeof(struct ipflookupiter), 4011400 }, |
6155 | { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, |
6156 | { 1, 0, 0 }, /* IPFEXPR */ |
6157 | { 0, 0, 0 }, /* PROXYCTL */ |
6158 | { 0, sizeof (struct fripf), 5010000 } |
6159 | }; |
6160 | |
6161 | |
6162 | /* ------------------------------------------------------------------------ */ |
6163 | /* Function: ipf_inobj */ |
6164 | /* Returns: int - 0 = success, else failure */ |
6165 | /* Parameters: softc(I) - soft context pointerto work with */ |
6166 | /* data(I) - pointer to ioctl data */ |
6167 | /* objp(O) - where to store ipfobj structure */ |
6168 | /* ptr(I) - pointer to data to copy out */ |
6169 | /* type(I) - type of structure being moved */ |
6170 | /* */ |
6171 | /* Copy in the contents of what the ipfobj_t points to. In future, we */ |
6172 | /* add things to check for version numbers, sizes, etc, to make it backward */ |
6173 | /* compatible at the ABI for user land. */ |
6174 | /* If objp is not NULL then we assume that the caller wants to see what is */ |
6175 | /* in the ipfobj_t structure being copied in. As an example, this can tell */ |
6176 | /* the caller what version of ipfilter the ioctl program was written to. */ |
6177 | /* ------------------------------------------------------------------------ */ |
6178 | int |
6179 | ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr, |
6180 | int type) |
6181 | { |
6182 | ipfobj_t obj; |
6183 | int error; |
6184 | int size; |
6185 | |
6186 | if ((type < 0) || (type >= IPFOBJ_COUNT)) { |
6187 | IPFERROR(49); |
6188 | return EINVAL; |
6189 | } |
6190 | |
6191 | if (objp == NULL) |
6192 | objp = &obj; |
6193 | error = BCOPYIN(data, objp, sizeof(*objp)); |
6194 | if (error != 0) { |
6195 | IPFERROR(124); |
6196 | return EFAULT; |
6197 | } |
6198 | |
6199 | if (objp->ipfo_type != type) { |
6200 | IPFERROR(50); |
6201 | return EINVAL; |
6202 | } |
6203 | |
6204 | if (objp->ipfo_rev >= ipf_objbytes[type][2]) { |
6205 | if ((ipf_objbytes[type][0] & 1) != 0) { |
6206 | if (objp->ipfo_size < ipf_objbytes[type][1]) { |
6207 | IPFERROR(51); |
6208 | return EINVAL; |
6209 | } |
6210 | size = ipf_objbytes[type][1]; |
6211 | } else if (objp->ipfo_size == ipf_objbytes[type][1]) { |
6212 | size = objp->ipfo_size; |
6213 | } else { |
6214 | IPFERROR(52); |
6215 | return EINVAL; |
6216 | } |
6217 | error = COPYIN(objp->ipfo_ptr, ptr, size); |
6218 | if (error != 0) { |
6219 | IPFERROR(55); |
6220 | error = EFAULT; |
6221 | } |
6222 | } else { |
6223 | #ifdef IPFILTER_COMPAT |
6224 | error = ipf_in_compat(softc, objp, ptr, 0); |
6225 | #else |
6226 | IPFERROR(54); |
6227 | error = EINVAL; |
6228 | #endif |
6229 | } |
6230 | return error; |
6231 | } |
6232 | |
6233 | |
6234 | /* ------------------------------------------------------------------------ */ |
6235 | /* Function: ipf_inobjsz */ |
6236 | /* Returns: int - 0 = success, else failure */ |
6237 | /* Parameters: softc(I) - soft context pointerto work with */ |
6238 | /* data(I) - pointer to ioctl data */ |
6239 | /* ptr(I) - pointer to store real data in */ |
6240 | /* type(I) - type of structure being moved */ |
6241 | /* sz(I) - size of data to copy */ |
6242 | /* */ |
6243 | /* As per ipf_inobj, except the size of the object to copy in is passed in */ |
6244 | /* but it must not be smaller than the size defined for the type and the */ |
6245 | /* type must allow for varied sized objects. The extra requirement here is */ |
6246 | /* that sz must match the size of the object being passed in - this is not */ |
6247 | /* not possible nor required in ipf_inobj(). */ |
6248 | /* ------------------------------------------------------------------------ */ |
6249 | int |
6250 | ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) |
6251 | { |
6252 | ipfobj_t obj; |
6253 | int error; |
6254 | |
6255 | if ((type < 0) || (type >= IPFOBJ_COUNT)) { |
6256 | IPFERROR(56); |
6257 | return EINVAL; |
6258 | } |
6259 | |
6260 | error = BCOPYIN(data, &obj, sizeof(obj)); |
6261 | if (error != 0) { |
6262 | IPFERROR(125); |
6263 | return EFAULT; |
6264 | } |
6265 | |
6266 | if (obj.ipfo_type != type) { |
6267 | IPFERROR(58); |
6268 | return EINVAL; |
6269 | } |
6270 | |
6271 | if (obj.ipfo_rev >= ipf_objbytes[type][2]) { |
6272 | if (((ipf_objbytes[type][0] & 1) == 0) || |
6273 | (sz < ipf_objbytes[type][1])) { |
6274 | IPFERROR(57); |
6275 | return EINVAL; |
6276 | } |
6277 | error = COPYIN(obj.ipfo_ptr, ptr, sz); |
6278 | if (error != 0) { |
6279 | IPFERROR(61); |
6280 | error = EFAULT; |
6281 | } |
6282 | } else { |
6283 | #ifdef IPFILTER_COMPAT |
6284 | error = ipf_in_compat(softc, &obj, ptr, sz); |
6285 | #else |
6286 | IPFERROR(60); |
6287 | error = EINVAL; |
6288 | #endif |
6289 | } |
6290 | return error; |
6291 | } |
6292 | |
6293 | |
6294 | /* ------------------------------------------------------------------------ */ |
6295 | /* Function: ipf_outobjsz */ |
6296 | /* Returns: int - 0 = success, else failure */ |
6297 | /* Parameters: data(I) - pointer to ioctl data */ |
6298 | /* ptr(I) - pointer to store real data in */ |
6299 | /* type(I) - type of structure being moved */ |
6300 | /* sz(I) - size of data to copy */ |
6301 | /* */ |
6302 | /* As per ipf_outobj, except the size of the object to copy out is passed in*/ |
6303 | /* but it must not be smaller than the size defined for the type and the */ |
6304 | /* type must allow for varied sized objects. The extra requirement here is */ |
6305 | /* that sz must match the size of the object being passed in - this is not */ |
6306 | /* not possible nor required in ipf_outobj(). */ |
6307 | /* ------------------------------------------------------------------------ */ |
6308 | int |
6309 | ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) |
6310 | { |
6311 | ipfobj_t obj; |
6312 | int error; |
6313 | |
6314 | if ((type < 0) || (type >= IPFOBJ_COUNT)) { |
6315 | IPFERROR(62); |
6316 | return EINVAL; |
6317 | } |
6318 | |
6319 | error = BCOPYIN(data, &obj, sizeof(obj)); |
6320 | if (error != 0) { |
6321 | IPFERROR(127); |
6322 | return EFAULT; |
6323 | } |
6324 | |
6325 | if (obj.ipfo_type != type) { |
6326 | IPFERROR(63); |
6327 | return EINVAL; |
6328 | } |
6329 | |
6330 | if (obj.ipfo_rev >= ipf_objbytes[type][2]) { |
6331 | if (((ipf_objbytes[type][0] & 1) == 0) || |
6332 | (sz < ipf_objbytes[type][1])) { |
6333 | IPFERROR(146); |
6334 | return EINVAL; |
6335 | } |
6336 | error = COPYOUT(ptr, obj.ipfo_ptr, sz); |
6337 | if (error != 0) { |
6338 | IPFERROR(66); |
6339 | error = EFAULT; |
6340 | } |
6341 | } else { |
6342 | #ifdef IPFILTER_COMPAT |
6343 | error = ipf_out_compat(softc, &obj, ptr); |
6344 | #else |
6345 | IPFERROR(65); |
6346 | error = EINVAL; |
6347 | #endif |
6348 | } |
6349 | return error; |
6350 | } |
6351 | |
6352 | |
6353 | /* ------------------------------------------------------------------------ */ |
6354 | /* Function: ipf_outobj */ |
6355 | /* Returns: int - 0 = success, else failure */ |
6356 | /* Parameters: data(I) - pointer to ioctl data */ |
6357 | /* ptr(I) - pointer to store real data in */ |
6358 | /* type(I) - type of structure being moved */ |
6359 | /* */ |
6360 | /* Copy out the contents of what ptr is to where ipfobj points to. In */ |
6361 | /* future, we add things to check for version numbers, sizes, etc, to make */ |
6362 | /* it backward compatible at the ABI for user land. */ |
6363 | /* ------------------------------------------------------------------------ */ |
6364 | int |
6365 | ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type) |
6366 | { |
6367 | ipfobj_t obj; |
6368 | int error; |
6369 | |
6370 | if ((type < 0) || (type >= IPFOBJ_COUNT)) { |
6371 | IPFERROR(67); |
6372 | return EINVAL; |
6373 | } |
6374 | |
6375 | error = BCOPYIN(data, &obj, sizeof(obj)); |
6376 | if (error != 0) { |
6377 | IPFERROR(126); |
6378 | return EFAULT; |
6379 | } |
6380 | |
6381 | if (obj.ipfo_type != type) { |
6382 | IPFERROR(68); |
6383 | return EINVAL; |
6384 | } |
6385 | |
6386 | if (obj.ipfo_rev >= ipf_objbytes[type][2]) { |
6387 | if ((ipf_objbytes[type][0] & 1) != 0) { |
6388 | if (obj.ipfo_size < ipf_objbytes[type][1]) { |
6389 | IPFERROR(69); |
6390 | return EINVAL; |
6391 | } |
6392 | } else if (obj.ipfo_size != ipf_objbytes[type][1]) { |
6393 | IPFERROR(70); |
6394 | return EINVAL; |
6395 | } |
6396 | |
6397 | error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); |
6398 | if (error != 0) { |
6399 | IPFERROR(73); |
6400 | error = EFAULT; |
6401 | } |
6402 | } else { |
6403 | #ifdef IPFILTER_COMPAT |
6404 | error = ipf_out_compat(softc, &obj, ptr); |
6405 | #else |
6406 | IPFERROR(72); |
6407 | error = EINVAL; |
6408 | #endif |
6409 | } |
6410 | return error; |
6411 | } |
6412 | |
6413 | |
6414 | /* ------------------------------------------------------------------------ */ |
6415 | /* Function: ipf_outobjk */ |
6416 | /* Returns: int - 0 = success, else failure */ |
6417 | /* Parameters: obj(I) - pointer to data description structure */ |
6418 | /* ptr(I) - pointer to kernel data to copy out */ |
6419 | /* */ |
6420 | /* In the above functions, the ipfobj_t structure is copied into the kernel,*/ |
6421 | /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */ |
6422 | /* already populated with information and now we just need to use it. */ |
6423 | /* There is no need for this function to have a "type" parameter as there */ |
6424 | /* is no point in validating information that comes from the kernel with */ |
6425 | /* itself. */ |
6426 | /* ------------------------------------------------------------------------ */ |
6427 | int |
6428 | ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr) |
6429 | { |
6430 | int type = obj->ipfo_type; |
6431 | int error; |
6432 | |
6433 | if ((type < 0) || (type >= IPFOBJ_COUNT)) { |
6434 | IPFERROR(147); |
6435 | return EINVAL; |
6436 | } |
6437 | |
6438 | if (obj->ipfo_rev >= ipf_objbytes[type][2]) { |
6439 | if ((ipf_objbytes[type][0] & 1) != 0) { |
6440 | if (obj->ipfo_size < ipf_objbytes[type][1]) { |
6441 | IPFERROR(148); |
6442 | return EINVAL; |
6443 | } |
6444 | |
6445 | } else if (obj->ipfo_size != ipf_objbytes[type][1]) { |
6446 | IPFERROR(149); |
6447 | return EINVAL; |
6448 | } |
6449 | |
6450 | error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size); |
6451 | if (error != 0) { |
6452 | IPFERROR(150); |
6453 | error = EFAULT; |
6454 | } |
6455 | } else { |
6456 | #ifdef IPFILTER_COMPAT |
6457 | error = ipf_out_compat(softc, obj, ptr); |
6458 | #else |
6459 | IPFERROR(151); |
6460 | error = EINVAL; |
6461 | #endif |
6462 | } |
6463 | return error; |
6464 | } |
6465 | |
6466 | |
6467 | /* ------------------------------------------------------------------------ */ |
6468 | /* Function: ipf_checkl4sum */ |
6469 | /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ |
6470 | /* Parameters: fin(I) - pointer to packet information */ |
6471 | /* */ |
6472 | /* If possible, calculate the layer 4 checksum for the packet. If this is */ |
6473 | /* not possible, return without indicating a failure or success but in a */ |
6474 | /* way that is ditinguishable. This function should only be called by the */ |
6475 | /* ipf_checkv6sum() for each platform. */ |
6476 | /* ------------------------------------------------------------------------ */ |
6477 | int |
6478 | ipf_checkl4sum(fr_info_t *fin) |
6479 | { |
6480 | u_short sum, hdrsum, *csump; |
6481 | udphdr_t *udp; |
6482 | int dosum; |
6483 | |
6484 | /* |
6485 | * If the TCP packet isn't a fragment, isn't too short and otherwise |
6486 | * isn't already considered "bad", then validate the checksum. If |
6487 | * this check fails then considered the packet to be "bad". |
6488 | */ |
6489 | if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) |
6490 | return 1; |
6491 | |
6492 | csump = NULL; |
6493 | hdrsum = 0; |
6494 | dosum = 0; |
6495 | sum = 0; |
6496 | |
6497 | switch (fin->fin_p) |
6498 | { |
6499 | case IPPROTO_TCP : |
6500 | csump = &((tcphdr_t *)fin->fin_dp)->th_sum; |
6501 | dosum = 1; |
6502 | break; |
6503 | |
6504 | case IPPROTO_UDP : |
6505 | udp = fin->fin_dp; |
6506 | if (udp->uh_sum != 0) { |
6507 | csump = &udp->uh_sum; |
6508 | dosum = 1; |
6509 | } |
6510 | break; |
6511 | |
6512 | #ifdef USE_INET6 |
6513 | case IPPROTO_ICMPV6 : |
6514 | csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum; |
6515 | dosum = 1; |
6516 | break; |
6517 | #endif |
6518 | |
6519 | case IPPROTO_ICMP : |
6520 | csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; |
6521 | dosum = 1; |
6522 | break; |
6523 | |
6524 | default : |
6525 | return 1; |
6526 | /*NOTREACHED*/ |
6527 | } |
6528 | |
6529 | if (csump != NULL) |
6530 | hdrsum = *csump; |
6531 | |
6532 | if (dosum) { |
6533 | sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp); |
6534 | } |
6535 | #if !defined(_KERNEL) |
6536 | if (sum == hdrsum) { |
6537 | FR_DEBUG(("checkl4sum: %hx == %hx\n" , sum, hdrsum)); |
6538 | } else { |
6539 | FR_DEBUG(("checkl4sum: %hx != %hx\n" , sum, hdrsum)); |
6540 | } |
6541 | #endif |
6542 | DT2(l4sums, u_short, hdrsum, u_short, sum); |
6543 | if (hdrsum == sum) { |
6544 | fin->fin_cksum = FI_CK_SUMOK; |
6545 | return 0; |
6546 | } |
6547 | fin->fin_cksum = FI_CK_BAD; |
6548 | return -1; |
6549 | } |
6550 | |
6551 | |
6552 | /* ------------------------------------------------------------------------ */ |
6553 | /* Function: ipf_ifpfillv4addr */ |
6554 | /* Returns: int - 0 = address update, -1 = address not updated */ |
6555 | /* Parameters: atype(I) - type of network address update to perform */ |
6556 | /* sin(I) - pointer to source of address information */ |
6557 | /* mask(I) - pointer to source of netmask information */ |
6558 | /* inp(I) - pointer to destination address store */ |
6559 | /* inpmask(I) - pointer to destination netmask store */ |
6560 | /* */ |
6561 | /* Given a type of network address update (atype) to perform, copy */ |
6562 | /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ |
6563 | /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ |
6564 | /* which case the operation fails. For all values of atype other than */ |
6565 | /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ |
6566 | /* value. */ |
6567 | /* ------------------------------------------------------------------------ */ |
6568 | int |
6569 | ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask, |
6570 | struct in_addr *inp, struct in_addr *inpmask) |
6571 | { |
6572 | if (inpmask != NULL && atype != FRI_NETMASKED) |
6573 | inpmask->s_addr = 0xffffffff; |
6574 | |
6575 | if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { |
6576 | if (atype == FRI_NETMASKED) { |
6577 | if (inpmask == NULL) |
6578 | return -1; |
6579 | inpmask->s_addr = mask->sin_addr.s_addr; |
6580 | } |
6581 | inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; |
6582 | } else { |
6583 | inp->s_addr = sin->sin_addr.s_addr; |
6584 | } |
6585 | return 0; |
6586 | } |
6587 | |
6588 | |
6589 | #ifdef USE_INET6 |
6590 | /* ------------------------------------------------------------------------ */ |
6591 | /* Function: ipf_ifpfillv6addr */ |
6592 | /* Returns: int - 0 = address update, -1 = address not updated */ |
6593 | /* Parameters: atype(I) - type of network address update to perform */ |
6594 | /* sin(I) - pointer to source of address information */ |
6595 | /* mask(I) - pointer to source of netmask information */ |
6596 | /* inp(I) - pointer to destination address store */ |
6597 | /* inpmask(I) - pointer to destination netmask store */ |
6598 | /* */ |
6599 | /* Given a type of network address update (atype) to perform, copy */ |
6600 | /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ |
6601 | /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ |
6602 | /* which case the operation fails. For all values of atype other than */ |
6603 | /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ |
6604 | /* value. */ |
6605 | /* ------------------------------------------------------------------------ */ |
6606 | int |
6607 | ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin, |
6608 | struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask) |
6609 | { |
6610 | i6addr_t *src, *and; |
6611 | |
6612 | src = (i6addr_t *)&sin->sin6_addr; |
6613 | and = (i6addr_t *)&mask->sin6_addr; |
6614 | |
6615 | if (inpmask != NULL && atype != FRI_NETMASKED) { |
6616 | inpmask->i6[0] = 0xffffffff; |
6617 | inpmask->i6[1] = 0xffffffff; |
6618 | inpmask->i6[2] = 0xffffffff; |
6619 | inpmask->i6[3] = 0xffffffff; |
6620 | } |
6621 | |
6622 | if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { |
6623 | if (atype == FRI_NETMASKED) { |
6624 | if (inpmask == NULL) |
6625 | return -1; |
6626 | inpmask->i6[0] = and->i6[0]; |
6627 | inpmask->i6[1] = and->i6[1]; |
6628 | inpmask->i6[2] = and->i6[2]; |
6629 | inpmask->i6[3] = and->i6[3]; |
6630 | } |
6631 | |
6632 | inp->i6[0] = src->i6[0] & and->i6[0]; |
6633 | inp->i6[1] = src->i6[1] & and->i6[1]; |
6634 | inp->i6[2] = src->i6[2] & and->i6[2]; |
6635 | inp->i6[3] = src->i6[3] & and->i6[3]; |
6636 | } else { |
6637 | inp->i6[0] = src->i6[0]; |
6638 | inp->i6[1] = src->i6[1]; |
6639 | inp->i6[2] = src->i6[2]; |
6640 | inp->i6[3] = src->i6[3]; |
6641 | } |
6642 | return 0; |
6643 | } |
6644 | #endif |
6645 | |
6646 | |
6647 | /* ------------------------------------------------------------------------ */ |
6648 | /* Function: ipf_matchtag */ |
6649 | /* Returns: 0 == mismatch, 1 == match. */ |
6650 | /* Parameters: tag1(I) - pointer to first tag to compare */ |
6651 | /* tag2(I) - pointer to second tag to compare */ |
6652 | /* */ |
6653 | /* Returns true (non-zero) or false(0) if the two tag structures can be */ |
6654 | /* considered to be a match or not match, respectively. The tag is 16 */ |
6655 | /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ |
6656 | /* compare the ints instead, for speed. tag1 is the master of the */ |
6657 | /* comparison. This function should only be called with both tag1 and tag2 */ |
6658 | /* as non-NULL pointers. */ |
6659 | /* ------------------------------------------------------------------------ */ |
6660 | int |
6661 | ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2) |
6662 | { |
6663 | if (tag1 == tag2) |
6664 | return 1; |
6665 | |
6666 | if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) |
6667 | return 1; |
6668 | |
6669 | if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && |
6670 | (tag1->ipt_num[1] == tag2->ipt_num[1]) && |
6671 | (tag1->ipt_num[2] == tag2->ipt_num[2]) && |
6672 | (tag1->ipt_num[3] == tag2->ipt_num[3])) |
6673 | return 1; |
6674 | return 0; |
6675 | } |
6676 | |
6677 | |
6678 | /* ------------------------------------------------------------------------ */ |
6679 | /* Function: ipf_coalesce */ |
6680 | /* Returns: 1 == success, -1 == failure, 0 == no change */ |
6681 | /* Parameters: fin(I) - pointer to packet information */ |
6682 | /* */ |
6683 | /* Attempt to get all of the packet data into a single, contiguous buffer. */ |
6684 | /* If this call returns a failure then the buffers have also been freed. */ |
6685 | /* ------------------------------------------------------------------------ */ |
6686 | int |
6687 | ipf_coalesce(fr_info_t *fin) |
6688 | { |
6689 | |
6690 | if ((fin->fin_flx & FI_COALESCE) != 0) |
6691 | return 1; |
6692 | |
6693 | /* |
6694 | * If the mbuf pointers indicate that there is no mbuf to work with, |
6695 | * return but do not indicate success or failure. |
6696 | */ |
6697 | if (fin->fin_m == NULL || fin->fin_mp == NULL) |
6698 | return 0; |
6699 | |
6700 | #if defined(_KERNEL) |
6701 | if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { |
6702 | ipf_main_softc_t *softc = fin->fin_main_soft; |
6703 | |
6704 | DT1(frb_coalesce, fr_info_t *, fin); |
6705 | LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces); |
6706 | # ifdef MENTAT |
6707 | FREE_MB_T(*fin->fin_mp); |
6708 | # endif |
6709 | fin->fin_reason = FRB_COALESCE; |
6710 | *fin->fin_mp = NULL; |
6711 | fin->fin_m = NULL; |
6712 | return -1; |
6713 | } |
6714 | #else |
6715 | fin = fin; /* LINT */ |
6716 | #endif |
6717 | return 1; |
6718 | } |
6719 | |
6720 | |
6721 | /* |
6722 | * The following table lists all of the tunable variables that can be |
6723 | * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row |
6724 | * in the table below is as follows: |
6725 | * |
6726 | * pointer to value, name of value, minimum, maximum, size of the value's |
6727 | * container, value attribute flags |
6728 | * |
6729 | * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED |
6730 | * means the value can only be written to when IPFilter is loaded but disabled. |
6731 | * The obvious implication is if neither of these are set then the value can be |
6732 | * changed at any time without harm. |
6733 | */ |
6734 | |
6735 | |
6736 | /* ------------------------------------------------------------------------ */ |
6737 | /* Function: ipf_tune_findbycookie */ |
6738 | /* Returns: NULL = search failed, else pointer to tune struct */ |
6739 | /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ |
6740 | /* next(O) - pointer to place to store the cookie for the */ |
6741 | /* "next" tuneable, if it is desired. */ |
6742 | /* */ |
6743 | /* This function is used to walk through all of the existing tunables with */ |
6744 | /* successive calls. It searches the known tunables for the one which has */ |
6745 | /* a matching value for "cookie" - ie its address. When returning a match, */ |
6746 | /* the next one to be found may be returned inside next. */ |
6747 | /* ------------------------------------------------------------------------ */ |
6748 | static ipftuneable_t * |
6749 | ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next) |
6750 | { |
6751 | ipftuneable_t *ta, **tap; |
6752 | |
6753 | for (ta = *ptop; ta->ipft_name != NULL; ta++) |
6754 | if (ta == cookie) { |
6755 | if (next != NULL) { |
6756 | /* |
6757 | * If the next entry in the array has a name |
6758 | * present, then return a pointer to it for |
6759 | * where to go next, else return a pointer to |
6760 | * the dynaminc list as a key to search there |
6761 | * next. This facilitates a weak linking of |
6762 | * the two "lists" together. |
6763 | */ |
6764 | if ((ta + 1)->ipft_name != NULL) |
6765 | *next = ta + 1; |
6766 | else |
6767 | *next = ptop; |
6768 | } |
6769 | return ta; |
6770 | } |
6771 | |
6772 | for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next) |
6773 | if (tap == cookie) { |
6774 | if (next != NULL) |
6775 | *next = &ta->ipft_next; |
6776 | return ta; |
6777 | } |
6778 | |
6779 | if (next != NULL) |
6780 | *next = NULL; |
6781 | return NULL; |
6782 | } |
6783 | |
6784 | |
6785 | /* ------------------------------------------------------------------------ */ |
6786 | /* Function: ipf_tune_findbyname */ |
6787 | /* Returns: NULL = search failed, else pointer to tune struct */ |
6788 | /* Parameters: name(I) - name of the tuneable entry to find. */ |
6789 | /* */ |
6790 | /* Search the static array of tuneables and the list of dynamic tuneables */ |
6791 | /* for an entry with a matching name. If we can find one, return a pointer */ |
6792 | /* to the matching structure. */ |
6793 | /* ------------------------------------------------------------------------ */ |
6794 | static ipftuneable_t * |
6795 | ipf_tune_findbyname(ipftuneable_t *top, const char *name) |
6796 | { |
6797 | ipftuneable_t *ta; |
6798 | |
6799 | for (ta = top; ta != NULL; ta = ta->ipft_next) |
6800 | if (!strcmp(ta->ipft_name, name)) { |
6801 | return ta; |
6802 | } |
6803 | |
6804 | return NULL; |
6805 | } |
6806 | |
6807 | |
6808 | /* ------------------------------------------------------------------------ */ |
6809 | /* Function: ipf_tune_add_array */ |
6810 | /* Returns: int - 0 == success, else failure */ |
6811 | /* Parameters: newtune - pointer to new tune array to add to tuneables */ |
6812 | /* */ |
6813 | /* Appends tune structures from the array passed in (newtune) to the end of */ |
6814 | /* the current list of "dynamic" tuneable parameters. */ |
6815 | /* If any entry to be added is already present (by name) then the operation */ |
6816 | /* is aborted - entries that have been added are removed before returning. */ |
6817 | /* An entry with no name (NULL) is used as the indication that the end of */ |
6818 | /* the array has been reached. */ |
6819 | /* ------------------------------------------------------------------------ */ |
6820 | int |
6821 | ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune) |
6822 | { |
6823 | ipftuneable_t *nt, *dt; |
6824 | int error = 0; |
6825 | |
6826 | for (nt = newtune; nt->ipft_name != NULL; nt++) { |
6827 | error = ipf_tune_add(softc, nt); |
6828 | if (error != 0) { |
6829 | for (dt = newtune; dt != nt; dt++) { |
6830 | (void) ipf_tune_del(softc, dt); |
6831 | } |
6832 | } |
6833 | } |
6834 | |
6835 | return error; |
6836 | } |
6837 | |
6838 | |
6839 | /* ------------------------------------------------------------------------ */ |
6840 | /* Function: ipf_tune_array_link */ |
6841 | /* Returns: 0 == success, -1 == failure */ |
6842 | /* Parameters: softc(I) - soft context pointerto work with */ |
6843 | /* array(I) - pointer to an array of tuneables */ |
6844 | /* */ |
6845 | /* Given an array of tunables (array), append them to the current list of */ |
6846 | /* tuneables for this context (softc->ipf_tuners.) To properly prepare the */ |
6847 | /* the array for being appended to the list, initialise all of the next */ |
6848 | /* pointers so we don't need to walk parts of it with ++ and others with */ |
6849 | /* next. The array is expected to have an entry with a NULL name as the */ |
6850 | /* terminator. Trying to add an array with no non-NULL names will return as */ |
6851 | /* a failure. */ |
6852 | /* ------------------------------------------------------------------------ */ |
6853 | int |
6854 | ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array) |
6855 | { |
6856 | ipftuneable_t *t, **p; |
6857 | |
6858 | t = array; |
6859 | if (t->ipft_name == NULL) |
6860 | return -1; |
6861 | |
6862 | for (; t[1].ipft_name != NULL; t++) |
6863 | t[0].ipft_next = &t[1]; |
6864 | t->ipft_next = NULL; |
6865 | |
6866 | /* |
6867 | * Since a pointer to the last entry isn't kept, we need to find it |
6868 | * each time we want to add new variables to the list. |
6869 | */ |
6870 | for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) |
6871 | if (t->ipft_name == NULL) |
6872 | break; |
6873 | *p = array; |
6874 | |
6875 | return 0; |
6876 | } |
6877 | |
6878 | |
6879 | /* ------------------------------------------------------------------------ */ |
6880 | /* Function: ipf_tune_array_unlink */ |
6881 | /* Returns: 0 == success, -1 == failure */ |
6882 | /* Parameters: softc(I) - soft context pointerto work with */ |
6883 | /* array(I) - pointer to an array of tuneables */ |
6884 | /* */ |
6885 | /* ------------------------------------------------------------------------ */ |
6886 | int |
6887 | ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array) |
6888 | { |
6889 | ipftuneable_t *t, **p; |
6890 | |
6891 | for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) |
6892 | if (t == array) |
6893 | break; |
6894 | if (t == NULL) |
6895 | return -1; |
6896 | |
6897 | for (; t[1].ipft_name != NULL; t++) |
6898 | ; |
6899 | |
6900 | *p = t->ipft_next; |
6901 | |
6902 | return 0; |
6903 | } |
6904 | |
6905 | |
6906 | /* ------------------------------------------------------------------------ */ |
6907 | /* Function: ipf_tune_array_copy */ |
6908 | /* Returns: NULL = failure, else pointer to new array */ |
6909 | /* Parameters: base(I) - pointer to structure base */ |
6910 | /* size(I) - size of the array at template */ |
6911 | /* template(I) - original array to copy */ |
6912 | /* */ |
6913 | /* Allocate memory for a new set of tuneable values and copy everything */ |
6914 | /* from template into the new region of memory. The new region is full of */ |
6915 | /* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */ |
6916 | /* */ |
6917 | /* NOTE: the following assumes that sizeof(long) == sizeof(void *) */ |
6918 | /* In the array template, ipftp_offset is the offset (in bytes) of the */ |
6919 | /* location of the tuneable value inside the structure pointed to by base. */ |
6920 | /* As ipftp_offset is a union over the pointers to the tuneable values, if */ |
6921 | /* we add base to the copy's ipftp_offset, copy ends up with a pointer in */ |
6922 | /* ipftp_void that points to the stored value. */ |
6923 | /* ------------------------------------------------------------------------ */ |
6924 | ipftuneable_t * |
6925 | ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template) |
6926 | { |
6927 | ipftuneable_t *copy; |
6928 | int i; |
6929 | |
6930 | |
6931 | KMALLOCS(copy, ipftuneable_t *, size); |
6932 | if (copy == NULL) { |
6933 | return NULL; |
6934 | } |
6935 | bcopy(template, copy, size); |
6936 | |
6937 | for (i = 0; copy[i].ipft_name; i++) { |
6938 | copy[i].ipft_una.ipftp_offset += (u_long)base; |
6939 | copy[i].ipft_next = copy + i + 1; |
6940 | } |
6941 | |
6942 | return copy; |
6943 | } |
6944 | |
6945 | |
6946 | /* ------------------------------------------------------------------------ */ |
6947 | /* Function: ipf_tune_add */ |
6948 | /* Returns: int - 0 == success, else failure */ |
6949 | /* Parameters: newtune - pointer to new tune entry to add to tuneables */ |
6950 | /* */ |
6951 | /* Appends tune structures from the array passed in (newtune) to the end of */ |
6952 | /* the current list of "dynamic" tuneable parameters. Once added, the */ |
6953 | /* owner of the object is not expected to ever change "ipft_next". */ |
6954 | /* ------------------------------------------------------------------------ */ |
6955 | int |
6956 | ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune) |
6957 | { |
6958 | ipftuneable_t *ta, **tap; |
6959 | |
6960 | ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name); |
6961 | if (ta != NULL) { |
6962 | IPFERROR(74); |
6963 | return EEXIST; |
6964 | } |
6965 | |
6966 | for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next) |
6967 | ; |
6968 | |
6969 | newtune->ipft_next = NULL; |
6970 | *tap = newtune; |
6971 | return 0; |
6972 | } |
6973 | |
6974 | |
6975 | /* ------------------------------------------------------------------------ */ |
6976 | /* Function: ipf_tune_del */ |
6977 | /* Returns: int - 0 == success, else failure */ |
6978 | /* Parameters: oldtune - pointer to tune entry to remove from the list of */ |
6979 | /* current dynamic tuneables */ |
6980 | /* */ |
6981 | /* Search for the tune structure, by pointer, in the list of those that are */ |
6982 | /* dynamically added at run time. If found, adjust the list so that this */ |
6983 | /* structure is no longer part of it. */ |
6984 | /* ------------------------------------------------------------------------ */ |
6985 | int |
6986 | ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune) |
6987 | { |
6988 | ipftuneable_t *ta, **tap; |
6989 | int error = 0; |
6990 | |
6991 | for (tap = &softc->ipf_tuners; (ta = *tap) != NULL; |
6992 | tap = &ta->ipft_next) { |
6993 | if (ta == oldtune) { |
6994 | *tap = oldtune->ipft_next; |
6995 | oldtune->ipft_next = NULL; |
6996 | break; |
6997 | } |
6998 | } |
6999 | |
7000 | if (ta == NULL) { |
7001 | error = ESRCH; |
7002 | IPFERROR(75); |
7003 | } |
7004 | return error; |
7005 | } |
7006 | |
7007 | |
7008 | /* ------------------------------------------------------------------------ */ |
7009 | /* Function: ipf_tune_del_array */ |
7010 | /* Returns: int - 0 == success, else failure */ |
7011 | /* Parameters: oldtune - pointer to tuneables array */ |
7012 | /* */ |
7013 | /* Remove each tuneable entry in the array from the list of "dynamic" */ |
7014 | /* tunables. If one entry should fail to be found, an error will be */ |
7015 | /* returned and no further ones removed. */ |
7016 | /* An entry with a NULL name is used as the indicator of the last entry in */ |
7017 | /* the array. */ |
7018 | /* ------------------------------------------------------------------------ */ |
7019 | int |
7020 | ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune) |
7021 | { |
7022 | ipftuneable_t *ot; |
7023 | int error = 0; |
7024 | |
7025 | for (ot = oldtune; ot->ipft_name != NULL; ot++) { |
7026 | error = ipf_tune_del(softc, ot); |
7027 | if (error != 0) |
7028 | break; |
7029 | } |
7030 | |
7031 | return error; |
7032 | |
7033 | } |
7034 | |
7035 | |
7036 | /* ------------------------------------------------------------------------ */ |
7037 | /* Function: ipf_tune */ |
7038 | /* Returns: int - 0 == success, else failure */ |
7039 | /* Parameters: cmd(I) - ioctl command number */ |
7040 | /* data(I) - pointer to ioctl data structure */ |
7041 | /* */ |
7042 | /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ |
7043 | /* three ioctls provide the means to access and control global variables */ |
7044 | /* within IPFilter, allowing (for example) timeouts and table sizes to be */ |
7045 | /* changed without rebooting, reloading or recompiling. The initialisation */ |
7046 | /* and 'destruction' routines of the various components of ipfilter are all */ |
7047 | /* each responsible for handling their own values being too big. */ |
7048 | /* ------------------------------------------------------------------------ */ |
7049 | int |
7050 | ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data) |
7051 | { |
7052 | ipftuneable_t *ta; |
7053 | ipftune_t tu; |
7054 | void *cookie; |
7055 | int error; |
7056 | |
7057 | error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE); |
7058 | if (error != 0) |
7059 | return error; |
7060 | |
7061 | tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; |
7062 | cookie = tu.ipft_cookie; |
7063 | ta = NULL; |
7064 | |
7065 | switch (cmd) |
7066 | { |
7067 | case SIOCIPFGETNEXT : |
7068 | /* |
7069 | * If cookie is non-NULL, assume it to be a pointer to the last |
7070 | * entry we looked at, so find it (if possible) and return a |
7071 | * pointer to the next one after it. The last entry in the |
7072 | * the table is a NULL entry, so when we get to it, set cookie |
7073 | * to NULL and return that, indicating end of list, erstwhile |
7074 | * if we come in with cookie set to NULL, we are starting anew |
7075 | * at the front of the list. |
7076 | */ |
7077 | if (cookie != NULL) { |
7078 | ta = ipf_tune_findbycookie(&softc->ipf_tuners, |
7079 | cookie, &tu.ipft_cookie); |
7080 | } else { |
7081 | ta = softc->ipf_tuners; |
7082 | tu.ipft_cookie = ta + 1; |
7083 | } |
7084 | if (ta != NULL) { |
7085 | /* |
7086 | * Entry found, but does the data pointed to by that |
7087 | * row fit in what we can return? |
7088 | */ |
7089 | if (ta->ipft_sz > sizeof(tu.ipft_un)) { |
7090 | IPFERROR(76); |
7091 | return EINVAL; |
7092 | } |
7093 | |
7094 | tu.ipft_vlong = 0; |
7095 | if (ta->ipft_sz == sizeof(u_long)) |
7096 | tu.ipft_vlong = *ta->ipft_plong; |
7097 | else if (ta->ipft_sz == sizeof(u_int)) |
7098 | tu.ipft_vint = *ta->ipft_pint; |
7099 | else if (ta->ipft_sz == sizeof(u_short)) |
7100 | tu.ipft_vshort = *ta->ipft_pshort; |
7101 | else if (ta->ipft_sz == sizeof(u_char)) |
7102 | tu.ipft_vchar = *ta->ipft_pchar; |
7103 | |
7104 | tu.ipft_sz = ta->ipft_sz; |
7105 | tu.ipft_min = ta->ipft_min; |
7106 | tu.ipft_max = ta->ipft_max; |
7107 | tu.ipft_flags = ta->ipft_flags; |
7108 | bcopy(ta->ipft_name, tu.ipft_name, |
7109 | MIN(sizeof(tu.ipft_name), |
7110 | strlen(ta->ipft_name) + 1)); |
7111 | } |
7112 | error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); |
7113 | break; |
7114 | |
7115 | case SIOCIPFGET : |
7116 | case SIOCIPFSET : |
7117 | /* |
7118 | * Search by name or by cookie value for a particular entry |
7119 | * in the tuning paramter table. |
7120 | */ |
7121 | IPFERROR(77); |
7122 | error = ESRCH; |
7123 | if (cookie != NULL) { |
7124 | ta = ipf_tune_findbycookie(&softc->ipf_tuners, |
7125 | cookie, NULL); |
7126 | if (ta != NULL) |
7127 | error = 0; |
7128 | } else if (tu.ipft_name[0] != '\0') { |
7129 | ta = ipf_tune_findbyname(softc->ipf_tuners, |
7130 | tu.ipft_name); |
7131 | if (ta != NULL) |
7132 | error = 0; |
7133 | } |
7134 | if (error != 0) |
7135 | break; |
7136 | |
7137 | if (cmd == (ioctlcmd_t)SIOCIPFGET) { |
7138 | /* |
7139 | * Fetch the tuning parameters for a particular value |
7140 | */ |
7141 | tu.ipft_vlong = 0; |
7142 | if (ta->ipft_sz == sizeof(u_long)) |
7143 | tu.ipft_vlong = *ta->ipft_plong; |
7144 | else if (ta->ipft_sz == sizeof(u_int)) |
7145 | tu.ipft_vint = *ta->ipft_pint; |
7146 | else if (ta->ipft_sz == sizeof(u_short)) |
7147 | tu.ipft_vshort = *ta->ipft_pshort; |
7148 | else if (ta->ipft_sz == sizeof(u_char)) |
7149 | tu.ipft_vchar = *ta->ipft_pchar; |
7150 | tu.ipft_cookie = ta; |
7151 | tu.ipft_sz = ta->ipft_sz; |
7152 | tu.ipft_min = ta->ipft_min; |
7153 | tu.ipft_max = ta->ipft_max; |
7154 | tu.ipft_flags = ta->ipft_flags; |
7155 | error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); |
7156 | |
7157 | } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { |
7158 | /* |
7159 | * Set an internal parameter. The hard part here is |
7160 | * getting the new value safely and correctly out of |
7161 | * the kernel (given we only know its size, not type.) |
7162 | */ |
7163 | u_long in; |
7164 | |
7165 | if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && |
7166 | (softc->ipf_running > 0)) { |
7167 | IPFERROR(78); |
7168 | error = EBUSY; |
7169 | break; |
7170 | } |
7171 | |
7172 | in = tu.ipft_vlong; |
7173 | if (in < ta->ipft_min || in > ta->ipft_max) { |
7174 | IPFERROR(79); |
7175 | error = EINVAL; |
7176 | break; |
7177 | } |
7178 | |
7179 | if (ta->ipft_func != NULL) { |
7180 | SPL_INT(s); |
7181 | |
7182 | SPL_NET(s); |
7183 | error = (*ta->ipft_func)(softc, ta, |
7184 | &tu.ipft_un); |
7185 | SPL_X(s); |
7186 | |
7187 | } else if (ta->ipft_sz == sizeof(u_long)) { |
7188 | tu.ipft_vlong = *ta->ipft_plong; |
7189 | *ta->ipft_plong = in; |
7190 | |
7191 | } else if (ta->ipft_sz == sizeof(u_int)) { |
7192 | tu.ipft_vint = *ta->ipft_pint; |
7193 | *ta->ipft_pint = (u_int)(in & 0xffffffff); |
7194 | |
7195 | } else if (ta->ipft_sz == sizeof(u_short)) { |
7196 | tu.ipft_vshort = *ta->ipft_pshort; |
7197 | *ta->ipft_pshort = (u_short)(in & 0xffff); |
7198 | |
7199 | } else if (ta->ipft_sz == sizeof(u_char)) { |
7200 | tu.ipft_vchar = *ta->ipft_pchar; |
7201 | *ta->ipft_pchar = (u_char)(in & 0xff); |
7202 | } |
7203 | error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); |
7204 | } |
7205 | break; |
7206 | |
7207 | default : |
7208 | IPFERROR(80); |
7209 | error = EINVAL; |
7210 | break; |
7211 | } |
7212 | |
7213 | return error; |
7214 | } |
7215 | |
7216 | |
7217 | /* ------------------------------------------------------------------------ */ |
7218 | /* Function: ipf_zerostats */ |
7219 | /* Returns: int - 0 = success, else failure */ |
7220 | /* Parameters: data(O) - pointer to pointer for copying data back to */ |
7221 | /* */ |
7222 | /* Copies the current statistics out to userspace and then zero's the */ |
7223 | /* current ones in the kernel. The lock is only held across the bzero() as */ |
7224 | /* the copyout may result in paging (ie network activity.) */ |
7225 | /* ------------------------------------------------------------------------ */ |
7226 | int |
7227 | ipf_zerostats(ipf_main_softc_t *softc, void *data) |
7228 | { |
7229 | friostat_t fio; |
7230 | ipfobj_t obj; |
7231 | int error; |
7232 | |
7233 | error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT); |
7234 | if (error != 0) |
7235 | return error; |
7236 | ipf_getstat(softc, &fio, obj.ipfo_rev); |
7237 | error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT); |
7238 | if (error != 0) |
7239 | return error; |
7240 | |
7241 | WRITE_ENTER(&softc->ipf_mutex); |
7242 | bzero(&softc->ipf_stats, sizeof(softc->ipf_stats)); |
7243 | RWLOCK_EXIT(&softc->ipf_mutex); |
7244 | |
7245 | return 0; |
7246 | } |
7247 | |
7248 | |
7249 | /* ------------------------------------------------------------------------ */ |
7250 | /* Function: ipf_resolvedest */ |
7251 | /* Returns: Nil */ |
7252 | /* Parameters: softc(I) - pointer to soft context main structure */ |
7253 | /* base(I) - where strings are stored */ |
7254 | /* fdp(IO) - pointer to destination information to resolve */ |
7255 | /* v(I) - IP protocol version to match */ |
7256 | /* */ |
7257 | /* Looks up an interface name in the frdest structure pointed to by fdp and */ |
7258 | /* if a matching name can be found for the particular IP protocol version */ |
7259 | /* then store the interface pointer in the frdest struct. If no match is */ |
7260 | /* found, then set the interface pointer to be -1 as NULL is considered to */ |
7261 | /* indicate there is no information at all in the structure. */ |
7262 | /* ------------------------------------------------------------------------ */ |
7263 | int |
7264 | ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) |
7265 | { |
7266 | int errval = 0; |
7267 | void *ifp; |
7268 | |
7269 | ifp = NULL; |
7270 | |
7271 | if (fdp->fd_name != -1) { |
7272 | if (fdp->fd_type == FRD_DSTLIST) { |
7273 | ifp = ipf_lookup_res_name(softc, IPL_LOGIPF, |
7274 | IPLT_DSTLIST, |
7275 | base + fdp->fd_name, |
7276 | NULL); |
7277 | if (ifp == NULL) { |
7278 | IPFERROR(144); |
7279 | errval = ESRCH; |
7280 | } |
7281 | } else { |
7282 | ifp = GETIFP(base + fdp->fd_name, v); |
7283 | if (ifp == NULL) |
7284 | ifp = (void *)-1; |
7285 | if ((ifp != NULL) && (ifp != (void *)-1)) |
7286 | fdp->fd_local = ipf_deliverlocal(softc, v, ifp, |
7287 | &fdp->fd_ip6); |
7288 | } |
7289 | } |
7290 | fdp->fd_ptr = ifp; |
7291 | |
7292 | return errval; |
7293 | } |
7294 | |
7295 | |
7296 | /* ------------------------------------------------------------------------ */ |
7297 | /* Function: ipf_resolvenic */ |
7298 | /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ |
7299 | /* pointer to interface structure for NIC */ |
7300 | /* Parameters: softc(I)- pointer to soft context main structure */ |
7301 | /* name(I) - complete interface name */ |
7302 | /* v(I) - IP protocol version */ |
7303 | /* */ |
7304 | /* Look for a network interface structure that firstly has a matching name */ |
7305 | /* to that passed in and that is also being used for that IP protocol */ |
7306 | /* version (necessary on some platforms where there are separate listings */ |
7307 | /* for both IPv4 and IPv6 on the same physical NIC. */ |
7308 | /* */ |
7309 | /* ------------------------------------------------------------------------ */ |
7310 | void * |
7311 | ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v) |
7312 | { |
7313 | void *nic; |
7314 | |
7315 | softc = softc; /* gcc -Wextra */ |
7316 | if (name[0] == '\0') |
7317 | return NULL; |
7318 | |
7319 | if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { |
7320 | return NULL; |
7321 | } |
7322 | |
7323 | nic = GETIFP(name, v); |
7324 | if (nic == NULL) |
7325 | nic = (void *)-1; |
7326 | return nic; |
7327 | } |
7328 | |
7329 | |
7330 | /* ------------------------------------------------------------------------ */ |
7331 | /* Function: ipf_token_expire */ |
7332 | /* Returns: None. */ |
7333 | /* Parameters: softc(I) - pointer to soft context main structure */ |
7334 | /* */ |
7335 | /* This function is run every ipf tick to see if there are any tokens that */ |
7336 | /* have been held for too long and need to be freed up. */ |
7337 | /* ------------------------------------------------------------------------ */ |
7338 | void |
7339 | ipf_token_expire(ipf_main_softc_t *softc) |
7340 | { |
7341 | ipftoken_t *it; |
7342 | |
7343 | WRITE_ENTER(&softc->ipf_tokens); |
7344 | while ((it = softc->ipf_token_head) != NULL) { |
7345 | if (it->ipt_die > softc->ipf_ticks) |
7346 | break; |
7347 | |
7348 | ipf_token_deref(softc, it); |
7349 | } |
7350 | RWLOCK_EXIT(&softc->ipf_tokens); |
7351 | } |
7352 | |
7353 | |
7354 | /* ------------------------------------------------------------------------ */ |
7355 | /* Function: ipf_token_flush */ |
7356 | /* Returns: None. */ |
7357 | /* Parameters: softc(I) - pointer to soft context main structure */ |
7358 | /* */ |
7359 | /* Loop through all of the existing tokens and call deref to see if they */ |
7360 | /* can be freed. Normally a function like this might just loop on */ |
7361 | /* ipf_token_head but there is a chance that a token might have a ref count */ |
7362 | /* of greater than one and in that case the the reference would drop twice */ |
7363 | /* by code that is only entitled to drop it once. */ |
7364 | /* ------------------------------------------------------------------------ */ |
7365 | static void |
7366 | ipf_token_flush(ipf_main_softc_t *softc) |
7367 | { |
7368 | ipftoken_t *it, *next; |
7369 | |
7370 | WRITE_ENTER(&softc->ipf_tokens); |
7371 | for (it = softc->ipf_token_head; it != NULL; it = next) { |
7372 | next = it->ipt_next; |
7373 | (void) ipf_token_deref(softc, it); |
7374 | } |
7375 | RWLOCK_EXIT(&softc->ipf_tokens); |
7376 | } |
7377 | |
7378 | |
7379 | /* ------------------------------------------------------------------------ */ |
7380 | /* Function: ipf_token_del */ |
7381 | /* Returns: int - 0 = success, else error */ |
7382 | /* Parameters: softc(I)- pointer to soft context main structure */ |
7383 | /* type(I) - the token type to match */ |
7384 | /* uid(I) - uid owning the token */ |
7385 | /* ptr(I) - context pointer for the token */ |
7386 | /* */ |
7387 | /* This function looks for a a token in the current list that matches up */ |
7388 | /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ |
7389 | /* call ipf_token_dewref() to remove it from the list. In the event that */ |
7390 | /* the token has a reference held elsewhere, setting ipt_complete to 2 */ |
7391 | /* enables debugging to distinguish between the two paths that ultimately */ |
7392 | /* lead to a token to be deleted. */ |
7393 | /* ------------------------------------------------------------------------ */ |
7394 | int |
7395 | ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr) |
7396 | { |
7397 | ipftoken_t *it; |
7398 | int error; |
7399 | |
7400 | IPFERROR(82); |
7401 | error = ESRCH; |
7402 | |
7403 | WRITE_ENTER(&softc->ipf_tokens); |
7404 | for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { |
7405 | if (ptr == it->ipt_ctx && type == it->ipt_type && |
7406 | uid == it->ipt_uid) { |
7407 | it->ipt_complete = 2; |
7408 | ipf_token_deref(softc, it); |
7409 | error = 0; |
7410 | break; |
7411 | } |
7412 | } |
7413 | RWLOCK_EXIT(&softc->ipf_tokens); |
7414 | |
7415 | return error; |
7416 | } |
7417 | |
7418 | |
7419 | /* ------------------------------------------------------------------------ */ |
7420 | /* Function: ipf_token_mark_complete */ |
7421 | /* Returns: None. */ |
7422 | /* Parameters: token(I) - pointer to token structure */ |
7423 | /* */ |
7424 | /* Mark a token as being ineligable for being found with ipf_token_find. */ |
7425 | /* ------------------------------------------------------------------------ */ |
7426 | void |
7427 | ipf_token_mark_complete(ipftoken_t *token) |
7428 | { |
7429 | if (token->ipt_complete == 0) |
7430 | token->ipt_complete = 1; |
7431 | } |
7432 | |
7433 | |
7434 | /* ------------------------------------------------------------------------ */ |
7435 | /* Function: ipf_token_find */ |
7436 | /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ |
7437 | /* Parameters: softc(I)- pointer to soft context main structure */ |
7438 | /* type(I) - the token type to match */ |
7439 | /* uid(I) - uid owning the token */ |
7440 | /* ptr(I) - context pointer for the token */ |
7441 | /* */ |
7442 | /* This function looks for a live token in the list of current tokens that */ |
7443 | /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ |
7444 | /* allocated. If one is found then it is moved to the top of the list of */ |
7445 | /* currently active tokens. */ |
7446 | /* ------------------------------------------------------------------------ */ |
7447 | ipftoken_t * |
7448 | ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) |
7449 | { |
7450 | ipftoken_t *it, *new; |
7451 | |
7452 | KMALLOC(new, ipftoken_t *); |
7453 | if (new != NULL) |
7454 | bzero((char *)new, sizeof(*new)); |
7455 | |
7456 | WRITE_ENTER(&softc->ipf_tokens); |
7457 | for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { |
7458 | if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && |
7459 | (uid == it->ipt_uid) && (it->ipt_complete < 2)) |
7460 | break; |
7461 | } |
7462 | |
7463 | if (it == NULL) { |
7464 | it = new; |
7465 | new = NULL; |
7466 | if (it == NULL) { |
7467 | RWLOCK_EXIT(&softc->ipf_tokens); |
7468 | return NULL; |
7469 | } |
7470 | it->ipt_ctx = ptr; |
7471 | it->ipt_uid = uid; |
7472 | it->ipt_type = type; |
7473 | it->ipt_ref = 1; |
7474 | } else { |
7475 | if (new != NULL) { |
7476 | KFREE(new); |
7477 | new = NULL; |
7478 | } |
7479 | |
7480 | if (it->ipt_complete > 0) |
7481 | it = NULL; |
7482 | else |
7483 | ipf_token_unlink(softc, it); |
7484 | } |
7485 | |
7486 | if (it != NULL) { |
7487 | it->ipt_pnext = softc->ipf_token_tail; |
7488 | *softc->ipf_token_tail = it; |
7489 | softc->ipf_token_tail = &it->ipt_next; |
7490 | it->ipt_next = NULL; |
7491 | it->ipt_ref++; |
7492 | |
7493 | it->ipt_die = softc->ipf_ticks + 20; |
7494 | } |
7495 | |
7496 | RWLOCK_EXIT(&softc->ipf_tokens); |
7497 | |
7498 | return it; |
7499 | } |
7500 | |
7501 | |
7502 | /* ------------------------------------------------------------------------ */ |
7503 | /* Function: ipf_token_unlink */ |
7504 | /* Returns: None. */ |
7505 | /* Parameters: softc(I) - pointer to soft context main structure */ |
7506 | /* token(I) - pointer to token structure */ |
7507 | /* Write Locks: ipf_tokens */ |
7508 | /* */ |
7509 | /* This function unlinks a token structure from the linked list of tokens */ |
7510 | /* that "own" it. The head pointer never needs to be explicitly adjusted */ |
7511 | /* but the tail does due to the linked list implementation. */ |
7512 | /* ------------------------------------------------------------------------ */ |
7513 | static void |
7514 | ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token) |
7515 | { |
7516 | |
7517 | if (softc->ipf_token_tail == &token->ipt_next) |
7518 | softc->ipf_token_tail = token->ipt_pnext; |
7519 | |
7520 | *token->ipt_pnext = token->ipt_next; |
7521 | if (token->ipt_next != NULL) |
7522 | token->ipt_next->ipt_pnext = token->ipt_pnext; |
7523 | token->ipt_next = NULL; |
7524 | token->ipt_pnext = NULL; |
7525 | } |
7526 | |
7527 | |
7528 | /* ------------------------------------------------------------------------ */ |
7529 | /* Function: ipf_token_deref */ |
7530 | /* Returns: int - 0 == token freed, else reference count */ |
7531 | /* Parameters: softc(I) - pointer to soft context main structure */ |
7532 | /* token(I) - pointer to token structure */ |
7533 | /* Write Locks: ipf_tokens */ |
7534 | /* */ |
7535 | /* Drop the reference count on the token structure and if it drops to zero, */ |
7536 | /* call the dereference function for the token type because it is then */ |
7537 | /* possible to free the token data structure. */ |
7538 | /* ------------------------------------------------------------------------ */ |
7539 | int |
7540 | ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token) |
7541 | { |
7542 | void *data, **datap; |
7543 | |
7544 | ASSERT(token->ipt_ref > 0); |
7545 | token->ipt_ref--; |
7546 | if (token->ipt_ref > 0) |
7547 | return token->ipt_ref; |
7548 | |
7549 | data = token->ipt_data; |
7550 | datap = &data; |
7551 | |
7552 | if ((data != NULL) && (data != (void *)-1)) { |
7553 | switch (token->ipt_type) |
7554 | { |
7555 | case IPFGENITER_IPF : |
7556 | (void) ipf_derefrule(softc, (frentry_t **)datap); |
7557 | break; |
7558 | case IPFGENITER_IPNAT : |
7559 | WRITE_ENTER(&softc->ipf_nat); |
7560 | ipf_nat_rule_deref(softc, (ipnat_t **)datap); |
7561 | RWLOCK_EXIT(&softc->ipf_nat); |
7562 | break; |
7563 | case IPFGENITER_NAT : |
7564 | ipf_nat_deref(softc, (nat_t **)datap); |
7565 | break; |
7566 | case IPFGENITER_STATE : |
7567 | ipf_state_deref(softc, (ipstate_t **)datap); |
7568 | break; |
7569 | case IPFGENITER_FRAG : |
7570 | ipf_frag_pkt_deref(softc, (ipfr_t **)datap); |
7571 | break; |
7572 | case IPFGENITER_NATFRAG : |
7573 | ipf_frag_nat_deref(softc, (ipfr_t **)datap); |
7574 | break; |
7575 | case IPFGENITER_HOSTMAP : |
7576 | WRITE_ENTER(&softc->ipf_nat); |
7577 | ipf_nat_hostmapdel(softc, (hostmap_t **)datap); |
7578 | RWLOCK_EXIT(&softc->ipf_nat); |
7579 | break; |
7580 | default : |
7581 | ipf_lookup_iterderef(softc, token->ipt_type, data); |
7582 | break; |
7583 | } |
7584 | } |
7585 | |
7586 | ipf_token_unlink(softc, token); |
7587 | KFREE(token); |
7588 | return 0; |
7589 | } |
7590 | |
7591 | |
7592 | /* ------------------------------------------------------------------------ */ |
7593 | /* Function: ipf_nextrule */ |
7594 | /* Returns: frentry_t * - NULL == no more rules, else pointer to next */ |
7595 | /* Parameters: softc(I) - pointer to soft context main structure */ |
7596 | /* fr(I) - pointer to filter rule */ |
7597 | /* out(I) - 1 == out rules, 0 == input rules */ |
7598 | /* */ |
7599 | /* Starting with "fr", find the next rule to visit. This includes visiting */ |
7600 | /* the list of rule groups if either fr is NULL (empty list) or it is the */ |
7601 | /* last rule in the list. When walking rule lists, it is either input or */ |
7602 | /* output rules that are returned, never both. */ |
7603 | /* ------------------------------------------------------------------------ */ |
7604 | static frentry_t * |
7605 | ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, |
7606 | frentry_t *fr, int out) |
7607 | { |
7608 | frentry_t *next; |
7609 | frgroup_t *fg; |
7610 | |
7611 | if (fr != NULL && fr->fr_group != -1) { |
7612 | fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group, |
7613 | unit, active, NULL); |
7614 | if (fg != NULL) |
7615 | fg = fg->fg_next; |
7616 | } else { |
7617 | fg = softc->ipf_groups[unit][active]; |
7618 | } |
7619 | |
7620 | while (fg != NULL) { |
7621 | next = fg->fg_start; |
7622 | while (next != NULL) { |
7623 | if (out) { |
7624 | if (next->fr_flags & FR_OUTQUE) |
7625 | return next; |
7626 | } else if (next->fr_flags & FR_INQUE) { |
7627 | return next; |
7628 | } |
7629 | next = next->fr_next; |
7630 | } |
7631 | if (next == NULL) |
7632 | fg = fg->fg_next; |
7633 | } |
7634 | |
7635 | return NULL; |
7636 | } |
7637 | |
7638 | /* ------------------------------------------------------------------------ */ |
7639 | /* Function: ipf_getnextrule */ |
7640 | /* Returns: int - 0 = success, else error */ |
7641 | /* Parameters: softc(I)- pointer to soft context main structure */ |
7642 | /* t(I) - pointer to destination information to resolve */ |
7643 | /* ptr(I) - pointer to ipfobj_t to copyin from user space */ |
7644 | /* */ |
7645 | /* This function's first job is to bring in the ipfruleiter_t structure via */ |
7646 | /* the ipfobj_t structure to determine what should be the next rule to */ |
7647 | /* return. Once the ipfruleiter_t has been brought in, it then tries to */ |
7648 | /* find the 'next rule'. This may include searching rule group lists or */ |
7649 | /* just be as simple as looking at the 'next' field in the rule structure. */ |
7650 | /* When we have found the rule to return, increase its reference count and */ |
7651 | /* if we used an existing rule to get here, decrease its reference count. */ |
7652 | /* ------------------------------------------------------------------------ */ |
7653 | int |
7654 | ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr) |
7655 | { |
7656 | frentry_t *fr, *next, zero; |
7657 | ipfruleiter_t it; |
7658 | int error, out; |
7659 | frgroup_t *fg; |
7660 | ipfobj_t obj; |
7661 | int predict; |
7662 | char *dst; |
7663 | int unit; |
7664 | |
7665 | if (t == NULL || ptr == NULL) { |
7666 | IPFERROR(84); |
7667 | return EFAULT; |
7668 | } |
7669 | |
7670 | error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER); |
7671 | if (error != 0) |
7672 | return error; |
7673 | |
7674 | if ((it.iri_inout < 0) || (it.iri_inout > 3)) { |
7675 | IPFERROR(85); |
7676 | return EINVAL; |
7677 | } |
7678 | if ((it.iri_active != 0) && (it.iri_active != 1)) { |
7679 | IPFERROR(86); |
7680 | return EINVAL; |
7681 | } |
7682 | if (it.iri_nrules == 0) { |
7683 | IPFERROR(87); |
7684 | return ENOSPC; |
7685 | } |
7686 | if (it.iri_rule == NULL) { |
7687 | IPFERROR(88); |
7688 | return EFAULT; |
7689 | } |
7690 | |
7691 | fg = NULL; |
7692 | fr = t->ipt_data; |
7693 | if ((it.iri_inout & F_OUT) != 0) |
7694 | out = 1; |
7695 | else |
7696 | out = 0; |
7697 | if ((it.iri_inout & F_ACIN) != 0) |
7698 | unit = IPL_LOGCOUNT; |
7699 | else |
7700 | unit = IPL_LOGIPF; |
7701 | |
7702 | READ_ENTER(&softc->ipf_mutex); |
7703 | if (fr == NULL) { |
7704 | if (*it.iri_group == '\0') { |
7705 | if (unit == IPL_LOGCOUNT) { |
7706 | next = softc->ipf_acct[out][it.iri_active]; |
7707 | } else { |
7708 | next = softc->ipf_rules[out][it.iri_active]; |
7709 | } |
7710 | if (next == NULL) |
7711 | next = ipf_nextrule(softc, it.iri_active, |
7712 | unit, NULL, out); |
7713 | } else { |
7714 | fg = ipf_findgroup(softc, it.iri_group, unit, |
7715 | it.iri_active, NULL); |
7716 | if (fg != NULL) |
7717 | next = fg->fg_start; |
7718 | else |
7719 | next = NULL; |
7720 | } |
7721 | } else { |
7722 | next = fr->fr_next; |
7723 | if (next == NULL) |
7724 | next = ipf_nextrule(softc, it.iri_active, unit, |
7725 | fr, out); |
7726 | } |
7727 | |
7728 | if (next != NULL && next->fr_next != NULL) |
7729 | predict = 1; |
7730 | else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL) |
7731 | predict = 1; |
7732 | else |
7733 | predict = 0; |
7734 | |
7735 | if (fr != NULL) |
7736 | (void) ipf_derefrule(softc, &fr); |
7737 | |
7738 | obj.ipfo_type = IPFOBJ_FRENTRY; |
7739 | dst = (char *)it.iri_rule; |
7740 | |
7741 | if (next != NULL) { |
7742 | obj.ipfo_size = next->fr_size; |
7743 | MUTEX_ENTER(&next->fr_lock); |
7744 | next->fr_ref++; |
7745 | MUTEX_EXIT(&next->fr_lock); |
7746 | t->ipt_data = next; |
7747 | } else { |
7748 | obj.ipfo_size = sizeof(frentry_t); |
7749 | bzero(&zero, sizeof(zero)); |
7750 | next = &zero; |
7751 | t->ipt_data = NULL; |
7752 | } |
7753 | it.iri_rule = predict ? next : NULL; |
7754 | if (predict == 0) |
7755 | ipf_token_mark_complete(t); |
7756 | |
7757 | RWLOCK_EXIT(&softc->ipf_mutex); |
7758 | |
7759 | obj.ipfo_ptr = dst; |
7760 | error = ipf_outobjk(softc, &obj, next); |
7761 | if (error == 0 && t->ipt_data != NULL) { |
7762 | dst += obj.ipfo_size; |
7763 | if (next->fr_data != NULL) { |
7764 | ipfobj_t dobj; |
7765 | |
7766 | if (next->fr_type == FR_T_IPFEXPR) |
7767 | dobj.ipfo_type = IPFOBJ_IPFEXPR; |
7768 | else |
7769 | dobj.ipfo_type = IPFOBJ_FRIPF; |
7770 | dobj.ipfo_size = next->fr_dsize; |
7771 | dobj.ipfo_rev = obj.ipfo_rev; |
7772 | dobj.ipfo_ptr = dst; |
7773 | error = ipf_outobjk(softc, &dobj, next->fr_data); |
7774 | } |
7775 | } |
7776 | |
7777 | if ((fr != NULL) && (next == &zero)) |
7778 | (void) ipf_derefrule(softc, &fr); |
7779 | |
7780 | return error; |
7781 | } |
7782 | |
7783 | |
7784 | /* ------------------------------------------------------------------------ */ |
7785 | /* Function: ipf_frruleiter */ |
7786 | /* Returns: int - 0 = success, else error */ |
7787 | /* Parameters: softc(I)- pointer to soft context main structure */ |
7788 | /* data(I) - the token type to match */ |
7789 | /* uid(I) - uid owning the token */ |
7790 | /* ptr(I) - context pointer for the token */ |
7791 | /* */ |
7792 | /* This function serves as a stepping stone between ipf_ipf_ioctl and */ |
7793 | /* ipf_getnextrule. It's role is to find the right token in the kernel for */ |
7794 | /* the process doing the ioctl and use that to ask for the next rule. */ |
7795 | /* ------------------------------------------------------------------------ */ |
7796 | static int |
7797 | ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) |
7798 | { |
7799 | ipftoken_t *token; |
7800 | ipfruleiter_t it; |
7801 | ipfobj_t obj; |
7802 | int error; |
7803 | |
7804 | token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx); |
7805 | if (token != NULL) { |
7806 | error = ipf_getnextrule(softc, token, data); |
7807 | WRITE_ENTER(&softc->ipf_tokens); |
7808 | ipf_token_deref(softc, token); |
7809 | RWLOCK_EXIT(&softc->ipf_tokens); |
7810 | } else { |
7811 | error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER); |
7812 | if (error != 0) |
7813 | return error; |
7814 | it.iri_rule = NULL; |
7815 | error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER); |
7816 | } |
7817 | |
7818 | return error; |
7819 | } |
7820 | |
7821 | |
7822 | /* ------------------------------------------------------------------------ */ |
7823 | /* Function: ipf_geniter */ |
7824 | /* Returns: int - 0 = success, else error */ |
7825 | /* Parameters: softc(I) - pointer to soft context main structure */ |
7826 | /* token(I) - pointer to ipftoken_t structure */ |
7827 | /* itp(I) - pointer to iterator data */ |
7828 | /* */ |
7829 | /* Decide which iterator function to call using information passed through */ |
7830 | /* the ipfgeniter_t structure at itp. */ |
7831 | /* ------------------------------------------------------------------------ */ |
7832 | static int |
7833 | ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp) |
7834 | { |
7835 | int error; |
7836 | |
7837 | switch (itp->igi_type) |
7838 | { |
7839 | case IPFGENITER_FRAG : |
7840 | error = ipf_frag_pkt_next(softc, token, itp); |
7841 | break; |
7842 | default : |
7843 | IPFERROR(92); |
7844 | error = EINVAL; |
7845 | break; |
7846 | } |
7847 | |
7848 | return error; |
7849 | } |
7850 | |
7851 | |
7852 | /* ------------------------------------------------------------------------ */ |
7853 | /* Function: ipf_genericiter */ |
7854 | /* Returns: int - 0 = success, else error */ |
7855 | /* Parameters: softc(I)- pointer to soft context main structure */ |
7856 | /* data(I) - the token type to match */ |
7857 | /* uid(I) - uid owning the token */ |
7858 | /* ptr(I) - context pointer for the token */ |
7859 | /* */ |
7860 | /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */ |
7861 | /* ------------------------------------------------------------------------ */ |
7862 | int |
7863 | ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) |
7864 | { |
7865 | ipftoken_t *token; |
7866 | ipfgeniter_t iter; |
7867 | int error; |
7868 | |
7869 | error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER); |
7870 | if (error != 0) |
7871 | return error; |
7872 | |
7873 | token = ipf_token_find(softc, iter.igi_type, uid, ctx); |
7874 | if (token != NULL) { |
7875 | token->ipt_subtype = iter.igi_type; |
7876 | error = ipf_geniter(softc, token, &iter); |
7877 | WRITE_ENTER(&softc->ipf_tokens); |
7878 | ipf_token_deref(softc, token); |
7879 | RWLOCK_EXIT(&softc->ipf_tokens); |
7880 | } else { |
7881 | IPFERROR(93); |
7882 | error = 0; |
7883 | } |
7884 | |
7885 | return error; |
7886 | } |
7887 | |
7888 | |
7889 | /* ------------------------------------------------------------------------ */ |
7890 | /* Function: ipf_ipf_ioctl */ |
7891 | /* Returns: int - 0 = success, else error */ |
7892 | /* Parameters: softc(I)- pointer to soft context main structure */ |
7893 | /* data(I) - the token type to match */ |
7894 | /* cmd(I) - the ioctl command number */ |
7895 | /* mode(I) - mode flags for the ioctl */ |
7896 | /* uid(I) - uid owning the token */ |
7897 | /* ptr(I) - context pointer for the token */ |
7898 | /* */ |
7899 | /* This function handles all of the ioctl command that are actually isssued */ |
7900 | /* to the /dev/ipl device. */ |
7901 | /* ------------------------------------------------------------------------ */ |
7902 | int |
7903 | ipf_ipf_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, |
7904 | int uid, void *ctx) |
7905 | { |
7906 | friostat_t fio; |
7907 | int error, tmp; |
7908 | ipfobj_t obj; |
7909 | SPL_INT(s); |
7910 | |
7911 | switch (cmd) |
7912 | { |
7913 | case SIOCFRENB : |
7914 | if (!(mode & FWRITE)) { |
7915 | IPFERROR(94); |
7916 | error = EPERM; |
7917 | } else { |
7918 | error = BCOPYIN(data, &tmp, sizeof(tmp)); |
7919 | if (error != 0) { |
7920 | IPFERROR(95); |
7921 | error = EFAULT; |
7922 | break; |
7923 | } |
7924 | |
7925 | WRITE_ENTER(&softc->ipf_global); |
7926 | if (tmp) { |
7927 | if (softc->ipf_running > 0) |
7928 | error = 0; |
7929 | else |
7930 | error = ipfattach(softc); |
7931 | if (error == 0) |
7932 | softc->ipf_running = 1; |
7933 | else |
7934 | (void) ipfdetach(softc); |
7935 | } else { |
7936 | if (softc->ipf_running == 1) |
7937 | error = ipfdetach(softc); |
7938 | else |
7939 | error = 0; |
7940 | if (error == 0) |
7941 | softc->ipf_running = -1; |
7942 | } |
7943 | RWLOCK_EXIT(&softc->ipf_global); |
7944 | } |
7945 | break; |
7946 | |
7947 | case SIOCIPFSET : |
7948 | if (!(mode & FWRITE)) { |
7949 | IPFERROR(96); |
7950 | error = EPERM; |
7951 | break; |
7952 | } |
7953 | /* FALLTHRU */ |
7954 | case SIOCIPFGETNEXT : |
7955 | case SIOCIPFGET : |
7956 | error = ipf_ipftune(softc, cmd, (void *)data); |
7957 | break; |
7958 | |
7959 | case SIOCSETFF : |
7960 | if (!(mode & FWRITE)) { |
7961 | IPFERROR(97); |
7962 | error = EPERM; |
7963 | } else { |
7964 | error = BCOPYIN(data, &softc->ipf_flags, |
7965 | sizeof(softc->ipf_flags)); |
7966 | if (error != 0) { |
7967 | IPFERROR(98); |
7968 | error = EFAULT; |
7969 | } |
7970 | } |
7971 | break; |
7972 | |
7973 | case SIOCGETFF : |
7974 | error = BCOPYOUT(&softc->ipf_flags, data, |
7975 | sizeof(softc->ipf_flags)); |
7976 | if (error != 0) { |
7977 | IPFERROR(99); |
7978 | error = EFAULT; |
7979 | } |
7980 | break; |
7981 | |
7982 | case SIOCFUNCL : |
7983 | error = ipf_resolvefunc(softc, (void *)data); |
7984 | break; |
7985 | |
7986 | case SIOCINAFR : |
7987 | case SIOCRMAFR : |
7988 | case SIOCADAFR : |
7989 | case SIOCZRLST : |
7990 | if (!(mode & FWRITE)) { |
7991 | IPFERROR(100); |
7992 | error = EPERM; |
7993 | } else { |
7994 | error = frrequest(softc, IPL_LOGIPF, cmd, data, |
7995 | softc->ipf_active, 1); |
7996 | } |
7997 | break; |
7998 | |
7999 | case SIOCINIFR : |
8000 | case SIOCRMIFR : |
8001 | case SIOCADIFR : |
8002 | if (!(mode & FWRITE)) { |
8003 | IPFERROR(101); |
8004 | error = EPERM; |
8005 | } else { |
8006 | error = frrequest(softc, IPL_LOGIPF, cmd, data, |
8007 | 1 - softc->ipf_active, 1); |
8008 | } |
8009 | break; |
8010 | |
8011 | case SIOCSWAPA : |
8012 | if (!(mode & FWRITE)) { |
8013 | IPFERROR(102); |
8014 | error = EPERM; |
8015 | } else { |
8016 | WRITE_ENTER(&softc->ipf_mutex); |
8017 | error = BCOPYOUT(&softc->ipf_active, data, |
8018 | sizeof(softc->ipf_active)); |
8019 | if (error != 0) { |
8020 | IPFERROR(103); |
8021 | error = EFAULT; |
8022 | } else { |
8023 | softc->ipf_active = 1 - softc->ipf_active; |
8024 | } |
8025 | RWLOCK_EXIT(&softc->ipf_mutex); |
8026 | } |
8027 | break; |
8028 | |
8029 | case SIOCGETFS : |
8030 | error = ipf_inobj(softc, (void *)data, &obj, &fio, |
8031 | IPFOBJ_IPFSTAT); |
8032 | if (error != 0) |
8033 | break; |
8034 | ipf_getstat(softc, &fio, obj.ipfo_rev); |
8035 | error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT); |
8036 | break; |
8037 | |
8038 | case SIOCFRZST : |
8039 | if (!(mode & FWRITE)) { |
8040 | IPFERROR(104); |
8041 | error = EPERM; |
8042 | } else |
8043 | error = ipf_zerostats(softc, data); |
8044 | break; |
8045 | |
8046 | case SIOCIPFFL : |
8047 | if (!(mode & FWRITE)) { |
8048 | IPFERROR(105); |
8049 | error = EPERM; |
8050 | } else { |
8051 | error = BCOPYIN(data, &tmp, sizeof(tmp)); |
8052 | if (!error) { |
8053 | tmp = ipf_flush(softc, IPL_LOGIPF, tmp); |
8054 | error = BCOPYOUT(&tmp, data, sizeof(tmp)); |
8055 | if (error != 0) { |
8056 | IPFERROR(106); |
8057 | error = EFAULT; |
8058 | } |
8059 | } else { |
8060 | IPFERROR(107); |
8061 | error = EFAULT; |
8062 | } |
8063 | } |
8064 | break; |
8065 | |
8066 | #ifdef USE_INET6 |
8067 | case SIOCIPFL6 : |
8068 | if (!(mode & FWRITE)) { |
8069 | IPFERROR(108); |
8070 | error = EPERM; |
8071 | } else { |
8072 | error = BCOPYIN(data, &tmp, sizeof(tmp)); |
8073 | if (!error) { |
8074 | tmp = ipf_flush(softc, IPL_LOGIPF, tmp); |
8075 | error = BCOPYOUT(&tmp, data, sizeof(tmp)); |
8076 | if (error != 0) { |
8077 | IPFERROR(109); |
8078 | error = EFAULT; |
8079 | } |
8080 | } else { |
8081 | IPFERROR(110); |
8082 | error = EFAULT; |
8083 | } |
8084 | } |
8085 | break; |
8086 | #endif |
8087 | |
8088 | case SIOCSTLCK : |
8089 | if (!(mode & FWRITE)) { |
8090 | IPFERROR(122); |
8091 | error = EPERM; |
8092 | } else { |
8093 | error = BCOPYIN(data, &tmp, sizeof(tmp)); |
8094 | if (error == 0) { |
8095 | ipf_state_setlock(softc->ipf_state_soft, tmp); |
8096 | ipf_nat_setlock(softc->ipf_nat_soft, tmp); |
8097 | ipf_frag_setlock(softc->ipf_frag_soft, tmp); |
8098 | ipf_auth_setlock(softc->ipf_auth_soft, tmp); |
8099 | } else { |
8100 | IPFERROR(111); |
8101 | error = EFAULT; |
8102 | } |
8103 | } |
8104 | break; |
8105 | |
8106 | #ifdef IPFILTER_LOG |
8107 | case SIOCIPFFB : |
8108 | if (!(mode & FWRITE)) { |
8109 | IPFERROR(112); |
8110 | error = EPERM; |
8111 | } else { |
8112 | tmp = ipf_log_clear(softc, IPL_LOGIPF); |
8113 | error = BCOPYOUT(&tmp, data, sizeof(tmp)); |
8114 | if (error) { |
8115 | IPFERROR(113); |
8116 | error = EFAULT; |
8117 | } |
8118 | } |
8119 | break; |
8120 | #endif /* IPFILTER_LOG */ |
8121 | |
8122 | case SIOCFRSYN : |
8123 | if (!(mode & FWRITE)) { |
8124 | IPFERROR(114); |
8125 | error = EPERM; |
8126 | } else { |
8127 | WRITE_ENTER(&softc->ipf_global); |
8128 | #if (defined(MENTAT) && defined(_KERNEL)) && !defined(INSTANCES) |
8129 | error = ipfsync(); |
8130 | #else |
8131 | ipf_sync(softc, NULL); |
8132 | error = 0; |
8133 | #endif |
8134 | RWLOCK_EXIT(&softc->ipf_global); |
8135 | |
8136 | } |
8137 | break; |
8138 | |
8139 | case SIOCGFRST : |
8140 | error = ipf_outobj(softc, (void *)data, |
8141 | ipf_frag_stats(softc->ipf_frag_soft), |
8142 | IPFOBJ_FRAGSTAT); |
8143 | break; |
8144 | |
8145 | #ifdef IPFILTER_LOG |
8146 | case FIONREAD : |
8147 | tmp = ipf_log_bytesused(softc, IPL_LOGIPF); |
8148 | error = BCOPYOUT(&tmp, data, sizeof(tmp)); |
8149 | break; |
8150 | #endif |
8151 | |
8152 | case SIOCIPFITER : |
8153 | SPL_SCHED(s); |
8154 | error = ipf_frruleiter(softc, data, uid, ctx); |
8155 | SPL_X(s); |
8156 | break; |
8157 | |
8158 | case SIOCGENITER : |
8159 | SPL_SCHED(s); |
8160 | error = ipf_genericiter(softc, data, uid, ctx); |
8161 | SPL_X(s); |
8162 | break; |
8163 | |
8164 | case SIOCIPFDELTOK : |
8165 | error = BCOPYIN(data, &tmp, sizeof(tmp)); |
8166 | if (error == 0) { |
8167 | SPL_SCHED(s); |
8168 | error = ipf_token_del(softc, tmp, uid, ctx); |
8169 | SPL_X(s); |
8170 | } |
8171 | break; |
8172 | |
8173 | default : |
8174 | IPFERROR(115); |
8175 | error = EINVAL; |
8176 | break; |
8177 | } |
8178 | |
8179 | return error; |
8180 | } |
8181 | |
8182 | |
8183 | /* ------------------------------------------------------------------------ */ |
8184 | /* Function: ipf_decaps */ |
8185 | /* Returns: int - -1 == decapsulation failed, else bit mask of */ |
8186 | /* flags indicating packet filtering decision. */ |
8187 | /* Parameters: fin(I) - pointer to packet information */ |
8188 | /* pass(I) - IP protocol version to match */ |
8189 | /* l5proto(I) - layer 5 protocol to decode UDP data as. */ |
8190 | /* */ |
8191 | /* This function is called for packets that are wrapt up in other packets, */ |
8192 | /* for example, an IP packet that is the entire data segment for another IP */ |
8193 | /* packet. If the basic constraints for this are satisfied, change the */ |
8194 | /* buffer to point to the start of the inner packet and start processing */ |
8195 | /* rules belonging to the head group this rule specifies. */ |
8196 | /* ------------------------------------------------------------------------ */ |
8197 | u_32_t |
8198 | ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto) |
8199 | { |
8200 | fr_info_t fin2, *fino = NULL; |
8201 | int elen, hlen, nh; |
8202 | grehdr_t gre; |
8203 | ip_t *ip; |
8204 | mb_t *m; |
8205 | |
8206 | if ((fin->fin_flx & FI_COALESCE) == 0) |
8207 | if (ipf_coalesce(fin) == -1) |
8208 | goto cantdecaps; |
8209 | |
8210 | m = fin->fin_m; |
8211 | hlen = fin->fin_hlen; |
8212 | |
8213 | switch (fin->fin_p) |
8214 | { |
8215 | case IPPROTO_UDP : |
8216 | /* |
8217 | * In this case, the specific protocol being decapsulated |
8218 | * inside UDP frames comes from the rule. |
8219 | */ |
8220 | nh = fin->fin_fr->fr_icode; |
8221 | break; |
8222 | |
8223 | case IPPROTO_GRE : /* 47 */ |
8224 | bcopy(fin->fin_dp, (char *)&gre, sizeof(gre)); |
8225 | hlen += sizeof(grehdr_t); |
8226 | if (gre.gr_R|gre.gr_s) |
8227 | goto cantdecaps; |
8228 | if (gre.gr_C) |
8229 | hlen += 4; |
8230 | if (gre.gr_K) |
8231 | hlen += 4; |
8232 | if (gre.gr_S) |
8233 | hlen += 4; |
8234 | |
8235 | nh = IPPROTO_IP; |
8236 | |
8237 | /* |
8238 | * If the routing options flag is set, validate that it is |
8239 | * there and bounce over it. |
8240 | */ |
8241 | #if 0 |
8242 | /* This is really heavy weight and lots of room for error, */ |
8243 | /* so for now, put it off and get the simple stuff right. */ |
8244 | if (gre.gr_R) { |
8245 | u_char off, len, *s; |
8246 | u_short af; |
8247 | int end; |
8248 | |
8249 | end = 0; |
8250 | s = fin->fin_dp; |
8251 | s += hlen; |
8252 | aplen = fin->fin_plen - hlen; |
8253 | while (aplen > 3) { |
8254 | af = (s[0] << 8) | s[1]; |
8255 | off = s[2]; |
8256 | len = s[3]; |
8257 | aplen -= 4; |
8258 | s += 4; |
8259 | if (af == 0 && len == 0) { |
8260 | end = 1; |
8261 | break; |
8262 | } |
8263 | if (aplen < len) |
8264 | break; |
8265 | s += len; |
8266 | aplen -= len; |
8267 | } |
8268 | if (end != 1) |
8269 | goto cantdecaps; |
8270 | hlen = s - (u_char *)fin->fin_dp; |
8271 | } |
8272 | #endif |
8273 | break; |
8274 | |
8275 | #ifdef IPPROTO_IPIP |
8276 | case IPPROTO_IPIP : /* 4 */ |
8277 | #endif |
8278 | nh = IPPROTO_IP; |
8279 | break; |
8280 | |
8281 | default : /* Includes ESP, AH is special for IPv4 */ |
8282 | goto cantdecaps; |
8283 | } |
8284 | |
8285 | switch (nh) |
8286 | { |
8287 | case IPPROTO_IP : |
8288 | case IPPROTO_IPV6 : |
8289 | break; |
8290 | default : |
8291 | goto cantdecaps; |
8292 | } |
8293 | |
8294 | bcopy((char *)fin, (char *)&fin2, sizeof(fin2)); |
8295 | fino = fin; |
8296 | fin = &fin2; |
8297 | elen = hlen; |
8298 | #if defined(MENTAT) && defined(_KERNEL) |
8299 | m->b_rptr += elen; |
8300 | #else |
8301 | m->m_data += elen; |
8302 | m->m_len -= elen; |
8303 | #endif |
8304 | fin->fin_plen -= elen; |
8305 | |
8306 | ip = (ip_t *)((char *)fin->fin_ip + elen); |
8307 | |
8308 | /* |
8309 | * Make sure we have at least enough data for the network layer |
8310 | * header. |
8311 | */ |
8312 | if (IP_V(ip) == 4) |
8313 | hlen = IP_HL(ip) << 2; |
8314 | #ifdef USE_INET6 |
8315 | else if (IP_V(ip) == 6) |
8316 | hlen = sizeof(ip6_t); |
8317 | #endif |
8318 | else |
8319 | goto cantdecaps2; |
8320 | |
8321 | if (fin->fin_plen < hlen) |
8322 | goto cantdecaps2; |
8323 | |
8324 | fin->fin_dp = (char *)ip + hlen; |
8325 | |
8326 | if (IP_V(ip) == 4) { |
8327 | /* |
8328 | * Perform IPv4 header checksum validation. |
8329 | */ |
8330 | if (ipf_cksum((u_short *)ip, hlen)) |
8331 | goto cantdecaps2; |
8332 | } |
8333 | |
8334 | if (ipf_makefrip(hlen, ip, fin) == -1) { |
8335 | cantdecaps2: |
8336 | if (m != NULL) { |
8337 | #if defined(MENTAT) && defined(_KERNEL) |
8338 | m->b_rptr -= elen; |
8339 | #else |
8340 | m->m_data -= elen; |
8341 | m->m_len += elen; |
8342 | #endif |
8343 | } |
8344 | cantdecaps: |
8345 | DT1(frb_decapfrip, fr_info_t *, fin); |
8346 | pass &= ~FR_CMDMASK; |
8347 | pass |= FR_BLOCK|FR_QUICK; |
8348 | fin->fin_reason = FRB_DECAPFRIP; |
8349 | return -1; |
8350 | } |
8351 | |
8352 | pass = ipf_scanlist(fin, pass); |
8353 | |
8354 | /* |
8355 | * Copy the packet filter "result" fields out of the fr_info_t struct |
8356 | * that is local to the decapsulation processing and back into the |
8357 | * one we were called with. |
8358 | */ |
8359 | fino->fin_flx = fin->fin_flx; |
8360 | fino->fin_rev = fin->fin_rev; |
8361 | fino->fin_icode = fin->fin_icode; |
8362 | fino->fin_rule = fin->fin_rule; |
8363 | (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN); |
8364 | fino->fin_fr = fin->fin_fr; |
8365 | fino->fin_error = fin->fin_error; |
8366 | fino->fin_mp = fin->fin_mp; |
8367 | fino->fin_m = fin->fin_m; |
8368 | m = fin->fin_m; |
8369 | if (m != NULL) { |
8370 | #if defined(MENTAT) && defined(_KERNEL) |
8371 | m->b_rptr -= elen; |
8372 | #else |
8373 | m->m_data -= elen; |
8374 | m->m_len += elen; |
8375 | #endif |
8376 | } |
8377 | return pass; |
8378 | } |
8379 | |
8380 | |
8381 | /* ------------------------------------------------------------------------ */ |
8382 | /* Function: ipf_matcharray_load */ |
8383 | /* Returns: int - 0 = success, else error */ |
8384 | /* Parameters: softc(I) - pointer to soft context main structure */ |
8385 | /* data(I) - pointer to ioctl data */ |
8386 | /* objp(I) - ipfobj_t structure to load data into */ |
8387 | /* arrayptr(I) - pointer to location to store array pointer */ |
8388 | /* */ |
8389 | /* This function loads in a mathing array through the ipfobj_t struct that */ |
8390 | /* describes it. Sanity checking and array size limitations are enforced */ |
8391 | /* in this function to prevent userspace from trying to load in something */ |
8392 | /* that is insanely big. Once the size of the array is known, the memory */ |
8393 | /* required is malloc'd and returned through changing *arrayptr. The */ |
8394 | /* contents of the array are verified before returning. Only in the event */ |
8395 | /* of a successful call is the caller required to free up the malloc area. */ |
8396 | /* ------------------------------------------------------------------------ */ |
8397 | int |
8398 | ipf_matcharray_load(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, |
8399 | int **arrayptr) |
8400 | { |
8401 | int arraysize, *array, error; |
8402 | |
8403 | *arrayptr = NULL; |
8404 | |
8405 | error = BCOPYIN(data, objp, sizeof(*objp)); |
8406 | if (error != 0) { |
8407 | IPFERROR(116); |
8408 | return EFAULT; |
8409 | } |
8410 | |
8411 | if (objp->ipfo_type != IPFOBJ_IPFEXPR) { |
8412 | IPFERROR(117); |
8413 | return EINVAL; |
8414 | } |
8415 | |
8416 | if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) || |
8417 | (objp->ipfo_size > 1024)) { |
8418 | IPFERROR(118); |
8419 | return EINVAL; |
8420 | } |
8421 | |
8422 | arraysize = objp->ipfo_size * sizeof(*array); |
8423 | KMALLOCS(array, int *, arraysize); |
8424 | if (array == NULL) { |
8425 | IPFERROR(119); |
8426 | return ENOMEM; |
8427 | } |
8428 | |
8429 | error = COPYIN(objp->ipfo_ptr, array, arraysize); |
8430 | if (error != 0) { |
8431 | KFREES(array, arraysize); |
8432 | IPFERROR(120); |
8433 | return EFAULT; |
8434 | } |
8435 | |
8436 | if (ipf_matcharray_verify(array, arraysize) != 0) { |
8437 | KFREES(array, arraysize); |
8438 | IPFERROR(121); |
8439 | return EINVAL; |
8440 | } |
8441 | |
8442 | *arrayptr = array; |
8443 | return 0; |
8444 | } |
8445 | |
8446 | |
8447 | /* ------------------------------------------------------------------------ */ |
8448 | /* Function: ipf_matcharray_verify */ |
8449 | /* Returns: Nil */ |
8450 | /* Parameters: array(I) - pointer to matching array */ |
8451 | /* arraysize(I) - number of elements in the array */ |
8452 | /* */ |
8453 | /* Verify the contents of a matching array by stepping through each element */ |
8454 | /* in it. The actual commands in the array are not verified for */ |
8455 | /* correctness, only that all of the sizes are correctly within limits. */ |
8456 | /* ------------------------------------------------------------------------ */ |
8457 | int |
8458 | ipf_matcharray_verify(int *array, int arraysize) |
8459 | { |
8460 | int i, nelem, maxidx; |
8461 | ipfexp_t *e; |
8462 | |
8463 | nelem = arraysize / sizeof(*array); |
8464 | |
8465 | /* |
8466 | * Currently, it makes no sense to have an array less than 6 |
8467 | * elements long - the initial size at the from, a single operation |
8468 | * (minimum 4 in length) and a trailer, for a total of 6. |
8469 | */ |
8470 | if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) { |
8471 | return -1; |
8472 | } |
8473 | |
8474 | /* |
8475 | * Verify the size of data pointed to by array with how long |
8476 | * the array claims to be itself. |
8477 | */ |
8478 | if (array[0] * sizeof(*array) != arraysize) { |
8479 | return -1; |
8480 | } |
8481 | |
8482 | maxidx = nelem - 1; |
8483 | /* |
8484 | * The last opcode in this array should be an IPF_EXP_END. |
8485 | */ |
8486 | if (array[maxidx] != IPF_EXP_END) { |
8487 | return -1; |
8488 | } |
8489 | |
8490 | for (i = 1; i < maxidx; ) { |
8491 | e = (ipfexp_t *)(array + i); |
8492 | |
8493 | /* |
8494 | * The length of the bits to check must be at least 1 |
8495 | * (or else there is nothing to comapre with!) and it |
8496 | * cannot exceed the length of the data present. |
8497 | */ |
8498 | if ((e->ipfe_size < 1 ) || |
8499 | (e->ipfe_size + i > maxidx)) { |
8500 | return -1; |
8501 | } |
8502 | i += e->ipfe_size; |
8503 | } |
8504 | return 0; |
8505 | } |
8506 | |
8507 | |
8508 | /* ------------------------------------------------------------------------ */ |
8509 | /* Function: ipf_fr_matcharray */ |
8510 | /* Returns: int - 0 = match failed, else positive match */ |
8511 | /* Parameters: fin(I) - pointer to packet information */ |
8512 | /* array(I) - pointer to matching array */ |
8513 | /* */ |
8514 | /* This function is used to apply a matching array against a packet and */ |
8515 | /* return an indication of whether or not the packet successfully matches */ |
8516 | /* all of the commands in it. */ |
8517 | /* ------------------------------------------------------------------------ */ |
8518 | static int |
8519 | ipf_fr_matcharray(fr_info_t *fin, int *array) |
8520 | { |
8521 | int i, n, *x, rv, p; |
8522 | ipfexp_t *e; |
8523 | |
8524 | rv = 0; |
8525 | n = array[0]; |
8526 | x = array + 1; |
8527 | |
8528 | for (; n > 0; x += 3 + x[3], rv = 0) { |
8529 | e = (ipfexp_t *)x; |
8530 | if (e->ipfe_cmd == IPF_EXP_END) |
8531 | break; |
8532 | n -= e->ipfe_size; |
8533 | |
8534 | /* |
8535 | * The upper 16 bits currently store the protocol value. |
8536 | * This is currently used with TCP and UDP port compares and |
8537 | * allows "tcp.port = 80" without requiring an explicit |
8538 | " "ip.pr = tcp" first. |
8539 | */ |
8540 | p = e->ipfe_cmd >> 16; |
8541 | if ((p != 0) && (p != fin->fin_p)) |
8542 | break; |
8543 | |
8544 | switch (e->ipfe_cmd) |
8545 | { |
8546 | case IPF_EXP_IP_PR : |
8547 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8548 | rv |= (fin->fin_p == e->ipfe_arg0[i]); |
8549 | } |
8550 | break; |
8551 | |
8552 | case IPF_EXP_IP_SRCADDR : |
8553 | if (fin->fin_v != 4) |
8554 | break; |
8555 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8556 | rv |= ((fin->fin_saddr & |
8557 | e->ipfe_arg0[i * 2 + 1]) == |
8558 | e->ipfe_arg0[i * 2]); |
8559 | } |
8560 | break; |
8561 | |
8562 | case IPF_EXP_IP_DSTADDR : |
8563 | if (fin->fin_v != 4) |
8564 | break; |
8565 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8566 | rv |= ((fin->fin_daddr & |
8567 | e->ipfe_arg0[i * 2 + 1]) == |
8568 | e->ipfe_arg0[i * 2]); |
8569 | } |
8570 | break; |
8571 | |
8572 | case IPF_EXP_IP_ADDR : |
8573 | if (fin->fin_v != 4) |
8574 | break; |
8575 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8576 | rv |= ((fin->fin_saddr & |
8577 | e->ipfe_arg0[i * 2 + 1]) == |
8578 | e->ipfe_arg0[i * 2]) || |
8579 | ((fin->fin_daddr & |
8580 | e->ipfe_arg0[i * 2 + 1]) == |
8581 | e->ipfe_arg0[i * 2]); |
8582 | } |
8583 | break; |
8584 | |
8585 | #ifdef USE_INET6 |
8586 | case IPF_EXP_IP6_SRCADDR : |
8587 | if (fin->fin_v != 6) |
8588 | break; |
8589 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8590 | rv |= IP6_MASKEQ(&fin->fin_src6, |
8591 | &e->ipfe_arg0[i * 8 + 4], |
8592 | &e->ipfe_arg0[i * 8]); |
8593 | } |
8594 | break; |
8595 | |
8596 | case IPF_EXP_IP6_DSTADDR : |
8597 | if (fin->fin_v != 6) |
8598 | break; |
8599 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8600 | rv |= IP6_MASKEQ(&fin->fin_dst6, |
8601 | &e->ipfe_arg0[i * 8 + 4], |
8602 | &e->ipfe_arg0[i * 8]); |
8603 | } |
8604 | break; |
8605 | |
8606 | case IPF_EXP_IP6_ADDR : |
8607 | if (fin->fin_v != 6) |
8608 | break; |
8609 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8610 | rv |= IP6_MASKEQ(&fin->fin_src6, |
8611 | &e->ipfe_arg0[i * 8 + 4], |
8612 | &e->ipfe_arg0[i * 8]) || |
8613 | IP6_MASKEQ(&fin->fin_dst6, |
8614 | &e->ipfe_arg0[i * 8 + 4], |
8615 | &e->ipfe_arg0[i * 8]); |
8616 | } |
8617 | break; |
8618 | #endif |
8619 | |
8620 | case IPF_EXP_UDP_PORT : |
8621 | case IPF_EXP_TCP_PORT : |
8622 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8623 | rv |= (fin->fin_sport == e->ipfe_arg0[i]) || |
8624 | (fin->fin_dport == e->ipfe_arg0[i]); |
8625 | } |
8626 | break; |
8627 | |
8628 | case IPF_EXP_UDP_SPORT : |
8629 | case IPF_EXP_TCP_SPORT : |
8630 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8631 | rv |= (fin->fin_sport == e->ipfe_arg0[i]); |
8632 | } |
8633 | break; |
8634 | |
8635 | case IPF_EXP_UDP_DPORT : |
8636 | case IPF_EXP_TCP_DPORT : |
8637 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8638 | rv |= (fin->fin_dport == e->ipfe_arg0[i]); |
8639 | } |
8640 | break; |
8641 | |
8642 | case IPF_EXP_TCP_FLAGS : |
8643 | for (i = 0; !rv && i < e->ipfe_narg; i++) { |
8644 | rv |= ((fin->fin_tcpf & |
8645 | e->ipfe_arg0[i * 2 + 1]) == |
8646 | e->ipfe_arg0[i * 2]); |
8647 | } |
8648 | break; |
8649 | } |
8650 | rv ^= e->ipfe_not; |
8651 | |
8652 | if (rv == 0) |
8653 | break; |
8654 | } |
8655 | |
8656 | return rv; |
8657 | } |
8658 | |
8659 | |
8660 | /* ------------------------------------------------------------------------ */ |
8661 | /* Function: ipf_queueflush */ |
8662 | /* Returns: int - number of entries flushed (0 = none) */ |
8663 | /* Parameters: softc(I) - pointer to soft context main structure */ |
8664 | /* deletefn(I) - function to call to delete entry */ |
8665 | /* ipfqs(I) - top of the list of ipf internal queues */ |
8666 | /* userqs(I) - top of the list of user defined timeouts */ |
8667 | /* */ |
8668 | /* This fucntion gets called when the state/NAT hash tables fill up and we */ |
8669 | /* need to try a bit harder to free up some space. The algorithm used here */ |
8670 | /* split into two parts but both halves have the same goal: to reduce the */ |
8671 | /* number of connections considered to be "active" to the low watermark. */ |
8672 | /* There are two steps in doing this: */ |
8673 | /* 1) Remove any TCP connections that are already considered to be "closed" */ |
8674 | /* but have not yet been removed from the state table. The two states */ |
8675 | /* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */ |
8676 | /* candidates for this style of removal. If freeing up entries in */ |
8677 | /* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */ |
8678 | /* we do not go on to step 2. */ |
8679 | /* */ |
8680 | /* 2) Look for the oldest entries on each timeout queue and free them if */ |
8681 | /* they are within the given window we are considering. Where the */ |
8682 | /* window starts and the steps taken to increase its size depend upon */ |
8683 | /* how long ipf has been running (ipf_ticks.) Anything modified in the */ |
8684 | /* last 30 seconds is not touched. */ |
8685 | /* touched */ |
8686 | /* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */ |
8687 | /* | | | | | | */ |
8688 | /* future <--+----------+--------+-----------+-----+-----+-----------> past */ |
8689 | /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ |
8690 | /* */ |
8691 | /* Points to note: */ |
8692 | /* - tqe_die is the time, in the future, when entries die. */ |
8693 | /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */ |
8694 | /* ticks. */ |
8695 | /* - tqe_touched is when the entry was last used by NAT/state */ |
8696 | /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */ |
8697 | /* ipf_ticks any given timeout queue and vice versa. */ |
8698 | /* - both tqe_die and tqe_touched increase over time */ |
8699 | /* - timeout queues are sorted with the highest value of tqe_die at the */ |
8700 | /* bottom and therefore the smallest values of each are at the top */ |
8701 | /* - the pointer passed in as ipfqs should point to an array of timeout */ |
8702 | /* queues representing each of the TCP states */ |
8703 | /* */ |
8704 | /* We start by setting up a maximum range to scan for things to move of */ |
8705 | /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ |
8706 | /* found in that range, "interval" is adjusted (so long as it isn't 30) and */ |
8707 | /* we start again with a new value for "iend" and "istart". This is */ |
8708 | /* continued until we either finish the scan of 30 second intervals or the */ |
8709 | /* low water mark is reached. */ |
8710 | /* ------------------------------------------------------------------------ */ |
8711 | int |
8712 | ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn, |
8713 | ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low) |
8714 | { |
8715 | u_long interval, istart, iend; |
8716 | ipftq_t *ifq, *ifqnext; |
8717 | ipftqent_t *tqe, *tqn; |
8718 | int removed = 0; |
8719 | |
8720 | for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) { |
8721 | tqn = tqe->tqe_next; |
8722 | if ((*deletefn)(softc, tqe->tqe_parent) == 0) |
8723 | removed++; |
8724 | } |
8725 | if ((*activep * 100 / size) > low) { |
8726 | for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head; |
8727 | ((tqe = tqn) != NULL); ) { |
8728 | tqn = tqe->tqe_next; |
8729 | if ((*deletefn)(softc, tqe->tqe_parent) == 0) |
8730 | removed++; |
8731 | } |
8732 | } |
8733 | |
8734 | if ((*activep * 100 / size) <= low) { |
8735 | return removed; |
8736 | } |
8737 | |
8738 | /* |
8739 | * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is |
8740 | * used then the operations are upgraded to floating point |
8741 | * and kernels don't like floating point... |
8742 | */ |
8743 | if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) { |
8744 | istart = IPF_TTLVAL(86400 * 4); |
8745 | interval = IPF_TTLVAL(43200); |
8746 | } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) { |
8747 | istart = IPF_TTLVAL(43200); |
8748 | interval = IPF_TTLVAL(1800); |
8749 | } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) { |
8750 | istart = IPF_TTLVAL(1800); |
8751 | interval = IPF_TTLVAL(30); |
8752 | } else { |
8753 | return 0; |
8754 | } |
8755 | if (istart > softc->ipf_ticks) { |
8756 | if (softc->ipf_ticks - interval < interval) |
8757 | istart = interval; |
8758 | else |
8759 | istart = (softc->ipf_ticks / interval) * interval; |
8760 | } |
8761 | |
8762 | iend = softc->ipf_ticks - interval; |
8763 | |
8764 | while ((*activep * 100 / size) > low) { |
8765 | u_long try; |
8766 | |
8767 | try = softc->ipf_ticks - istart; |
8768 | |
8769 | for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { |
8770 | for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { |
8771 | if (try < tqe->tqe_touched) |
8772 | break; |
8773 | tqn = tqe->tqe_next; |
8774 | if ((*deletefn)(softc, tqe->tqe_parent) == 0) |
8775 | removed++; |
8776 | } |
8777 | } |
8778 | |
8779 | for (ifq = userqs; ifq != NULL; ifq = ifqnext) { |
8780 | ifqnext = ifq->ifq_next; |
8781 | |
8782 | for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { |
8783 | if (try < tqe->tqe_touched) |
8784 | break; |
8785 | tqn = tqe->tqe_next; |
8786 | if ((*deletefn)(softc, tqe->tqe_parent) == 0) |
8787 | removed++; |
8788 | } |
8789 | } |
8790 | |
8791 | if (try >= iend) { |
8792 | if (interval == IPF_TTLVAL(43200)) { |
8793 | interval = IPF_TTLVAL(1800); |
8794 | } else if (interval == IPF_TTLVAL(1800)) { |
8795 | interval = IPF_TTLVAL(30); |
8796 | } else { |
8797 | break; |
8798 | } |
8799 | if (interval >= softc->ipf_ticks) |
8800 | break; |
8801 | |
8802 | iend = softc->ipf_ticks - interval; |
8803 | } |
8804 | istart -= interval; |
8805 | } |
8806 | |
8807 | return removed; |
8808 | } |
8809 | |
8810 | |
8811 | /* ------------------------------------------------------------------------ */ |
8812 | /* Function: ipf_deliverlocal */ |
8813 | /* Returns: int - 1 = local address, 0 = non-local address */ |
8814 | /* Parameters: softc(I) - pointer to soft context main structure */ |
8815 | /* ipversion(I) - IP protocol version (4 or 6) */ |
8816 | /* ifp(I) - network interface pointer */ |
8817 | /* ipaddr(I) - IPv4/6 destination address */ |
8818 | /* */ |
8819 | /* This fucntion is used to determine in the address "ipaddr" belongs to */ |
8820 | /* the network interface represented by ifp. */ |
8821 | /* ------------------------------------------------------------------------ */ |
8822 | int |
8823 | ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp, |
8824 | i6addr_t *ipaddr) |
8825 | { |
8826 | i6addr_t addr; |
8827 | int islocal = 0; |
8828 | |
8829 | if (ipversion == 4) { |
8830 | if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) { |
8831 | if (addr.in4.s_addr == ipaddr->in4.s_addr) |
8832 | islocal = 1; |
8833 | } |
8834 | |
8835 | #ifdef USE_INET6 |
8836 | } else if (ipversion == 6) { |
8837 | if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) { |
8838 | if (IP6_EQ(&addr, ipaddr)) |
8839 | islocal = 1; |
8840 | } |
8841 | #endif |
8842 | } |
8843 | |
8844 | return islocal; |
8845 | } |
8846 | |
8847 | |
8848 | /* ------------------------------------------------------------------------ */ |
8849 | /* Function: ipf_settimeout */ |
8850 | /* Returns: int - 0 = success, -1 = failure */ |
8851 | /* Parameters: softc(I) - pointer to soft context main structure */ |
8852 | /* t(I) - pointer to tuneable array entry */ |
8853 | /* p(I) - pointer to values passed in to apply */ |
8854 | /* */ |
8855 | /* This function is called to set the timeout values for each distinct */ |
8856 | /* queue timeout that is available. When called, it calls into both the */ |
8857 | /* state and NAT code, telling them to update their timeout queues. */ |
8858 | /* ------------------------------------------------------------------------ */ |
8859 | static int |
8860 | ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, |
8861 | ipftuneval_t *p) |
8862 | { |
8863 | |
8864 | /* |
8865 | * ipf_interror should be set by the functions called here, not |
8866 | * by this function - it's just a middle man. |
8867 | */ |
8868 | if (ipf_state_settimeout(softc, t, p) == -1) |
8869 | return -1; |
8870 | if (ipf_nat_settimeout(softc, t, p) == -1) |
8871 | return -1; |
8872 | return 0; |
8873 | } |
8874 | |
8875 | |
8876 | /* ------------------------------------------------------------------------ */ |
8877 | /* Function: ipf_apply_timeout */ |
8878 | /* Returns: int - 0 = success, -1 = failure */ |
8879 | /* Parameters: head(I) - pointer to tuneable array entry */ |
8880 | /* seconds(I) - pointer to values passed in to apply */ |
8881 | /* */ |
8882 | /* This function applies a timeout of "seconds" to the timeout queue that */ |
8883 | /* is pointed to by "head". All entries on this list have an expiration */ |
8884 | /* set to be the current tick value of ipf plus the ttl. Given that this */ |
8885 | /* function should only be called when the delta is non-zero, the task is */ |
8886 | /* to walk the entire list and apply the change. The sort order will not */ |
8887 | /* change. The only catch is that this is O(n) across the list, so if the */ |
8888 | /* queue has lots of entries (10s of thousands or 100s of thousands), it */ |
8889 | /* could take a relatively long time to work through them all. */ |
8890 | /* ------------------------------------------------------------------------ */ |
8891 | void |
8892 | ipf_apply_timeout(ipftq_t *head, u_int seconds) |
8893 | { |
8894 | u_int oldtimeout, newtimeout; |
8895 | ipftqent_t *tqe; |
8896 | int delta; |
8897 | |
8898 | MUTEX_ENTER(&head->ifq_lock); |
8899 | oldtimeout = head->ifq_ttl; |
8900 | newtimeout = IPF_TTLVAL(seconds); |
8901 | delta = oldtimeout - newtimeout; |
8902 | |
8903 | head->ifq_ttl = newtimeout; |
8904 | |
8905 | for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) { |
8906 | tqe->tqe_die += delta; |
8907 | } |
8908 | MUTEX_EXIT(&head->ifq_lock); |
8909 | } |
8910 | |
8911 | |
8912 | /* ------------------------------------------------------------------------ */ |
8913 | /* Function: ipf_settimeout_tcp */ |
8914 | /* Returns: int - 0 = successfully applied, -1 = failed */ |
8915 | /* Parameters: t(I) - pointer to tuneable to change */ |
8916 | /* p(I) - pointer to new timeout information */ |
8917 | /* tab(I) - pointer to table of TCP queues */ |
8918 | /* */ |
8919 | /* This function applies the new timeout (p) to the TCP tunable (t) and */ |
8920 | /* updates all of the entries on the relevant timeout queue by calling */ |
8921 | /* ipf_apply_timeout(). */ |
8922 | /* ------------------------------------------------------------------------ */ |
8923 | int |
8924 | ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab) |
8925 | { |
8926 | if (!strcmp(t->ipft_name, "tcp_idle_timeout" ) || |
8927 | !strcmp(t->ipft_name, "tcp_established" )) { |
8928 | ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int); |
8929 | } else if (!strcmp(t->ipft_name, "tcp_close_wait" )) { |
8930 | ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int); |
8931 | } else if (!strcmp(t->ipft_name, "tcp_last_ack" )) { |
8932 | ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int); |
8933 | } else if (!strcmp(t->ipft_name, "tcp_timeout" )) { |
8934 | ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); |
8935 | ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); |
8936 | ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); |
8937 | } else if (!strcmp(t->ipft_name, "tcp_listen" )) { |
8938 | ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); |
8939 | } else if (!strcmp(t->ipft_name, "tcp_half_established" )) { |
8940 | ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); |
8941 | } else if (!strcmp(t->ipft_name, "tcp_closing" )) { |
8942 | ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); |
8943 | } else if (!strcmp(t->ipft_name, "tcp_syn_received" )) { |
8944 | ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int); |
8945 | } else if (!strcmp(t->ipft_name, "tcp_syn_sent" )) { |
8946 | ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int); |
8947 | } else if (!strcmp(t->ipft_name, "tcp_closed" )) { |
8948 | ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); |
8949 | } else if (!strcmp(t->ipft_name, "tcp_half_closed" )) { |
8950 | ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); |
8951 | } else if (!strcmp(t->ipft_name, "tcp_time_wait" )) { |
8952 | ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int); |
8953 | } else { |
8954 | /* |
8955 | * ipf_interror isn't set here because it should be set |
8956 | * by whatever called this function. |
8957 | */ |
8958 | return -1; |
8959 | } |
8960 | return 0; |
8961 | } |
8962 | |
8963 | |
8964 | /* ------------------------------------------------------------------------ */ |
8965 | /* Function: ipf_main_soft_create */ |
8966 | /* Returns: NULL = failure, else success */ |
8967 | /* Parameters: arg(I) - pointer to soft context structure if already allocd */ |
8968 | /* */ |
8969 | /* Create the foundation soft context structure. In circumstances where it */ |
8970 | /* is not required to dynamically allocate the context, a pointer can be */ |
8971 | /* passed in (rather than NULL) to a structure to be initialised. */ |
8972 | /* The main thing of interest is that a number of locks are initialised */ |
8973 | /* here instead of in the where might be expected - in the relevant create */ |
8974 | /* function elsewhere. This is done because the current locking design has */ |
8975 | /* some areas where these locks are used outside of their module. */ |
8976 | /* Possibly the most important exercise that is done here is setting of all */ |
8977 | /* the timeout values, allowing them to be changed before init(). */ |
8978 | /* ------------------------------------------------------------------------ */ |
8979 | void * |
8980 | ipf_main_soft_create(void *arg) |
8981 | { |
8982 | ipf_main_softc_t *softc; |
8983 | |
8984 | if (arg == NULL) { |
8985 | KMALLOC(softc, ipf_main_softc_t *); |
8986 | if (softc == NULL) |
8987 | return NULL; |
8988 | } else { |
8989 | softc = arg; |
8990 | } |
8991 | |
8992 | bzero((char *)softc, sizeof(*softc)); |
8993 | |
8994 | /* |
8995 | * This serves as a flag as to whether or not the softc should be |
8996 | * free'd when _destroy is called. |
8997 | */ |
8998 | softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0; |
8999 | |
9000 | softc->ipf_tuners = ipf_tune_array_copy(softc, |
9001 | sizeof(ipf_main_tuneables), |
9002 | ipf_main_tuneables); |
9003 | if (softc->ipf_tuners == NULL) { |
9004 | ipf_main_soft_destroy(softc); |
9005 | return NULL; |
9006 | } |
9007 | |
9008 | MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex" ); |
9009 | MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock" ); |
9010 | RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex" ); |
9011 | RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock" ); |
9012 | RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock" ); |
9013 | RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock" ); |
9014 | RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock" ); |
9015 | RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock" ); |
9016 | RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock" ); |
9017 | |
9018 | softc->ipf_token_head = NULL; |
9019 | softc->ipf_token_tail = &softc->ipf_token_head; |
9020 | |
9021 | softc->ipf_tcpidletimeout = FIVE_DAYS; |
9022 | softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL); |
9023 | softc->ipf_tcplastack = IPF_TTLVAL(30); |
9024 | softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL); |
9025 | softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL); |
9026 | softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL); |
9027 | softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL); |
9028 | softc->ipf_tcpclosed = IPF_TTLVAL(30); |
9029 | softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600); |
9030 | softc->ipf_udptimeout = IPF_TTLVAL(120); |
9031 | softc->ipf_udpacktimeout = IPF_TTLVAL(12); |
9032 | softc->ipf_icmptimeout = IPF_TTLVAL(60); |
9033 | softc->ipf_icmpacktimeout = IPF_TTLVAL(6); |
9034 | softc->ipf_iptimeout = IPF_TTLVAL(60); |
9035 | |
9036 | #if defined(IPFILTER_DEFAULT_BLOCK) |
9037 | softc->ipf_pass = FR_BLOCK|FR_NOMATCH; |
9038 | #else |
9039 | softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; |
9040 | #endif |
9041 | softc->ipf_minttl = 4; |
9042 | softc->ipf_icmpminfragmtu = 68; |
9043 | softc->ipf_flags = IPF_LOGGING; |
9044 | |
9045 | return softc; |
9046 | } |
9047 | |
9048 | /* ------------------------------------------------------------------------ */ |
9049 | /* Function: ipf_main_soft_init */ |
9050 | /* Returns: 0 = success, -1 = failure */ |
9051 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9052 | /* */ |
9053 | /* A null-op function that exists as a placeholder so that the flow in */ |
9054 | /* other functions is obvious. */ |
9055 | /* ------------------------------------------------------------------------ */ |
9056 | /*ARGSUSED*/ |
9057 | int |
9058 | ipf_main_soft_init(ipf_main_softc_t *softc) |
9059 | { |
9060 | return 0; |
9061 | } |
9062 | |
9063 | |
9064 | /* ------------------------------------------------------------------------ */ |
9065 | /* Function: ipf_main_soft_destroy */ |
9066 | /* Returns: void */ |
9067 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9068 | /* */ |
9069 | /* Undo everything that we did in ipf_main_soft_create. */ |
9070 | /* */ |
9071 | /* The most important check that needs to be made here is whether or not */ |
9072 | /* the structure was allocated by ipf_main_soft_create() by checking what */ |
9073 | /* value is stored in ipf_dynamic_main. */ |
9074 | /* ------------------------------------------------------------------------ */ |
9075 | /*ARGSUSED*/ |
9076 | void |
9077 | ipf_main_soft_destroy(ipf_main_softc_t *softc) |
9078 | { |
9079 | |
9080 | RW_DESTROY(&softc->ipf_frag); |
9081 | RW_DESTROY(&softc->ipf_poolrw); |
9082 | RW_DESTROY(&softc->ipf_nat); |
9083 | RW_DESTROY(&softc->ipf_state); |
9084 | RW_DESTROY(&softc->ipf_tokens); |
9085 | RW_DESTROY(&softc->ipf_mutex); |
9086 | RW_DESTROY(&softc->ipf_global); |
9087 | MUTEX_DESTROY(&softc->ipf_timeoutlock); |
9088 | MUTEX_DESTROY(&softc->ipf_rw); |
9089 | |
9090 | if (softc->ipf_tuners != NULL) { |
9091 | KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables)); |
9092 | } |
9093 | if (softc->ipf_dynamic_softc == 1) { |
9094 | KFREE(softc); |
9095 | } |
9096 | } |
9097 | |
9098 | |
9099 | /* ------------------------------------------------------------------------ */ |
9100 | /* Function: ipf_main_soft_fini */ |
9101 | /* Returns: 0 = success, -1 = failure */ |
9102 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9103 | /* */ |
9104 | /* Clean out the rules which have been added since _init was last called, */ |
9105 | /* the only dynamic part of the mainline. */ |
9106 | /* ------------------------------------------------------------------------ */ |
9107 | int |
9108 | ipf_main_soft_fini(ipf_main_softc_t *softc) |
9109 | { |
9110 | (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); |
9111 | (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE); |
9112 | (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE); |
9113 | (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE); |
9114 | |
9115 | return 0; |
9116 | } |
9117 | |
9118 | |
9119 | /* ------------------------------------------------------------------------ */ |
9120 | /* Function: ipf_main_load */ |
9121 | /* Returns: 0 = success, -1 = failure */ |
9122 | /* Parameters: none */ |
9123 | /* */ |
9124 | /* Handle global initialisation that needs to be done for the base part of */ |
9125 | /* IPFilter. At present this just amounts to initialising some ICMP lookup */ |
9126 | /* arrays that get used by the state/NAT code. */ |
9127 | /* ------------------------------------------------------------------------ */ |
9128 | int |
9129 | ipf_main_load(void) |
9130 | { |
9131 | int i; |
9132 | |
9133 | /* fill icmp reply type table */ |
9134 | for (i = 0; i <= ICMP_MAXTYPE; i++) |
9135 | icmpreplytype4[i] = -1; |
9136 | icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; |
9137 | icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; |
9138 | icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; |
9139 | icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; |
9140 | |
9141 | #ifdef USE_INET6 |
9142 | /* fill icmp reply type table */ |
9143 | for (i = 0; i <= ICMP6_MAXTYPE; i++) |
9144 | icmpreplytype6[i] = -1; |
9145 | icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY; |
9146 | icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT; |
9147 | icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY; |
9148 | icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT; |
9149 | icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; |
9150 | #endif |
9151 | |
9152 | return 0; |
9153 | } |
9154 | |
9155 | |
9156 | /* ------------------------------------------------------------------------ */ |
9157 | /* Function: ipf_main_unload */ |
9158 | /* Returns: 0 = success, -1 = failure */ |
9159 | /* Parameters: none */ |
9160 | /* */ |
9161 | /* A null-op function that exists as a placeholder so that the flow in */ |
9162 | /* other functions is obvious. */ |
9163 | /* ------------------------------------------------------------------------ */ |
9164 | int |
9165 | ipf_main_unload(void) |
9166 | { |
9167 | return 0; |
9168 | } |
9169 | |
9170 | |
9171 | /* ------------------------------------------------------------------------ */ |
9172 | /* Function: ipf_load_all */ |
9173 | /* Returns: 0 = success, -1 = failure */ |
9174 | /* Parameters: none */ |
9175 | /* */ |
9176 | /* Work through all of the subsystems inside IPFilter and call the load */ |
9177 | /* function for each in an order that won't lead to a crash :) */ |
9178 | /* ------------------------------------------------------------------------ */ |
9179 | int |
9180 | ipf_load_all(void) |
9181 | { |
9182 | if (ipf_main_load() == -1) |
9183 | return -1; |
9184 | |
9185 | if (ipf_state_main_load() == -1) |
9186 | return -1; |
9187 | |
9188 | if (ipf_nat_main_load() == -1) |
9189 | return -1; |
9190 | |
9191 | if (ipf_frag_main_load() == -1) |
9192 | return -1; |
9193 | |
9194 | if (ipf_auth_main_load() == -1) |
9195 | return -1; |
9196 | |
9197 | if (ipf_proxy_main_load() == -1) |
9198 | return -1; |
9199 | |
9200 | return 0; |
9201 | } |
9202 | |
9203 | |
9204 | /* ------------------------------------------------------------------------ */ |
9205 | /* Function: ipf_unload_all */ |
9206 | /* Returns: 0 = success, -1 = failure */ |
9207 | /* Parameters: none */ |
9208 | /* */ |
9209 | /* Work through all of the subsystems inside IPFilter and call the unload */ |
9210 | /* function for each in an order that won't lead to a crash :) */ |
9211 | /* ------------------------------------------------------------------------ */ |
9212 | int |
9213 | ipf_unload_all(void) |
9214 | { |
9215 | if (ipf_proxy_main_unload() == -1) |
9216 | return -1; |
9217 | |
9218 | if (ipf_auth_main_unload() == -1) |
9219 | return -1; |
9220 | |
9221 | if (ipf_frag_main_unload() == -1) |
9222 | return -1; |
9223 | |
9224 | if (ipf_nat_main_unload() == -1) |
9225 | return -1; |
9226 | |
9227 | if (ipf_state_main_unload() == -1) |
9228 | return -1; |
9229 | |
9230 | if (ipf_main_unload() == -1) |
9231 | return -1; |
9232 | |
9233 | return 0; |
9234 | } |
9235 | |
9236 | |
9237 | /* ------------------------------------------------------------------------ */ |
9238 | /* Function: ipf_create_all */ |
9239 | /* Returns: NULL = failure, else success */ |
9240 | /* Parameters: arg(I) - pointer to soft context main structure */ |
9241 | /* */ |
9242 | /* Work through all of the subsystems inside IPFilter and call the create */ |
9243 | /* function for each in an order that won't lead to a crash :) */ |
9244 | /* ------------------------------------------------------------------------ */ |
9245 | ipf_main_softc_t * |
9246 | ipf_create_all(void *arg) |
9247 | { |
9248 | ipf_main_softc_t *softc; |
9249 | |
9250 | softc = ipf_main_soft_create(arg); |
9251 | if (softc == NULL) |
9252 | return NULL; |
9253 | |
9254 | #ifdef IPFILTER_LOG |
9255 | softc->ipf_log_soft = ipf_log_soft_create(softc); |
9256 | if (softc->ipf_log_soft == NULL) { |
9257 | ipf_destroy_all(softc); |
9258 | return NULL; |
9259 | } |
9260 | #endif |
9261 | |
9262 | softc->ipf_lookup_soft = ipf_lookup_soft_create(softc); |
9263 | if (softc->ipf_lookup_soft == NULL) { |
9264 | ipf_destroy_all(softc); |
9265 | return NULL; |
9266 | } |
9267 | |
9268 | softc->ipf_sync_soft = ipf_sync_soft_create(softc); |
9269 | if (softc->ipf_sync_soft == NULL) { |
9270 | ipf_destroy_all(softc); |
9271 | return NULL; |
9272 | } |
9273 | |
9274 | softc->ipf_state_soft = ipf_state_soft_create(softc); |
9275 | if (softc->ipf_state_soft == NULL) { |
9276 | ipf_destroy_all(softc); |
9277 | return NULL; |
9278 | } |
9279 | |
9280 | softc->ipf_nat_soft = ipf_nat_soft_create(softc); |
9281 | if (softc->ipf_nat_soft == NULL) { |
9282 | ipf_destroy_all(softc); |
9283 | return NULL; |
9284 | } |
9285 | |
9286 | softc->ipf_frag_soft = ipf_frag_soft_create(softc); |
9287 | if (softc->ipf_frag_soft == NULL) { |
9288 | ipf_destroy_all(softc); |
9289 | return NULL; |
9290 | } |
9291 | |
9292 | softc->ipf_auth_soft = ipf_auth_soft_create(softc); |
9293 | if (softc->ipf_auth_soft == NULL) { |
9294 | ipf_destroy_all(softc); |
9295 | return NULL; |
9296 | } |
9297 | |
9298 | softc->ipf_proxy_soft = ipf_proxy_soft_create(softc); |
9299 | if (softc->ipf_proxy_soft == NULL) { |
9300 | ipf_destroy_all(softc); |
9301 | return NULL; |
9302 | } |
9303 | |
9304 | return softc; |
9305 | } |
9306 | |
9307 | |
9308 | /* ------------------------------------------------------------------------ */ |
9309 | /* Function: ipf_destroy_all */ |
9310 | /* Returns: void */ |
9311 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9312 | /* */ |
9313 | /* Work through all of the subsystems inside IPFilter and call the destroy */ |
9314 | /* function for each in an order that won't lead to a crash :) */ |
9315 | /* */ |
9316 | /* Every one of these functions is expected to succeed, so there is no */ |
9317 | /* checking of return values. */ |
9318 | /* ------------------------------------------------------------------------ */ |
9319 | void |
9320 | ipf_destroy_all(ipf_main_softc_t *softc) |
9321 | { |
9322 | |
9323 | if (softc->ipf_state_soft != NULL) { |
9324 | ipf_state_soft_destroy(softc, softc->ipf_state_soft); |
9325 | softc->ipf_state_soft = NULL; |
9326 | } |
9327 | |
9328 | if (softc->ipf_nat_soft != NULL) { |
9329 | ipf_nat_soft_destroy(softc, softc->ipf_nat_soft); |
9330 | softc->ipf_nat_soft = NULL; |
9331 | } |
9332 | |
9333 | if (softc->ipf_frag_soft != NULL) { |
9334 | ipf_frag_soft_destroy(softc, softc->ipf_frag_soft); |
9335 | softc->ipf_frag_soft = NULL; |
9336 | } |
9337 | |
9338 | if (softc->ipf_auth_soft != NULL) { |
9339 | ipf_auth_soft_destroy(softc, softc->ipf_auth_soft); |
9340 | softc->ipf_auth_soft = NULL; |
9341 | } |
9342 | |
9343 | if (softc->ipf_proxy_soft != NULL) { |
9344 | ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft); |
9345 | softc->ipf_proxy_soft = NULL; |
9346 | } |
9347 | |
9348 | if (softc->ipf_sync_soft != NULL) { |
9349 | ipf_sync_soft_destroy(softc, softc->ipf_sync_soft); |
9350 | softc->ipf_sync_soft = NULL; |
9351 | } |
9352 | |
9353 | if (softc->ipf_lookup_soft != NULL) { |
9354 | ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft); |
9355 | softc->ipf_lookup_soft = NULL; |
9356 | } |
9357 | |
9358 | #ifdef IPFILTER_LOG |
9359 | if (softc->ipf_log_soft != NULL) { |
9360 | ipf_log_soft_destroy(softc, softc->ipf_log_soft); |
9361 | softc->ipf_log_soft = NULL; |
9362 | } |
9363 | #endif |
9364 | |
9365 | ipf_main_soft_destroy(softc); |
9366 | } |
9367 | |
9368 | |
9369 | /* ------------------------------------------------------------------------ */ |
9370 | /* Function: ipf_init_all */ |
9371 | /* Returns: 0 = success, -1 = failure */ |
9372 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9373 | /* */ |
9374 | /* Work through all of the subsystems inside IPFilter and call the init */ |
9375 | /* function for each in an order that won't lead to a crash :) */ |
9376 | /* ------------------------------------------------------------------------ */ |
9377 | int |
9378 | ipf_init_all(ipf_main_softc_t *softc) |
9379 | { |
9380 | |
9381 | if (ipf_main_soft_init(softc) == -1) |
9382 | return -1; |
9383 | |
9384 | #ifdef IPFILTER_LOG |
9385 | if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1) |
9386 | return -1; |
9387 | #endif |
9388 | |
9389 | if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1) |
9390 | return -1; |
9391 | |
9392 | if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1) |
9393 | return -1; |
9394 | |
9395 | if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1) |
9396 | return -1; |
9397 | |
9398 | if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1) |
9399 | return -1; |
9400 | |
9401 | if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1) |
9402 | return -1; |
9403 | |
9404 | if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1) |
9405 | return -1; |
9406 | |
9407 | if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1) |
9408 | return -1; |
9409 | |
9410 | return 0; |
9411 | } |
9412 | |
9413 | |
9414 | /* ------------------------------------------------------------------------ */ |
9415 | /* Function: ipf_fini_all */ |
9416 | /* Returns: 0 = success, -1 = failure */ |
9417 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9418 | /* */ |
9419 | /* Work through all of the subsystems inside IPFilter and call the fini */ |
9420 | /* function for each in an order that won't lead to a crash :) */ |
9421 | /* ------------------------------------------------------------------------ */ |
9422 | int |
9423 | ipf_fini_all(ipf_main_softc_t *softc) |
9424 | { |
9425 | |
9426 | ipf_token_flush(softc); |
9427 | |
9428 | if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1) |
9429 | return -1; |
9430 | |
9431 | if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1) |
9432 | return -1; |
9433 | |
9434 | if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1) |
9435 | return -1; |
9436 | |
9437 | if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1) |
9438 | return -1; |
9439 | |
9440 | if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1) |
9441 | return -1; |
9442 | |
9443 | if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1) |
9444 | return -1; |
9445 | |
9446 | if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1) |
9447 | return -1; |
9448 | |
9449 | #ifdef IPFILTER_LOG |
9450 | if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1) |
9451 | return -1; |
9452 | #endif |
9453 | |
9454 | if (ipf_main_soft_fini(softc) == -1) |
9455 | return -1; |
9456 | |
9457 | return 0; |
9458 | } |
9459 | |
9460 | |
9461 | /* ------------------------------------------------------------------------ */ |
9462 | /* Function: ipf_rule_expire */ |
9463 | /* Returns: Nil */ |
9464 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9465 | /* */ |
9466 | /* At present this function exists just to support temporary addition of */ |
9467 | /* firewall rules. Both inactive and active lists are scanned for items to */ |
9468 | /* purge, as by rights, the expiration is computed as soon as the rule is */ |
9469 | /* loaded in. */ |
9470 | /* ------------------------------------------------------------------------ */ |
9471 | void |
9472 | ipf_rule_expire(ipf_main_softc_t *softc) |
9473 | { |
9474 | frentry_t *fr; |
9475 | |
9476 | if ((softc->ipf_rule_explist[0] == NULL) && |
9477 | (softc->ipf_rule_explist[1] == NULL)) |
9478 | return; |
9479 | |
9480 | WRITE_ENTER(&softc->ipf_mutex); |
9481 | |
9482 | while ((fr = softc->ipf_rule_explist[0]) != NULL) { |
9483 | /* |
9484 | * Because the list is kept sorted on insertion, the fist |
9485 | * one that dies in the future means no more work to do. |
9486 | */ |
9487 | if (fr->fr_die > softc->ipf_ticks) |
9488 | break; |
9489 | ipf_rule_delete(softc, fr, IPL_LOGIPF, 0); |
9490 | } |
9491 | |
9492 | while ((fr = softc->ipf_rule_explist[1]) != NULL) { |
9493 | /* |
9494 | * Because the list is kept sorted on insertion, the fist |
9495 | * one that dies in the future means no more work to do. |
9496 | */ |
9497 | if (fr->fr_die > softc->ipf_ticks) |
9498 | break; |
9499 | ipf_rule_delete(softc, fr, IPL_LOGIPF, 1); |
9500 | } |
9501 | |
9502 | RWLOCK_EXIT(&softc->ipf_mutex); |
9503 | } |
9504 | |
9505 | |
9506 | static int ipf_ht_node_cmp(const struct host_node_s *, const struct host_node_s *); |
9507 | static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int, |
9508 | i6addr_t *); |
9509 | |
9510 | RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp) |
9511 | |
9512 | |
9513 | /* ------------------------------------------------------------------------ */ |
9514 | /* Function: ipf_ht_node_cmp */ |
9515 | /* Returns: int - 0 == nodes are the same, .. */ |
9516 | /* Parameters: k1(I) - pointer to first key to compare */ |
9517 | /* k2(I) - pointer to second key to compare */ |
9518 | /* */ |
9519 | /* The "key" for the node is a combination of two fields: the address */ |
9520 | /* family and the address itself. */ |
9521 | /* */ |
9522 | /* Because we're not actually interpreting the address data, it isn't */ |
9523 | /* necessary to convert them to/from network/host byte order. The mask is */ |
9524 | /* just used to remove bits that aren't significant - it doesn't matter */ |
9525 | /* where they are, as long as they're always in the same place. */ |
9526 | /* */ |
9527 | /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */ |
9528 | /* this is where individual ones will differ the most - but not true for */ |
9529 | /* for /48's, etc. */ |
9530 | /* ------------------------------------------------------------------------ */ |
9531 | static int |
9532 | ipf_ht_node_cmp(const struct host_node_s *k1, const struct host_node_s *k2) |
9533 | { |
9534 | int i; |
9535 | |
9536 | i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family); |
9537 | if (i != 0) |
9538 | return i; |
9539 | |
9540 | if (k1->hn_addr.adf_family == AF_INET) |
9541 | return (k2->hn_addr.adf_addr.in4.s_addr - |
9542 | k1->hn_addr.adf_addr.in4.s_addr); |
9543 | |
9544 | i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3]; |
9545 | if (i != 0) |
9546 | return i; |
9547 | i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2]; |
9548 | if (i != 0) |
9549 | return i; |
9550 | i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1]; |
9551 | if (i != 0) |
9552 | return i; |
9553 | i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0]; |
9554 | return i; |
9555 | } |
9556 | |
9557 | |
9558 | /* ------------------------------------------------------------------------ */ |
9559 | /* Function: ipf_ht_node_make_key */ |
9560 | /* Returns: Nil */ |
9561 | /* parameters: htp(I) - pointer to address tracking structure */ |
9562 | /* key(I) - where to store masked address for lookup */ |
9563 | /* family(I) - protocol family of address */ |
9564 | /* addr(I) - pointer to network address */ |
9565 | /* */ |
9566 | /* Using the "netmask" (number of bits) stored parent host tracking struct, */ |
9567 | /* copy the address passed in into the key structure whilst masking out the */ |
9568 | /* bits that we don't want. */ |
9569 | /* */ |
9570 | /* Because the parser will set ht_netmask to 128 if there is no protocol */ |
9571 | /* specified (the parser doesn't know if it should be a v4 or v6 rule), we */ |
9572 | /* have to be wary of that and not allow 32-128 to happen. */ |
9573 | /* ------------------------------------------------------------------------ */ |
9574 | static void |
9575 | ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family, |
9576 | i6addr_t *addr) |
9577 | { |
9578 | key->hn_addr.adf_family = family; |
9579 | if (family == AF_INET) { |
9580 | u_32_t mask; |
9581 | int bits; |
9582 | |
9583 | key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4); |
9584 | bits = htp->ht_netmask; |
9585 | if (bits >= 32) { |
9586 | mask = 0xffffffff; |
9587 | } else { |
9588 | mask = htonl(0xffffffff << (32 - bits)); |
9589 | } |
9590 | key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask; |
9591 | #ifdef USE_INET6 |
9592 | } else { |
9593 | int bits = htp->ht_netmask; |
9594 | |
9595 | key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6); |
9596 | if (bits > 96) { |
9597 | key->hn_addr.adf_addr.i6[3] = addr->i6[3] & |
9598 | htonl(0xffffffff << (128 - bits)); |
9599 | key->hn_addr.adf_addr.i6[2] = addr->i6[2]; |
9600 | key->hn_addr.adf_addr.i6[1] = addr->i6[2]; |
9601 | key->hn_addr.adf_addr.i6[0] = addr->i6[2]; |
9602 | } else if (bits > 64) { |
9603 | key->hn_addr.adf_addr.i6[3] = 0; |
9604 | key->hn_addr.adf_addr.i6[2] = addr->i6[2] & |
9605 | htonl(0xffffffff << (96 - bits)); |
9606 | key->hn_addr.adf_addr.i6[1] = addr->i6[1]; |
9607 | key->hn_addr.adf_addr.i6[0] = addr->i6[0]; |
9608 | } else if (bits > 32) { |
9609 | key->hn_addr.adf_addr.i6[3] = 0; |
9610 | key->hn_addr.adf_addr.i6[2] = 0; |
9611 | key->hn_addr.adf_addr.i6[1] = addr->i6[1] & |
9612 | htonl(0xffffffff << (64 - bits)); |
9613 | key->hn_addr.adf_addr.i6[0] = addr->i6[0]; |
9614 | } else { |
9615 | key->hn_addr.adf_addr.i6[3] = 0; |
9616 | key->hn_addr.adf_addr.i6[2] = 0; |
9617 | key->hn_addr.adf_addr.i6[1] = 0; |
9618 | key->hn_addr.adf_addr.i6[0] = addr->i6[0] & |
9619 | htonl(0xffffffff << (32 - bits)); |
9620 | } |
9621 | #endif |
9622 | } |
9623 | } |
9624 | |
9625 | |
9626 | /* ------------------------------------------------------------------------ */ |
9627 | /* Function: ipf_ht_node_add */ |
9628 | /* Returns: int - 0 == success, -1 == failure */ |
9629 | /* Parameters: softc(I) - pointer to soft context main structure */ |
9630 | /* htp(I) - pointer to address tracking structure */ |
9631 | /* family(I) - protocol family of address */ |
9632 | /* addr(I) - pointer to network address */ |
9633 | /* */ |
9634 | /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ |
9635 | /* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */ |
9636 | /* */ |
9637 | /* After preparing the key with the address information to find, look in */ |
9638 | /* the red-black tree to see if the address is known. A successful call to */ |
9639 | /* this function can mean one of two things: a new node was added to the */ |
9640 | /* tree or a matching node exists and we're able to bump up its activity. */ |
9641 | /* ------------------------------------------------------------------------ */ |
9642 | int |
9643 | ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family, |
9644 | i6addr_t *addr) |
9645 | { |
9646 | host_node_t *h; |
9647 | host_node_t k; |
9648 | |
9649 | ipf_ht_node_make_key(htp, &k, family, addr); |
9650 | |
9651 | h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); |
9652 | if (h == NULL) { |
9653 | if (htp->ht_cur_nodes >= htp->ht_max_nodes) |
9654 | return -1; |
9655 | KMALLOC(h, host_node_t *); |
9656 | if (h == NULL) { |
9657 | DT(ipf_rb_no_mem); |
9658 | LBUMP(ipf_rb_no_mem); |
9659 | return -1; |
9660 | } |
9661 | |
9662 | /* |
9663 | * If there was a macro to initialise the RB node then that |
9664 | * would get used here, but there isn't... |
9665 | */ |
9666 | bzero((char *)h, sizeof(*h)); |
9667 | h->hn_addr = k.hn_addr; |
9668 | h->hn_addr.adf_family = k.hn_addr.adf_family; |
9669 | RBI_INSERT(ipf_rb, &htp->ht_root, h); |
9670 | htp->ht_cur_nodes++; |
9671 | } else { |
9672 | if ((htp->ht_max_per_node != 0) && |
9673 | (h->hn_active >= htp->ht_max_per_node)) { |
9674 | DT(ipf_rb_node_max); |
9675 | LBUMP(ipf_rb_node_max); |
9676 | return -1; |
9677 | } |
9678 | } |
9679 | |
9680 | h->hn_active++; |
9681 | |
9682 | return 0; |
9683 | } |
9684 | |
9685 | |
9686 | /* ------------------------------------------------------------------------ */ |
9687 | /* Function: ipf_ht_node_del */ |
9688 | /* Returns: int - 0 == success, -1 == failure */ |
9689 | /* parameters: htp(I) - pointer to address tracking structure */ |
9690 | /* family(I) - protocol family of address */ |
9691 | /* addr(I) - pointer to network address */ |
9692 | /* */ |
9693 | /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ |
9694 | /* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */ |
9695 | /* */ |
9696 | /* Try and find the address passed in amongst the leaves on this tree to */ |
9697 | /* be friend. If found then drop the active account for that node drops by */ |
9698 | /* one. If that count reaches 0, it is time to free it all up. */ |
9699 | /* ------------------------------------------------------------------------ */ |
9700 | int |
9701 | ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr) |
9702 | { |
9703 | host_node_t *h; |
9704 | host_node_t k; |
9705 | |
9706 | ipf_ht_node_make_key(htp, &k, family, addr); |
9707 | |
9708 | h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); |
9709 | if (h == NULL) { |
9710 | return -1; |
9711 | } else { |
9712 | h->hn_active--; |
9713 | if (h->hn_active == 0) { |
9714 | (void) RBI_DELETE(ipf_rb, &htp->ht_root, h); |
9715 | htp->ht_cur_nodes--; |
9716 | KFREE(h); |
9717 | } |
9718 | } |
9719 | |
9720 | return 0; |
9721 | } |
9722 | |
9723 | |
9724 | /* ------------------------------------------------------------------------ */ |
9725 | /* Function: ipf_rb_ht_init */ |
9726 | /* Returns: Nil */ |
9727 | /* Parameters: head(I) - pointer to host tracking structure */ |
9728 | /* */ |
9729 | /* Initialise the host tracking structure to be ready for use above. */ |
9730 | /* ------------------------------------------------------------------------ */ |
9731 | void |
9732 | ipf_rb_ht_init(host_track_t *head) |
9733 | { |
9734 | memset(head, 0, sizeof(*head)); |
9735 | RBI_INIT(ipf_rb, &head->ht_root); |
9736 | } |
9737 | |
9738 | |
9739 | /* ------------------------------------------------------------------------ */ |
9740 | /* Function: ipf_rb_ht_freenode */ |
9741 | /* Returns: Nil */ |
9742 | /* Parameters: head(I) - pointer to host tracking structure */ |
9743 | /* arg(I) - additional argument from walk caller */ |
9744 | /* */ |
9745 | /* Free an actual host_node_t structure. */ |
9746 | /* ------------------------------------------------------------------------ */ |
9747 | void |
9748 | ipf_rb_ht_freenode(host_node_t *node, void *arg) |
9749 | { |
9750 | KFREE(node); |
9751 | } |
9752 | |
9753 | |
9754 | /* ------------------------------------------------------------------------ */ |
9755 | /* Function: ipf_rb_ht_flush */ |
9756 | /* Returns: Nil */ |
9757 | /* Parameters: head(I) - pointer to host tracking structure */ |
9758 | /* */ |
9759 | /* Remove all of the nodes in the tree tracking hosts by calling a walker */ |
9760 | /* and free'ing each one. */ |
9761 | /* ------------------------------------------------------------------------ */ |
9762 | void |
9763 | ipf_rb_ht_flush(host_track_t *head) |
9764 | { |
9765 | /* XXX - May use node members after freeing the node. */ |
9766 | RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL); |
9767 | } |
9768 | |
9769 | |
9770 | /* ------------------------------------------------------------------------ */ |
9771 | /* Function: ipf_slowtimer */ |
9772 | /* Returns: Nil */ |
9773 | /* Parameters: ptr(I) - pointer to main ipf soft context structure */ |
9774 | /* */ |
9775 | /* Slowly expire held state for fragments. Timeouts are set * in */ |
9776 | /* expectation of this being called twice per second. */ |
9777 | /* ------------------------------------------------------------------------ */ |
9778 | void |
9779 | ipf_slowtimer(ipf_main_softc_t *softc) |
9780 | { |
9781 | |
9782 | ipf_token_expire(softc); |
9783 | ipf_frag_expire(softc); |
9784 | ipf_state_expire(softc); |
9785 | ipf_nat_expire(softc); |
9786 | ipf_auth_expire(softc); |
9787 | ipf_lookup_expire(softc); |
9788 | ipf_rule_expire(softc); |
9789 | ipf_sync_expire(softc); |
9790 | softc->ipf_ticks++; |
9791 | # if defined(__OpenBSD__) |
9792 | timeout_add(&ipf_slowtimer_ch, hz/2); |
9793 | # endif |
9794 | } |
9795 | |
9796 | |
9797 | /* ------------------------------------------------------------------------ */ |
9798 | /* Function: ipf_inet_mask_add */ |
9799 | /* Returns: Nil */ |
9800 | /* Parameters: bits(I) - pointer to nat context information */ |
9801 | /* mtab(I) - pointer to mask hash table structure */ |
9802 | /* */ |
9803 | /* When called, bits represents the mask of a new NAT rule that has just */ |
9804 | /* been added. This function inserts a bitmask into the array of masks to */ |
9805 | /* search when searching for a matching NAT rule for a packet. */ |
9806 | /* Prevention of duplicate masks is achieved by checking the use count for */ |
9807 | /* a given netmask. */ |
9808 | /* ------------------------------------------------------------------------ */ |
9809 | void |
9810 | ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab) |
9811 | { |
9812 | u_32_t mask; |
9813 | int i, j; |
9814 | |
9815 | mtab->imt4_masks[bits]++; |
9816 | if (mtab->imt4_masks[bits] > 1) |
9817 | return; |
9818 | |
9819 | if (bits == 0) |
9820 | mask = 0; |
9821 | else |
9822 | mask = 0xffffffff << (32 - bits); |
9823 | |
9824 | for (i = 0; i < 33; i++) { |
9825 | if (ntohl(mtab->imt4_active[i]) < mask) { |
9826 | for (j = 32; j > i; j--) |
9827 | mtab->imt4_active[j] = mtab->imt4_active[j - 1]; |
9828 | mtab->imt4_active[i] = htonl(mask); |
9829 | break; |
9830 | } |
9831 | } |
9832 | mtab->imt4_max++; |
9833 | } |
9834 | |
9835 | |
9836 | /* ------------------------------------------------------------------------ */ |
9837 | /* Function: ipf_inet_mask_del */ |
9838 | /* Returns: Nil */ |
9839 | /* Parameters: bits(I) - number of bits set in the netmask */ |
9840 | /* mtab(I) - pointer to mask hash table structure */ |
9841 | /* */ |
9842 | /* Remove the 32bit bitmask represented by "bits" from the collection of */ |
9843 | /* netmasks stored inside of mtab. */ |
9844 | /* ------------------------------------------------------------------------ */ |
9845 | void |
9846 | ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab) |
9847 | { |
9848 | u_32_t mask; |
9849 | int i, j; |
9850 | |
9851 | mtab->imt4_masks[bits]--; |
9852 | if (mtab->imt4_masks[bits] > 0) |
9853 | return; |
9854 | |
9855 | mask = htonl(0xffffffff << (32 - bits)); |
9856 | for (i = 0; i < 33; i++) { |
9857 | if (mtab->imt4_active[i] == mask) { |
9858 | for (j = i + 1; j < 33; j++) |
9859 | mtab->imt4_active[j - 1] = mtab->imt4_active[j]; |
9860 | break; |
9861 | } |
9862 | } |
9863 | mtab->imt4_max--; |
9864 | ASSERT(mtab->imt4_max >= 0); |
9865 | } |
9866 | |
9867 | |
9868 | #ifdef USE_INET6 |
9869 | /* ------------------------------------------------------------------------ */ |
9870 | /* Function: ipf_inet6_mask_add */ |
9871 | /* Returns: Nil */ |
9872 | /* Parameters: bits(I) - number of bits set in mask */ |
9873 | /* mask(I) - pointer to mask to add */ |
9874 | /* mtab(I) - pointer to mask hash table structure */ |
9875 | /* */ |
9876 | /* When called, bitcount represents the mask of a IPv6 NAT map rule that */ |
9877 | /* has just been added. This function inserts a bitmask into the array of */ |
9878 | /* masks to search when searching for a matching NAT rule for a packet. */ |
9879 | /* Prevention of duplicate masks is achieved by checking the use count for */ |
9880 | /* a given netmask. */ |
9881 | /* ------------------------------------------------------------------------ */ |
9882 | void |
9883 | ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) |
9884 | { |
9885 | i6addr_t zero; |
9886 | int i, j; |
9887 | |
9888 | mtab->imt6_masks[bits]++; |
9889 | if (mtab->imt6_masks[bits] > 1) |
9890 | return; |
9891 | |
9892 | if (bits == 0) { |
9893 | mask = &zero; |
9894 | zero.i6[0] = 0; |
9895 | zero.i6[1] = 0; |
9896 | zero.i6[2] = 0; |
9897 | zero.i6[3] = 0; |
9898 | } |
9899 | |
9900 | for (i = 0; i < 129; i++) { |
9901 | if (IP6_LT(&mtab->imt6_active[i], mask)) { |
9902 | for (j = 128; j > i; j--) |
9903 | mtab->imt6_active[j] = mtab->imt6_active[j - 1]; |
9904 | mtab->imt6_active[i] = *mask; |
9905 | break; |
9906 | } |
9907 | } |
9908 | mtab->imt6_max++; |
9909 | } |
9910 | |
9911 | |
9912 | /* ------------------------------------------------------------------------ */ |
9913 | /* Function: ipf_inet6_mask_del */ |
9914 | /* Returns: Nil */ |
9915 | /* Parameters: bits(I) - number of bits set in mask */ |
9916 | /* mask(I) - pointer to mask to remove */ |
9917 | /* mtab(I) - pointer to mask hash table structure */ |
9918 | /* */ |
9919 | /* Remove the 128bit bitmask represented by "bits" from the collection of */ |
9920 | /* netmasks stored inside of mtab. */ |
9921 | /* ------------------------------------------------------------------------ */ |
9922 | void |
9923 | ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) |
9924 | { |
9925 | i6addr_t zero; |
9926 | int i, j; |
9927 | |
9928 | mtab->imt6_masks[bits]--; |
9929 | if (mtab->imt6_masks[bits] > 0) |
9930 | return; |
9931 | |
9932 | if (bits == 0) |
9933 | mask = &zero; |
9934 | zero.i6[0] = 0; |
9935 | zero.i6[1] = 0; |
9936 | zero.i6[2] = 0; |
9937 | zero.i6[3] = 0; |
9938 | |
9939 | for (i = 0; i < 129; i++) { |
9940 | if (IP6_EQ(&mtab->imt6_active[i], mask)) { |
9941 | for (j = i + 1; j < 129; j++) { |
9942 | mtab->imt6_active[j - 1] = mtab->imt6_active[j]; |
9943 | if (IP6_EQ(&mtab->imt6_active[j - 1], &zero)) |
9944 | break; |
9945 | } |
9946 | break; |
9947 | } |
9948 | } |
9949 | mtab->imt6_max--; |
9950 | ASSERT(mtab->imt6_max >= 0); |
9951 | } |
9952 | #endif |
9953 | |