1
2 /*
3 * Copyright (C) 2012 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 *
7 * Copyright 2008 Sun Microsystems.
8 *
9 * $Id$
10 *
11 */
12 #if defined(KERNEL) || defined(_KERNEL)
13 # undef KERNEL
14 # undef _KERNEL
15 # define KERNEL 1
16 # define _KERNEL 1
17 #endif
18 #include <sys/errno.h>
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/time.h>
22 #if defined(_KERNEL) && defined(__FreeBSD__)
23 # if !defined(IPFILTER_LKM)
24 # include "opt_inet6.h"
25 # endif
26 # include <sys/filio.h>
27 #else
28 # include <sys/ioctl.h>
29 #endif
30 #if defined(__SVR4) || defined(sun) /* SOLARIS */
31 # include <sys/filio.h>
32 #endif
33 # include <sys/fcntl.h>
34 #if defined(_KERNEL)
35 # include <sys/systm.h>
36 # include <sys/file.h>
37 #else
38 # include <stdio.h>
39 # include <string.h>
40 # include <stdlib.h>
41 # include <stddef.h>
42 # include <sys/file.h>
43 # define _KERNEL
44 # include <sys/uio.h>
45 # undef _KERNEL
46 #endif
47 #if !defined(__SVR4)
48 # include <sys/mbuf.h>
49 #else
50 # include <sys/byteorder.h>
51 # if (SOLARIS2 < 5) && defined(sun)
52 # include <sys/dditypes.h>
53 # endif
54 #endif
55 # include <sys/protosw.h>
56 #include <sys/socket.h>
57 #include <net/if.h>
58 #ifdef sun
59 # include <net/af.h>
60 #endif
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #include <netinet/tcp.h>
65 # include <netinet/udp.h>
66 # include <netinet/ip_icmp.h>
67 #include "netinet/ip_compat.h"
68 #ifdef USE_INET6
69 # include <netinet/icmp6.h>
70 # if !SOLARIS && defined(_KERNEL)
71 # include <netinet6/in6_var.h>
72 # endif
73 #endif
74 #include "netinet/ip_fil.h"
75 #include "netinet/ip_nat.h"
76 #include "netinet/ip_frag.h"
77 #include "netinet/ip_state.h"
78 #include "netinet/ip_proxy.h"
79 #include "netinet/ip_auth.h"
80 #ifdef IPFILTER_SCAN
81 # include "netinet/ip_scan.h"
82 #endif
83 #include "netinet/ip_sync.h"
84 #include "netinet/ip_lookup.h"
85 #include "netinet/ip_pool.h"
86 #include "netinet/ip_htable.h"
87 #ifdef IPFILTER_COMPILED
88 # include "netinet/ip_rules.h"
89 #endif
90 #if defined(IPFILTER_BPF) && defined(_KERNEL)
91 # include <net/bpf.h>
92 #endif
93 #if defined(__FreeBSD__)
94 # include <sys/malloc.h>
95 #endif
96 #include "netinet/ipl.h"
97
98 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
99 # include <sys/callout.h>
100 extern struct callout ipf_slowtimer_ch;
101 #endif
102 /* END OF INCLUDES */
103
104
105 #ifndef _KERNEL
106 # include "ipf.h"
107 # include "ipt.h"
108 extern int opts;
109 extern int blockreason;
110 #endif /* _KERNEL */
111
112 #define FASTROUTE_RECURSION
113
114 #define LBUMP(x) softc->x++
115 #define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0)
116
117 static inline int ipf_check_ipf(fr_info_t *, frentry_t *, int);
118 static u_32_t ipf_checkcipso(fr_info_t *, u_char *, int);
119 static u_32_t ipf_checkripso(u_char *);
120 static u_32_t ipf_decaps(fr_info_t *, u_32_t, int);
121 #ifdef IPFILTER_LOG
122 static frentry_t *ipf_dolog(fr_info_t *, u_32_t *);
123 #endif
124 static int ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **);
125 static int ipf_flush_groups(ipf_main_softc_t *, frgroup_t **,
126 int);
127 static ipfunc_t ipf_findfunc(ipfunc_t);
128 static void *ipf_findlookup(ipf_main_softc_t *, int, frentry_t *,
129 i6addr_t *, i6addr_t *);
130 static frentry_t *ipf_firewall(fr_info_t *, u_32_t *);
131 static int ipf_fr_matcharray(fr_info_t *, int *);
132 static int ipf_frruleiter(ipf_main_softc_t *, void *, int,
133 void *);
134 static void ipf_funcfini(ipf_main_softc_t *, frentry_t *);
135 static int ipf_funcinit(ipf_main_softc_t *, frentry_t *);
136 static int ipf_geniter(ipf_main_softc_t *, ipftoken_t *,
137 ipfgeniter_t *);
138 static void ipf_getstat(ipf_main_softc_t *,
139 struct friostat *, int);
140 static int ipf_group_flush(ipf_main_softc_t *, frgroup_t *);
141 static void ipf_group_free(frgroup_t *);
142 static int ipf_grpmapfini(struct ipf_main_softc_s *,
143 frentry_t *);
144 static int ipf_grpmapinit(struct ipf_main_softc_s *,
145 frentry_t *);
146 static frentry_t *ipf_nextrule(ipf_main_softc_t *, int, int,
147 frentry_t *, int);
148 static int ipf_portcheck(frpcmp_t *, u_32_t);
149 static inline int ipf_pr_ah(fr_info_t *);
150 static inline void ipf_pr_esp(fr_info_t *);
151 static inline void ipf_pr_gre(fr_info_t *);
152 static inline void ipf_pr_udp(fr_info_t *);
153 static inline void ipf_pr_tcp(fr_info_t *);
154 static inline void ipf_pr_icmp(fr_info_t *);
155 static inline void ipf_pr_ipv4hdr(fr_info_t *);
156 static inline void ipf_pr_short(fr_info_t *, int);
157 static inline int ipf_pr_tcpcommon(fr_info_t *);
158 static inline int ipf_pr_udpcommon(fr_info_t *);
159 static void ipf_rule_delete(ipf_main_softc_t *, frentry_t *f,
160 int, int);
161 static void ipf_rule_expire_insert(ipf_main_softc_t *,
162 frentry_t *, int);
163 static int ipf_synclist(ipf_main_softc_t *, frentry_t *,
164 void *);
165 static void ipf_token_flush(ipf_main_softc_t *);
166 static void ipf_token_unlink(ipf_main_softc_t *,
167 ipftoken_t *);
168 static ipftuneable_t *ipf_tune_findbyname(ipftuneable_t *,
169 const char *);
170 static ipftuneable_t *ipf_tune_findbycookie(ipftuneable_t **, void *,
171 void **);
172 static int ipf_updateipid(fr_info_t *);
173 static int ipf_settimeout(struct ipf_main_softc_s *,
174 struct ipftuneable *,
175 ipftuneval_t *);
176 #if !defined(_KERNEL) || SOLARIS
177 static int ppsratecheck(struct timeval *, int *, int);
178 #endif
179
180
181 /*
182 * bit values for identifying presence of individual IP options
183 * All of these tables should be ordered by increasing key value on the left
184 * hand side to allow for binary searching of the array and include a trailer
185 * with a 0 for the bitmask for linear searches to easily find the end with.
186 */
187 static const struct optlist ipopts[] = {
188 { IPOPT_NOP, 0x000001 },
189 { IPOPT_RR, 0x000002 },
190 { IPOPT_ZSU, 0x000004 },
191 { IPOPT_MTUP, 0x000008 },
192 { IPOPT_MTUR, 0x000010 },
193 { IPOPT_ENCODE, 0x000020 },
194 { IPOPT_TS, 0x000040 },
195 { IPOPT_TR, 0x000080 },
196 { IPOPT_SECURITY, 0x000100 },
197 { IPOPT_LSRR, 0x000200 },
198 { IPOPT_E_SEC, 0x000400 },
199 { IPOPT_CIPSO, 0x000800 },
200 { IPOPT_SATID, 0x001000 },
201 { IPOPT_SSRR, 0x002000 },
202 { IPOPT_ADDEXT, 0x004000 },
203 { IPOPT_VISA, 0x008000 },
204 { IPOPT_IMITD, 0x010000 },
205 { IPOPT_EIP, 0x020000 },
206 { IPOPT_FINN, 0x040000 },
207 { 0, 0x000000 }
208 };
209
210 #ifdef USE_INET6
211 static const struct optlist ip6exthdr[] = {
212 { IPPROTO_HOPOPTS, 0x000001 },
213 { IPPROTO_IPV6, 0x000002 },
214 { IPPROTO_ROUTING, 0x000004 },
215 { IPPROTO_FRAGMENT, 0x000008 },
216 { IPPROTO_ESP, 0x000010 },
217 { IPPROTO_AH, 0x000020 },
218 { IPPROTO_NONE, 0x000040 },
219 { IPPROTO_DSTOPTS, 0x000080 },
220 { IPPROTO_MOBILITY, 0x000100 },
221 { 0, 0 }
222 };
223 #endif
224
225 /*
226 * bit values for identifying presence of individual IP security options
227 */
228 static const struct optlist secopt[] = {
229 { IPSO_CLASS_RES4, 0x01 },
230 { IPSO_CLASS_TOPS, 0x02 },
231 { IPSO_CLASS_SECR, 0x04 },
232 { IPSO_CLASS_RES3, 0x08 },
233 { IPSO_CLASS_CONF, 0x10 },
234 { IPSO_CLASS_UNCL, 0x20 },
235 { IPSO_CLASS_RES2, 0x40 },
236 { IPSO_CLASS_RES1, 0x80 }
237 };
238
239 /*
240 * Internal errors set by ipf_check_names_string().
241 */
242 static const int interr_tbl[3] = { 152, 156, 153 };
243
244 char ipfilter_version[] = IPL_VERSION;
245
246 int ipf_features = 0
247 #ifdef IPFILTER_LKM
248 | IPF_FEAT_LKM
249 #endif
250 #ifdef IPFILTER_LOG
251 | IPF_FEAT_LOG
252 #endif
253 | IPF_FEAT_LOOKUP
254 #ifdef IPFILTER_BPF
255 | IPF_FEAT_BPF
256 #endif
257 #ifdef IPFILTER_COMPILED
258 | IPF_FEAT_COMPILED
259 #endif
260 #ifdef IPFILTER_CKSUM
261 | IPF_FEAT_CKSUM
262 #endif
263 | IPF_FEAT_SYNC
264 #ifdef IPFILTER_SCAN
265 | IPF_FEAT_SCAN
266 #endif
267 #ifdef USE_INET6
268 | IPF_FEAT_IPV6
269 #endif
270 ;
271
272
273 /*
274 * Table of functions available for use with call rules.
275 */
276 static ipfunc_resolve_t ipf_availfuncs[] = {
277 { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini },
278 { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini },
279 { "", NULL, NULL, NULL }
280 };
281
282 static ipftuneable_t ipf_main_tuneables[] = {
283 { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) },
284 "ipf_flags", 0, 0xffffffff,
285 stsizeof(ipf_main_softc_t, ipf_flags),
286 0, NULL, NULL },
287 { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) },
288 "active", 0, 0,
289 stsizeof(ipf_main_softc_t, ipf_active),
290 IPFT_RDONLY, NULL, NULL },
291 { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) },
292 "control_forwarding", 0, 1,
293 stsizeof(ipf_main_softc_t, ipf_control_forwarding),
294 0, NULL, NULL },
295 { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) },
296 "update_ipid", 0, 1,
297 stsizeof(ipf_main_softc_t, ipf_update_ipid),
298 0, NULL, NULL },
299 { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) },
300 "chksrc", 0, 1,
301 stsizeof(ipf_main_softc_t, ipf_chksrc),
302 0, NULL, NULL },
303 { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) },
304 "min_ttl", 0, 1,
305 stsizeof(ipf_main_softc_t, ipf_minttl),
306 0, NULL, NULL },
307 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) },
308 "icmp_minfragmtu", 0, 1,
309 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu),
310 0, NULL, NULL },
311 { { (void *)offsetof(ipf_main_softc_t, ipf_pass) },
312 "default_pass", 0, 0xffffffff,
313 stsizeof(ipf_main_softc_t, ipf_pass),
314 0, NULL, NULL },
315 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) },
316 "tcp_idle_timeout", 1, 0x7fffffff,
317 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout),
318 0, NULL, ipf_settimeout },
319 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) },
320 "tcp_close_wait", 1, 0x7fffffff,
321 stsizeof(ipf_main_softc_t, ipf_tcpclosewait),
322 0, NULL, ipf_settimeout },
323 { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) },
324 "tcp_last_ack", 1, 0x7fffffff,
325 stsizeof(ipf_main_softc_t, ipf_tcplastack),
326 0, NULL, ipf_settimeout },
327 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) },
328 "tcp_timeout", 1, 0x7fffffff,
329 stsizeof(ipf_main_softc_t, ipf_tcptimeout),
330 0, NULL, ipf_settimeout },
331 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) },
332 "tcp_syn_sent", 1, 0x7fffffff,
333 stsizeof(ipf_main_softc_t, ipf_tcpsynsent),
334 0, NULL, ipf_settimeout },
335 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) },
336 "tcp_syn_received", 1, 0x7fffffff,
337 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv),
338 0, NULL, ipf_settimeout },
339 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) },
340 "tcp_closed", 1, 0x7fffffff,
341 stsizeof(ipf_main_softc_t, ipf_tcpclosed),
342 0, NULL, ipf_settimeout },
343 { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) },
344 "tcp_half_closed", 1, 0x7fffffff,
345 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed),
346 0, NULL, ipf_settimeout },
347 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) },
348 "tcp_time_wait", 1, 0x7fffffff,
349 stsizeof(ipf_main_softc_t, ipf_tcptimewait),
350 0, NULL, ipf_settimeout },
351 { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) },
352 "udp_timeout", 1, 0x7fffffff,
353 stsizeof(ipf_main_softc_t, ipf_udptimeout),
354 0, NULL, ipf_settimeout },
355 { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) },
356 "udp_ack_timeout", 1, 0x7fffffff,
357 stsizeof(ipf_main_softc_t, ipf_udpacktimeout),
358 0, NULL, ipf_settimeout },
359 { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) },
360 "icmp_timeout", 1, 0x7fffffff,
361 stsizeof(ipf_main_softc_t, ipf_icmptimeout),
362 0, NULL, ipf_settimeout },
363 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) },
364 "icmp_ack_timeout", 1, 0x7fffffff,
365 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout),
366 0, NULL, ipf_settimeout },
367 { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) },
368 "ip_timeout", 1, 0x7fffffff,
369 stsizeof(ipf_main_softc_t, ipf_iptimeout),
370 0, NULL, ipf_settimeout },
371 { { (void *)offsetof(ipf_main_softc_t, ipf_max_namelen) },
372 "max_namelen", 0, 0x7fffffff,
373 stsizeof(ipf_main_softc_t, ipf_max_namelen),
374 0, NULL, NULL },
375 #if defined(INSTANCES) && defined(_KERNEL)
376 { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) },
377 "intercept_loopback", 0, 1,
378 stsizeof(ipf_main_softc_t, ipf_get_loopback),
379 0, NULL, ipf_set_loopback },
380 #endif
381 { { 0 },
382 NULL, 0, 0,
383 0,
384 0, NULL, NULL }
385 };
386
387
388 /*
389 * The next section of code is a collection of small routines that set
390 * fields in the fr_info_t structure passed based on properties of the
391 * current packet. There are different routines for the same protocol
392 * for each of IPv4 and IPv6. Adding a new protocol, for which there
393 * will "special" inspection for setup, is now more easily done by adding
394 * a new routine and expanding the ipf_pr_ipinit*() function rather than by
395 * adding more code to a growing switch statement.
396 */
397 #ifdef USE_INET6
398 static inline int ipf_pr_ah6(fr_info_t *);
399 static inline void ipf_pr_esp6(fr_info_t *);
400 static inline void ipf_pr_gre6(fr_info_t *);
401 static inline void ipf_pr_udp6(fr_info_t *);
402 static inline void ipf_pr_tcp6(fr_info_t *);
403 static inline void ipf_pr_icmp6(fr_info_t *);
404 static inline void ipf_pr_ipv6hdr(fr_info_t *);
405 static inline void ipf_pr_short6(fr_info_t *, int);
406 static inline int ipf_pr_hopopts6(fr_info_t *);
407 static inline int ipf_pr_mobility6(fr_info_t *);
408 static inline int ipf_pr_routing6(fr_info_t *);
409 static inline int ipf_pr_dstopts6(fr_info_t *);
410 static inline int ipf_pr_fragment6(fr_info_t *);
411 static inline struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int);
412
413
414 /* ------------------------------------------------------------------------ */
415 /* Function: ipf_pr_short6 */
416 /* Returns: void */
417 /* Parameters: fin(I) - pointer to packet information */
418 /* xmin(I) - minimum header size */
419 /* */
420 /* IPv6 Only */
421 /* This is function enforces the 'is a packet too short to be legit' rule */
422 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */
423 /* for ipf_pr_short() for more details. */
424 /* ------------------------------------------------------------------------ */
425 static inline void
ipf_pr_short6(fr_info_t * fin,int xmin)426 ipf_pr_short6(fr_info_t *fin, int xmin)
427 {
428
429 if (fin->fin_dlen < xmin)
430 fin->fin_flx |= FI_SHORT;
431 }
432
433
434 /* ------------------------------------------------------------------------ */
435 /* Function: ipf_pr_ipv6hdr */
436 /* Returns: void */
437 /* Parameters: fin(I) - pointer to packet information */
438 /* */
439 /* IPv6 Only */
440 /* Copy values from the IPv6 header into the fr_info_t struct and call the */
441 /* per-protocol analyzer if it exists. In validating the packet, a protocol*/
442 /* analyzer may pullup or free the packet itself so we need to be vigiliant */
443 /* of that possibility arising. */
444 /* ------------------------------------------------------------------------ */
445 static inline void
ipf_pr_ipv6hdr(fr_info_t * fin)446 ipf_pr_ipv6hdr(fr_info_t *fin)
447 {
448 ip6_t *ip6 = (ip6_t *)fin->fin_ip;
449 int p, go = 1, i;
450 fr_ip_t *fi = &fin->fin_fi;
451
452 fin->fin_off = 0;
453
454 fi->fi_tos = 0;
455 fi->fi_optmsk = 0;
456 fi->fi_secmsk = 0;
457 fi->fi_auth = 0;
458
459 p = ip6->ip6_nxt;
460 fin->fin_crc = p;
461 fi->fi_ttl = ip6->ip6_hlim;
462 fi->fi_src.in6 = ip6->ip6_src;
463 fin->fin_crc += fi->fi_src.i6[0];
464 fin->fin_crc += fi->fi_src.i6[1];
465 fin->fin_crc += fi->fi_src.i6[2];
466 fin->fin_crc += fi->fi_src.i6[3];
467 fi->fi_dst.in6 = ip6->ip6_dst;
468 fin->fin_crc += fi->fi_dst.i6[0];
469 fin->fin_crc += fi->fi_dst.i6[1];
470 fin->fin_crc += fi->fi_dst.i6[2];
471 fin->fin_crc += fi->fi_dst.i6[3];
472 fin->fin_id = 0;
473 if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
474 fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
475
476 while (go && !(fin->fin_flx & FI_SHORT)) {
477 switch (p)
478 {
479 case IPPROTO_UDP :
480 ipf_pr_udp6(fin);
481 go = 0;
482 break;
483
484 case IPPROTO_TCP :
485 ipf_pr_tcp6(fin);
486 go = 0;
487 break;
488
489 case IPPROTO_ICMPV6 :
490 ipf_pr_icmp6(fin);
491 go = 0;
492 break;
493
494 case IPPROTO_GRE :
495 ipf_pr_gre6(fin);
496 go = 0;
497 break;
498
499 case IPPROTO_HOPOPTS :
500 p = ipf_pr_hopopts6(fin);
501 break;
502
503 case IPPROTO_MOBILITY :
504 p = ipf_pr_mobility6(fin);
505 break;
506
507 case IPPROTO_DSTOPTS :
508 p = ipf_pr_dstopts6(fin);
509 break;
510
511 case IPPROTO_ROUTING :
512 p = ipf_pr_routing6(fin);
513 break;
514
515 case IPPROTO_AH :
516 p = ipf_pr_ah6(fin);
517 break;
518
519 case IPPROTO_ESP :
520 ipf_pr_esp6(fin);
521 go = 0;
522 break;
523
524 case IPPROTO_IPV6 :
525 for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
526 if (ip6exthdr[i].ol_val == p) {
527 fin->fin_flx |= ip6exthdr[i].ol_bit;
528 break;
529 }
530 go = 0;
531 break;
532
533 case IPPROTO_NONE :
534 go = 0;
535 break;
536
537 case IPPROTO_FRAGMENT :
538 p = ipf_pr_fragment6(fin);
539 /*
540 * Given that the only fragments we want to let through
541 * (where fin_off != 0) are those where the non-first
542 * fragments only have data, we can safely stop looking
543 * at headers if this is a non-leading fragment.
544 */
545 if (fin->fin_off != 0)
546 go = 0;
547 break;
548
549 default :
550 go = 0;
551 break;
552 }
553
554 /*
555 * It is important to note that at this point, for the
556 * extension headers (go != 0), the entire header may not have
557 * been pulled up when the code gets to this point. This is
558 * only done for "go != 0" because the other header handlers
559 * will all pullup their complete header. The other indicator
560 * of an incomplete packet is that this was just an extension
561 * header.
562 */
563 if ((go != 0) && (p != IPPROTO_NONE) &&
564 (ipf_pr_pullup(fin, 0) == -1)) {
565 p = IPPROTO_NONE;
566 break;
567 }
568 }
569
570 /*
571 * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup
572 * and destroy whatever packet was here. The caller of this function
573 * expects us to return if there is a problem with ipf_pullup.
574 */
575 if (fin->fin_m == NULL) {
576 ipf_main_softc_t *softc = fin->fin_main_soft;
577
578 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad);
579 return;
580 }
581
582 fi->fi_p = p;
583
584 /*
585 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6().
586 * "go != 0" implies the above loop hasn't arrived at a layer 4 header.
587 */
588 if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) {
589 ipf_main_softc_t *softc = fin->fin_main_soft;
590
591 fin->fin_flx |= FI_BAD;
592 DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go);
593 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag);
594 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad);
595 }
596 }
597
598
599 /* ------------------------------------------------------------------------ */
600 /* Function: ipf_pr_ipv6exthdr */
601 /* Returns: struct ip6_ext * - pointer to the start of the next header */
602 /* or NULL if there is a prolblem. */
603 /* Parameters: fin(I) - pointer to packet information */
604 /* multiple(I) - flag indicating yes/no if multiple occurances */
605 /* of this extension header are allowed. */
606 /* proto(I) - protocol number for this extension header */
607 /* */
608 /* IPv6 Only */
609 /* This function embodies a number of common checks that all IPv6 extension */
610 /* headers must be subjected to. For example, making sure the packet is */
611 /* big enough for it to be in, checking if it is repeated and setting a */
612 /* flag to indicate its presence. */
613 /* ------------------------------------------------------------------------ */
614 static inline struct ip6_ext *
ipf_pr_ipv6exthdr(fr_info_t * fin,int multiple,int proto)615 ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto)
616 {
617 ipf_main_softc_t *softc = fin->fin_main_soft;
618 struct ip6_ext *hdr;
619 u_short shift;
620 int i;
621
622 fin->fin_flx |= FI_V6EXTHDR;
623
624 /* 8 is default length of extension hdr */
625 if ((fin->fin_dlen - 8) < 0) {
626 fin->fin_flx |= FI_SHORT;
627 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short);
628 return (NULL);
629 }
630
631 if (ipf_pr_pullup(fin, 8) == -1) {
632 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup);
633 return (NULL);
634 }
635
636 hdr = fin->fin_dp;
637 switch (proto)
638 {
639 case IPPROTO_FRAGMENT :
640 shift = 8;
641 break;
642 default :
643 shift = 8 + (hdr->ip6e_len << 3);
644 break;
645 }
646
647 if (shift > fin->fin_dlen) { /* Nasty extension header length? */
648 fin->fin_flx |= FI_BAD;
649 DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen);
650 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen);
651 return (NULL);
652 }
653
654 fin->fin_dp = (char *)fin->fin_dp + shift;
655 fin->fin_dlen -= shift;
656
657 /*
658 * If we have seen a fragment header, do not set any flags to indicate
659 * the presence of this extension header as it has no impact on the
660 * end result until after it has been defragmented.
661 */
662 if (fin->fin_flx & FI_FRAG)
663 return (hdr);
664
665 for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
666 if (ip6exthdr[i].ol_val == proto) {
667 /*
668 * Most IPv6 extension headers are only allowed once.
669 */
670 if ((multiple == 0) &&
671 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) {
672 fin->fin_flx |= FI_BAD;
673 DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit));
674 } else
675 fin->fin_optmsk |= ip6exthdr[i].ol_bit;
676 break;
677 }
678
679 return (hdr);
680 }
681
682
683 /* ------------------------------------------------------------------------ */
684 /* Function: ipf_pr_hopopts6 */
685 /* Returns: int - value of the next header or IPPROTO_NONE if error */
686 /* Parameters: fin(I) - pointer to packet information */
687 /* */
688 /* IPv6 Only */
689 /* This is function checks pending hop by hop options extension header */
690 /* ------------------------------------------------------------------------ */
691 static inline int
ipf_pr_hopopts6(fr_info_t * fin)692 ipf_pr_hopopts6(fr_info_t *fin)
693 {
694 struct ip6_ext *hdr;
695
696 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
697 if (hdr == NULL)
698 return (IPPROTO_NONE);
699 return (hdr->ip6e_nxt);
700 }
701
702
703 /* ------------------------------------------------------------------------ */
704 /* Function: ipf_pr_mobility6 */
705 /* Returns: int - value of the next header or IPPROTO_NONE if error */
706 /* Parameters: fin(I) - pointer to packet information */
707 /* */
708 /* IPv6 Only */
709 /* This is function checks the IPv6 mobility extension header */
710 /* ------------------------------------------------------------------------ */
711 static inline int
ipf_pr_mobility6(fr_info_t * fin)712 ipf_pr_mobility6(fr_info_t *fin)
713 {
714 struct ip6_ext *hdr;
715
716 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
717 if (hdr == NULL)
718 return (IPPROTO_NONE);
719 return (hdr->ip6e_nxt);
720 }
721
722
723 /* ------------------------------------------------------------------------ */
724 /* Function: ipf_pr_routing6 */
725 /* Returns: int - value of the next header or IPPROTO_NONE if error */
726 /* Parameters: fin(I) - pointer to packet information */
727 /* */
728 /* IPv6 Only */
729 /* This is function checks pending routing extension header */
730 /* ------------------------------------------------------------------------ */
731 static inline int
ipf_pr_routing6(fr_info_t * fin)732 ipf_pr_routing6(fr_info_t *fin)
733 {
734 struct ip6_routing *hdr;
735
736 hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING);
737 if (hdr == NULL)
738 return (IPPROTO_NONE);
739
740 switch (hdr->ip6r_type)
741 {
742 case 0 :
743 /*
744 * Nasty extension header length?
745 */
746 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) ||
747 (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) {
748 ipf_main_softc_t *softc = fin->fin_main_soft;
749
750 fin->fin_flx |= FI_BAD;
751 DT1(ipf_fi_bad_routing6, fr_info_t *, fin);
752 LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad);
753 return (IPPROTO_NONE);
754 }
755 break;
756
757 default :
758 break;
759 }
760
761 return (hdr->ip6r_nxt);
762 }
763
764
765 /* ------------------------------------------------------------------------ */
766 /* Function: ipf_pr_fragment6 */
767 /* Returns: int - value of the next header or IPPROTO_NONE if error */
768 /* Parameters: fin(I) - pointer to packet information */
769 /* */
770 /* IPv6 Only */
771 /* Examine the IPv6 fragment header and extract fragment offset information.*/
772 /* */
773 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */
774 /* so than in IPv4. There are 5 cases of fragments with IPv6 that all */
775 /* packets with a fragment header can fit into. They are as follows: */
776 /* */
777 /* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */
778 /* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */
779 /* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */
780 /* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */
781 /* 5. [IPV6][0-n EH][FH][data] */
782 /* */
783 /* IPV6 = IPv6 header, FH = Fragment Header, */
784 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */
785 /* */
786 /* Packets that match 1, 2, 3 will be dropped as the only reasonable */
787 /* scenario in which they happen is in extreme circumstances that are most */
788 /* likely to be an indication of an attack rather than normal traffic. */
789 /* A type 3 packet may be sent by an attacked after a type 4 packet. There */
790 /* are two rules that can be used to guard against type 3 packets: L4 */
791 /* headers must always be in a packet that has the offset field set to 0 */
792 /* and no packet is allowed to overlay that where offset = 0. */
793 /* ------------------------------------------------------------------------ */
794 static inline int
ipf_pr_fragment6(fr_info_t * fin)795 ipf_pr_fragment6(fr_info_t *fin)
796 {
797 ipf_main_softc_t *softc = fin->fin_main_soft;
798 struct ip6_frag *frag;
799
800 fin->fin_flx |= FI_FRAG;
801
802 frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT);
803 if (frag == NULL) {
804 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad);
805 return (IPPROTO_NONE);
806 }
807
808 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
809 /*
810 * Any fragment that isn't the last fragment must have its
811 * length as a multiple of 8.
812 */
813 if ((fin->fin_plen & 7) != 0) {
814 fin->fin_flx |= FI_BAD;
815 DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7));
816 }
817 }
818
819 fin->fin_fraghdr = frag;
820 fin->fin_id = frag->ip6f_ident;
821 fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
822 if (fin->fin_off != 0)
823 fin->fin_flx |= FI_FRAGBODY;
824
825 /*
826 * Jumbograms aren't handled, so the max. length is 64k
827 */
828 if ((fin->fin_off << 3) + fin->fin_dlen > 65535) {
829 fin->fin_flx |= FI_BAD;
830 DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen));
831 }
832
833 /*
834 * We don't know where the transport layer header (or whatever is next
835 * is), as it could be behind destination options (amongst others) so
836 * return the fragment header as the type of packet this is. Note that
837 * this effectively disables the fragment cache for > 1 protocol at a
838 * time.
839 */
840 return (frag->ip6f_nxt);
841 }
842
843
844 /* ------------------------------------------------------------------------ */
845 /* Function: ipf_pr_dstopts6 */
846 /* Returns: int - value of the next header or IPPROTO_NONE if error */
847 /* Parameters: fin(I) - pointer to packet information */
848 /* */
849 /* IPv6 Only */
850 /* This is function checks pending destination options extension header */
851 /* ------------------------------------------------------------------------ */
852 static inline int
ipf_pr_dstopts6(fr_info_t * fin)853 ipf_pr_dstopts6(fr_info_t *fin)
854 {
855 ipf_main_softc_t *softc = fin->fin_main_soft;
856 struct ip6_ext *hdr;
857
858 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS);
859 if (hdr == NULL) {
860 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad);
861 return (IPPROTO_NONE);
862 }
863 return (hdr->ip6e_nxt);
864 }
865
866
867 /* ------------------------------------------------------------------------ */
868 /* Function: ipf_pr_icmp6 */
869 /* Returns: void */
870 /* Parameters: fin(I) - pointer to packet information */
871 /* */
872 /* IPv6 Only */
873 /* This routine is mainly concerned with determining the minimum valid size */
874 /* for an ICMPv6 packet. */
875 /* ------------------------------------------------------------------------ */
876 static inline void
ipf_pr_icmp6(fr_info_t * fin)877 ipf_pr_icmp6(fr_info_t *fin)
878 {
879 int minicmpsz = sizeof(struct icmp6_hdr);
880 struct icmp6_hdr *icmp6;
881
882 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) {
883 ipf_main_softc_t *softc = fin->fin_main_soft;
884
885 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup);
886 return;
887 }
888
889 if (fin->fin_dlen > 1) {
890 ip6_t *ip6;
891
892 icmp6 = fin->fin_dp;
893
894 fin->fin_data[0] = *(u_short *)icmp6;
895
896 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
897 fin->fin_flx |= FI_ICMPQUERY;
898
899 switch (icmp6->icmp6_type)
900 {
901 case ICMP6_ECHO_REPLY :
902 case ICMP6_ECHO_REQUEST :
903 if (fin->fin_dlen >= 6)
904 fin->fin_data[1] = icmp6->icmp6_id;
905 minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
906 break;
907
908 case ICMP6_DST_UNREACH :
909 case ICMP6_PACKET_TOO_BIG :
910 case ICMP6_TIME_EXCEEDED :
911 case ICMP6_PARAM_PROB :
912 fin->fin_flx |= FI_ICMPERR;
913 minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
914 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
915 break;
916
917 if (M_LEN(fin->fin_m) < fin->fin_plen) {
918 if (ipf_coalesce(fin) != 1)
919 return;
920 }
921
922 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
923 return;
924
925 /*
926 * If the destination of this packet doesn't match the
927 * source of the original packet then this packet is
928 * not correct.
929 */
930 icmp6 = fin->fin_dp;
931 ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN);
932 if (IP6_NEQ(&fin->fin_fi.fi_dst,
933 (i6addr_t *)&ip6->ip6_src)) {
934 fin->fin_flx |= FI_BAD;
935 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin);
936 }
937 break;
938 default :
939 break;
940 }
941 }
942
943 ipf_pr_short6(fin, minicmpsz);
944 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) {
945 u_char p = fin->fin_p;
946
947 fin->fin_p = IPPROTO_ICMPV6;
948 ipf_checkv6sum(fin);
949 fin->fin_p = p;
950 }
951 }
952
953
954 /* ------------------------------------------------------------------------ */
955 /* Function: ipf_pr_udp6 */
956 /* Returns: void */
957 /* Parameters: fin(I) - pointer to packet information */
958 /* */
959 /* IPv6 Only */
960 /* Analyse the packet for IPv6/UDP properties. */
961 /* Is not expected to be called for fragmented packets. */
962 /* ------------------------------------------------------------------------ */
963 static inline void
ipf_pr_udp6(fr_info_t * fin)964 ipf_pr_udp6(fr_info_t *fin)
965 {
966
967 if (ipf_pr_udpcommon(fin) == 0) {
968 u_char p = fin->fin_p;
969
970 fin->fin_p = IPPROTO_UDP;
971 ipf_checkv6sum(fin);
972 fin->fin_p = p;
973 }
974 }
975
976
977 /* ------------------------------------------------------------------------ */
978 /* Function: ipf_pr_tcp6 */
979 /* Returns: void */
980 /* Parameters: fin(I) - pointer to packet information */
981 /* */
982 /* IPv6 Only */
983 /* Analyse the packet for IPv6/TCP properties. */
984 /* Is not expected to be called for fragmented packets. */
985 /* ------------------------------------------------------------------------ */
986 static inline void
ipf_pr_tcp6(fr_info_t * fin)987 ipf_pr_tcp6(fr_info_t *fin)
988 {
989
990 if (ipf_pr_tcpcommon(fin) == 0) {
991 u_char p = fin->fin_p;
992
993 fin->fin_p = IPPROTO_TCP;
994 ipf_checkv6sum(fin);
995 fin->fin_p = p;
996 }
997 }
998
999
1000 /* ------------------------------------------------------------------------ */
1001 /* Function: ipf_pr_esp6 */
1002 /* Returns: void */
1003 /* Parameters: fin(I) - pointer to packet information */
1004 /* */
1005 /* IPv6 Only */
1006 /* Analyse the packet for ESP properties. */
1007 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */
1008 /* even though the newer ESP packets must also have a sequence number that */
1009 /* is 32bits as well, it is not possible(?) to determine the version from a */
1010 /* simple packet header. */
1011 /* ------------------------------------------------------------------------ */
1012 static inline void
ipf_pr_esp6(fr_info_t * fin)1013 ipf_pr_esp6(fr_info_t *fin)
1014 {
1015
1016 if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) {
1017 ipf_main_softc_t *softc = fin->fin_main_soft;
1018
1019 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup);
1020 return;
1021 }
1022 }
1023
1024
1025 /* ------------------------------------------------------------------------ */
1026 /* Function: ipf_pr_ah6 */
1027 /* Returns: int - value of the next header or IPPROTO_NONE if error */
1028 /* Parameters: fin(I) - pointer to packet information */
1029 /* */
1030 /* IPv6 Only */
1031 /* Analyse the packet for AH properties. */
1032 /* The minimum length is taken to be the combination of all fields in the */
1033 /* header being present and no authentication data (null algorithm used.) */
1034 /* ------------------------------------------------------------------------ */
1035 static inline int
ipf_pr_ah6(fr_info_t * fin)1036 ipf_pr_ah6(fr_info_t *fin)
1037 {
1038 authhdr_t *ah;
1039
1040 fin->fin_flx |= FI_AH;
1041
1042 ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
1043 if (ah == NULL) {
1044 ipf_main_softc_t *softc = fin->fin_main_soft;
1045
1046 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad);
1047 return (IPPROTO_NONE);
1048 }
1049
1050 ipf_pr_short6(fin, sizeof(*ah));
1051
1052 /*
1053 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup
1054 * enough data to satisfy ah_next (the very first one.)
1055 */
1056 return (ah->ah_next);
1057 }
1058
1059
1060 /* ------------------------------------------------------------------------ */
1061 /* Function: ipf_pr_gre6 */
1062 /* Returns: void */
1063 /* Parameters: fin(I) - pointer to packet information */
1064 /* */
1065 /* Analyse the packet for GRE properties. */
1066 /* ------------------------------------------------------------------------ */
1067 static inline void
ipf_pr_gre6(fr_info_t * fin)1068 ipf_pr_gre6(fr_info_t *fin)
1069 {
1070 grehdr_t *gre;
1071
1072 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
1073 ipf_main_softc_t *softc = fin->fin_main_soft;
1074
1075 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup);
1076 return;
1077 }
1078
1079 gre = fin->fin_dp;
1080 if (GRE_REV(gre->gr_flags) == 1)
1081 fin->fin_data[0] = gre->gr_call;
1082 }
1083 #endif /* USE_INET6 */
1084
1085
1086 /* ------------------------------------------------------------------------ */
1087 /* Function: ipf_pr_pullup */
1088 /* Returns: int - 0 == pullup succeeded, -1 == failure */
1089 /* Parameters: fin(I) - pointer to packet information */
1090 /* plen(I) - length (excluding L3 header) to pullup */
1091 /* */
1092 /* Short inline function to cut down on code duplication to perform a call */
1093 /* to ipf_pullup to ensure there is the required amount of data, */
1094 /* consecutively in the packet buffer. */
1095 /* */
1096 /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */
1097 /* points to the first byte after the complete layer 3 header, which will */
1098 /* include all of the known extension headers for IPv6 or options for IPv4. */
1099 /* */
1100 /* Since fr_pullup() expects the total length of bytes to be pulled up, it */
1101 /* is necessary to add those we can already assume to be pulled up (fin_dp */
1102 /* - fin_ip) to what is passed through. */
1103 /* ------------------------------------------------------------------------ */
1104 int
ipf_pr_pullup(fr_info_t * fin,int plen)1105 ipf_pr_pullup(fr_info_t *fin, int plen)
1106 {
1107 ipf_main_softc_t *softc = fin->fin_main_soft;
1108
1109 if (fin->fin_m != NULL) {
1110 if (fin->fin_dp != NULL)
1111 plen += (char *)fin->fin_dp -
1112 ((char *)fin->fin_ip + fin->fin_hlen);
1113 plen += fin->fin_hlen;
1114 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
1115 #if defined(_KERNEL)
1116 if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
1117 DT1(ipf_pullup_fail, fr_info_t *, fin);
1118 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
1119 fin->fin_reason = FRB_PULLUP;
1120 fin->fin_flx |= FI_BAD;
1121 return (-1);
1122 }
1123 LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
1124 #else
1125 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
1126 /*
1127 * Fake ipf_pullup failing
1128 */
1129 fin->fin_reason = FRB_PULLUP;
1130 *fin->fin_mp = NULL;
1131 fin->fin_m = NULL;
1132 fin->fin_ip = NULL;
1133 fin->fin_flx |= FI_BAD;
1134 return (-1);
1135 #endif
1136 }
1137 }
1138 return (0);
1139 }
1140
1141
1142 /* ------------------------------------------------------------------------ */
1143 /* Function: ipf_pr_short */
1144 /* Returns: void */
1145 /* Parameters: fin(I) - pointer to packet information */
1146 /* xmin(I) - minimum header size */
1147 /* */
1148 /* Check if a packet is "short" as defined by xmin. The rule we are */
1149 /* applying here is that the packet must not be fragmented within the layer */
1150 /* 4 header. That is, it must not be a fragment that has its offset set to */
1151 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */
1152 /* entire layer 4 header must be present (min). */
1153 /* ------------------------------------------------------------------------ */
1154 static inline void
ipf_pr_short(fr_info_t * fin,int xmin)1155 ipf_pr_short(fr_info_t *fin, int xmin)
1156 {
1157
1158 if (fin->fin_off == 0) {
1159 if (fin->fin_dlen < xmin)
1160 fin->fin_flx |= FI_SHORT;
1161 } else if (fin->fin_off < xmin) {
1162 fin->fin_flx |= FI_SHORT;
1163 }
1164 }
1165
1166
1167 /* ------------------------------------------------------------------------ */
1168 /* Function: ipf_pr_icmp */
1169 /* Returns: void */
1170 /* Parameters: fin(I) - pointer to packet information */
1171 /* */
1172 /* IPv4 Only */
1173 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */
1174 /* except extrememly bad packets, both type and code will be present. */
1175 /* The expected minimum size of an ICMP packet is very much dependent on */
1176 /* the type of it. */
1177 /* */
1178 /* XXX - other ICMP sanity checks? */
1179 /* ------------------------------------------------------------------------ */
1180 static inline void
ipf_pr_icmp(fr_info_t * fin)1181 ipf_pr_icmp(fr_info_t *fin)
1182 {
1183 ipf_main_softc_t *softc = fin->fin_main_soft;
1184 int minicmpsz = sizeof(struct icmp);
1185 icmphdr_t *icmp;
1186 ip_t *oip;
1187
1188 ipf_pr_short(fin, ICMPERR_ICMPHLEN);
1189
1190 if (fin->fin_off != 0) {
1191 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag);
1192 return;
1193 }
1194
1195 if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) {
1196 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup);
1197 return;
1198 }
1199
1200 icmp = fin->fin_dp;
1201
1202 fin->fin_data[0] = *(u_short *)icmp;
1203 fin->fin_data[1] = icmp->icmp_id;
1204
1205 switch (icmp->icmp_type)
1206 {
1207 case ICMP_ECHOREPLY :
1208 case ICMP_ECHO :
1209 /* Router discovery messaes - RFC 1256 */
1210 case ICMP_ROUTERADVERT :
1211 case ICMP_ROUTERSOLICIT :
1212 fin->fin_flx |= FI_ICMPQUERY;
1213 minicmpsz = ICMP_MINLEN;
1214 break;
1215 /*
1216 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1217 * 3 * timestamp(3 * 4)
1218 */
1219 case ICMP_TSTAMP :
1220 case ICMP_TSTAMPREPLY :
1221 fin->fin_flx |= FI_ICMPQUERY;
1222 minicmpsz = 20;
1223 break;
1224 /*
1225 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1226 * mask(4)
1227 */
1228 case ICMP_IREQ :
1229 case ICMP_IREQREPLY :
1230 case ICMP_MASKREQ :
1231 case ICMP_MASKREPLY :
1232 fin->fin_flx |= FI_ICMPQUERY;
1233 minicmpsz = 12;
1234 break;
1235 /*
1236 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
1237 */
1238 case ICMP_UNREACH :
1239 #ifdef icmp_nextmtu
1240 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
1241 if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) {
1242 fin->fin_flx |= FI_BAD;
1243 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu);
1244 }
1245 }
1246 #endif
1247 /* FALLTHROUGH */
1248 case ICMP_SOURCEQUENCH :
1249 case ICMP_REDIRECT :
1250 case ICMP_TIMXCEED :
1251 case ICMP_PARAMPROB :
1252 fin->fin_flx |= FI_ICMPERR;
1253 if (ipf_coalesce(fin) != 1) {
1254 LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce);
1255 return;
1256 }
1257
1258 /*
1259 * ICMP error packets should not be generated for IP
1260 * packets that are a fragment that isn't the first
1261 * fragment.
1262 */
1263 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
1264 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) {
1265 fin->fin_flx |= FI_BAD;
1266 DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK));
1267 }
1268
1269 /*
1270 * If the destination of this packet doesn't match the
1271 * source of the original packet then this packet is
1272 * not correct.
1273 */
1274 if (oip->ip_src.s_addr != fin->fin_daddr) {
1275 fin->fin_flx |= FI_BAD;
1276 DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin);
1277 }
1278 break;
1279 default :
1280 break;
1281 }
1282
1283 ipf_pr_short(fin, minicmpsz);
1284
1285 ipf_checkv4sum(fin);
1286 }
1287
1288
1289 /* ------------------------------------------------------------------------ */
1290 /* Function: ipf_pr_tcpcommon */
1291 /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */
1292 /* Parameters: fin(I) - pointer to packet information */
1293 /* */
1294 /* TCP header sanity checking. Look for bad combinations of TCP flags, */
1295 /* and make some checks with how they interact with other fields. */
1296 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */
1297 /* valid and mark the packet as bad if not. */
1298 /* ------------------------------------------------------------------------ */
1299 static inline int
ipf_pr_tcpcommon(fr_info_t * fin)1300 ipf_pr_tcpcommon(fr_info_t *fin)
1301 {
1302 ipf_main_softc_t *softc = fin->fin_main_soft;
1303 int flags, tlen;
1304 tcphdr_t *tcp;
1305
1306 fin->fin_flx |= FI_TCPUDP;
1307 if (fin->fin_off != 0) {
1308 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag);
1309 return (0);
1310 }
1311
1312 if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) {
1313 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
1314 return (-1);
1315 }
1316
1317 tcp = fin->fin_dp;
1318 if (fin->fin_dlen > 3) {
1319 fin->fin_sport = ntohs(tcp->th_sport);
1320 fin->fin_dport = ntohs(tcp->th_dport);
1321 }
1322
1323 if ((fin->fin_flx & FI_SHORT) != 0) {
1324 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short);
1325 return (1);
1326 }
1327
1328 /*
1329 * Use of the TCP data offset *must* result in a value that is at
1330 * least the same size as the TCP header.
1331 */
1332 tlen = TCP_OFF(tcp) << 2;
1333 if (tlen < sizeof(tcphdr_t)) {
1334 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small);
1335 fin->fin_flx |= FI_BAD;
1336 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t));
1337 return (1);
1338 }
1339
1340 flags = tcp_get_flags(tcp);
1341 fin->fin_tcpf = tcp_get_flags(tcp);
1342
1343 /*
1344 * If the urgent flag is set, then the urgent pointer must
1345 * also be set and vice versa. Good TCP packets do not have
1346 * just one of these set.
1347 */
1348 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) {
1349 fin->fin_flx |= FI_BAD;
1350 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp);
1351 #if 0
1352 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) {
1353 /*
1354 * Ignore this case (#if 0) as it shows up in "real"
1355 * traffic with bogus values in the urgent pointer field.
1356 */
1357 fin->fin_flx |= FI_BAD;
1358 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp);
1359 #endif
1360 } else if (((flags & (TH_SYN|TH_FIN)) != 0) &&
1361 ((flags & (TH_RST|TH_ACK)) == TH_RST)) {
1362 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
1363 fin->fin_flx |= FI_BAD;
1364 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin);
1365 #if 1
1366 } else if (((flags & TH_SYN) != 0) &&
1367 ((flags & (TH_URG|TH_PUSH)) != 0)) {
1368 /*
1369 * SYN with URG and PUSH set is not for normal TCP but it is
1370 * possible(?) with T/TCP...but who uses T/TCP?
1371 */
1372 fin->fin_flx |= FI_BAD;
1373 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin);
1374 #endif
1375 } else if (!(flags & TH_ACK)) {
1376 /*
1377 * If the ack bit isn't set, then either the SYN or
1378 * RST bit must be set. If the SYN bit is set, then
1379 * we expect the ACK field to be 0. If the ACK is
1380 * not set and if URG, PSH or FIN are set, consdier
1381 * that to indicate a bad TCP packet.
1382 */
1383 if ((flags == TH_SYN) && (tcp->th_ack != 0)) {
1384 /*
1385 * Cisco PIX sets the ACK field to a random value.
1386 * In light of this, do not set FI_BAD until a patch
1387 * is available from Cisco to ensure that
1388 * interoperability between existing systems is
1389 * achieved.
1390 */
1391 /*fin->fin_flx |= FI_BAD*/;
1392 /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/
1393 } else if (!(flags & (TH_RST|TH_SYN))) {
1394 fin->fin_flx |= FI_BAD;
1395 DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin);
1396 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) {
1397 fin->fin_flx |= FI_BAD;
1398 DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin);
1399 }
1400 }
1401 if (fin->fin_flx & FI_BAD) {
1402 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags);
1403 return (1);
1404 }
1405
1406 /*
1407 * At this point, it's not exactly clear what is to be gained by
1408 * marking up which TCP options are and are not present. The one we
1409 * are most interested in is the TCP window scale. This is only in
1410 * a SYN packet [RFC1323] so we don't need this here...?
1411 * Now if we were to analyse the header for passive fingerprinting,
1412 * then that might add some weight to adding this...
1413 */
1414 if (tlen == sizeof(tcphdr_t)) {
1415 return (0);
1416 }
1417
1418 if (ipf_pr_pullup(fin, tlen) == -1) {
1419 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
1420 return (-1);
1421 }
1422
1423 #if 0
1424 tcp = fin->fin_dp;
1425 ip = fin->fin_ip;
1426 s = (u_char *)(tcp + 1);
1427 off = IP_HL(ip) << 2;
1428 # ifdef _KERNEL
1429 if (fin->fin_mp != NULL) {
1430 mb_t *m = *fin->fin_mp;
1431
1432 if (off + tlen > M_LEN(m))
1433 return;
1434 }
1435 # endif
1436 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) {
1437 opt = *s;
1438 if (opt == '\0')
1439 break;
1440 else if (opt == TCPOPT_NOP)
1441 ol = 1;
1442 else {
1443 if (tlen < 2)
1444 break;
1445 ol = (int)*(s + 1);
1446 if (ol < 2 || ol > tlen)
1447 break;
1448 }
1449
1450 for (i = 9, mv = 4; mv >= 0; ) {
1451 op = ipopts + i;
1452 if (opt == (u_char)op->ol_val) {
1453 optmsk |= op->ol_bit;
1454 break;
1455 }
1456 }
1457 tlen -= ol;
1458 s += ol;
1459 }
1460 #endif /* 0 */
1461
1462 return (0);
1463 }
1464
1465
1466
1467 /* ------------------------------------------------------------------------ */
1468 /* Function: ipf_pr_udpcommon */
1469 /* Returns: int - 0 = header ok, 1 = bad packet */
1470 /* Parameters: fin(I) - pointer to packet information */
1471 /* */
1472 /* Extract the UDP source and destination ports, if present. If compiled */
1473 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */
1474 /* ------------------------------------------------------------------------ */
1475 static inline int
ipf_pr_udpcommon(fr_info_t * fin)1476 ipf_pr_udpcommon(fr_info_t *fin)
1477 {
1478 udphdr_t *udp;
1479
1480 fin->fin_flx |= FI_TCPUDP;
1481
1482 if (!fin->fin_off && (fin->fin_dlen > 3)) {
1483 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) {
1484 ipf_main_softc_t *softc = fin->fin_main_soft;
1485
1486 fin->fin_flx |= FI_SHORT;
1487 LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup);
1488 return (1);
1489 }
1490
1491 udp = fin->fin_dp;
1492
1493 fin->fin_sport = ntohs(udp->uh_sport);
1494 fin->fin_dport = ntohs(udp->uh_dport);
1495 }
1496
1497 return (0);
1498 }
1499
1500
1501 /* ------------------------------------------------------------------------ */
1502 /* Function: ipf_pr_tcp */
1503 /* Returns: void */
1504 /* Parameters: fin(I) - pointer to packet information */
1505 /* */
1506 /* IPv4 Only */
1507 /* Analyse the packet for IPv4/TCP properties. */
1508 /* ------------------------------------------------------------------------ */
1509 static inline void
ipf_pr_tcp(fr_info_t * fin)1510 ipf_pr_tcp(fr_info_t *fin)
1511 {
1512
1513 ipf_pr_short(fin, sizeof(tcphdr_t));
1514
1515 if (ipf_pr_tcpcommon(fin) == 0)
1516 ipf_checkv4sum(fin);
1517 }
1518
1519
1520 /* ------------------------------------------------------------------------ */
1521 /* Function: ipf_pr_udp */
1522 /* Returns: void */
1523 /* Parameters: fin(I) - pointer to packet information */
1524 /* */
1525 /* IPv4 Only */
1526 /* Analyse the packet for IPv4/UDP properties. */
1527 /* ------------------------------------------------------------------------ */
1528 static inline void
ipf_pr_udp(fr_info_t * fin)1529 ipf_pr_udp(fr_info_t *fin)
1530 {
1531
1532 ipf_pr_short(fin, sizeof(udphdr_t));
1533
1534 if (ipf_pr_udpcommon(fin) == 0)
1535 ipf_checkv4sum(fin);
1536 }
1537
1538
1539 /* ------------------------------------------------------------------------ */
1540 /* Function: ipf_pr_esp */
1541 /* Returns: void */
1542 /* Parameters: fin(I) - pointer to packet information */
1543 /* */
1544 /* Analyse the packet for ESP properties. */
1545 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */
1546 /* even though the newer ESP packets must also have a sequence number that */
1547 /* is 32bits as well, it is not possible(?) to determine the version from a */
1548 /* simple packet header. */
1549 /* ------------------------------------------------------------------------ */
1550 static inline void
ipf_pr_esp(fr_info_t * fin)1551 ipf_pr_esp(fr_info_t *fin)
1552 {
1553
1554 if (fin->fin_off == 0) {
1555 ipf_pr_short(fin, 8);
1556 if (ipf_pr_pullup(fin, 8) == -1) {
1557 ipf_main_softc_t *softc = fin->fin_main_soft;
1558
1559 LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup);
1560 }
1561 }
1562 }
1563
1564
1565 /* ------------------------------------------------------------------------ */
1566 /* Function: ipf_pr_ah */
1567 /* Returns: int - value of the next header or IPPROTO_NONE if error */
1568 /* Parameters: fin(I) - pointer to packet information */
1569 /* */
1570 /* Analyse the packet for AH properties. */
1571 /* The minimum length is taken to be the combination of all fields in the */
1572 /* header being present and no authentication data (null algorithm used.) */
1573 /* ------------------------------------------------------------------------ */
1574 static inline int
ipf_pr_ah(fr_info_t * fin)1575 ipf_pr_ah(fr_info_t *fin)
1576 {
1577 ipf_main_softc_t *softc = fin->fin_main_soft;
1578 authhdr_t *ah;
1579 int len;
1580
1581 fin->fin_flx |= FI_AH;
1582 ipf_pr_short(fin, sizeof(*ah));
1583
1584 if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) {
1585 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad);
1586 return (IPPROTO_NONE);
1587 }
1588
1589 if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) {
1590 DT(fr_v4_ah_pullup_1);
1591 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
1592 return (IPPROTO_NONE);
1593 }
1594
1595 ah = (authhdr_t *)fin->fin_dp;
1596
1597 len = (ah->ah_plen + 2) << 2;
1598 ipf_pr_short(fin, len);
1599 if (ipf_pr_pullup(fin, len) == -1) {
1600 DT(fr_v4_ah_pullup_2);
1601 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
1602 return (IPPROTO_NONE);
1603 }
1604
1605 /*
1606 * Adjust fin_dp and fin_dlen for skipping over the authentication
1607 * header.
1608 */
1609 fin->fin_dp = (char *)fin->fin_dp + len;
1610 fin->fin_dlen -= len;
1611 return (ah->ah_next);
1612 }
1613
1614
1615 /* ------------------------------------------------------------------------ */
1616 /* Function: ipf_pr_gre */
1617 /* Returns: void */
1618 /* Parameters: fin(I) - pointer to packet information */
1619 /* */
1620 /* Analyse the packet for GRE properties. */
1621 /* ------------------------------------------------------------------------ */
1622 static inline void
ipf_pr_gre(fr_info_t * fin)1623 ipf_pr_gre(fr_info_t *fin)
1624 {
1625 ipf_main_softc_t *softc = fin->fin_main_soft;
1626 grehdr_t *gre;
1627
1628 ipf_pr_short(fin, sizeof(grehdr_t));
1629
1630 if (fin->fin_off != 0) {
1631 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag);
1632 return;
1633 }
1634
1635 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
1636 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup);
1637 return;
1638 }
1639
1640 gre = fin->fin_dp;
1641 if (GRE_REV(gre->gr_flags) == 1)
1642 fin->fin_data[0] = gre->gr_call;
1643 }
1644
1645
1646 /* ------------------------------------------------------------------------ */
1647 /* Function: ipf_pr_ipv4hdr */
1648 /* Returns: void */
1649 /* Parameters: fin(I) - pointer to packet information */
1650 /* */
1651 /* IPv4 Only */
1652 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */
1653 /* Check all options present and flag their presence if any exist. */
1654 /* ------------------------------------------------------------------------ */
1655 static inline void
ipf_pr_ipv4hdr(fr_info_t * fin)1656 ipf_pr_ipv4hdr(fr_info_t *fin)
1657 {
1658 u_short optmsk = 0, secmsk = 0, auth = 0;
1659 int hlen, ol, mv, p, i;
1660 const struct optlist *op;
1661 u_char *s, opt;
1662 u_short off;
1663 fr_ip_t *fi;
1664 ip_t *ip;
1665
1666 fi = &fin->fin_fi;
1667 hlen = fin->fin_hlen;
1668
1669 ip = fin->fin_ip;
1670 p = ip->ip_p;
1671 fi->fi_p = p;
1672 fin->fin_crc = p;
1673 fi->fi_tos = ip->ip_tos;
1674 fin->fin_id = ntohs(ip->ip_id);
1675 off = ntohs(ip->ip_off);
1676
1677 /* Get both TTL and protocol */
1678 fi->fi_p = ip->ip_p;
1679 fi->fi_ttl = ip->ip_ttl;
1680
1681 /* Zero out bits not used in IPv6 address */
1682 fi->fi_src.i6[1] = 0;
1683 fi->fi_src.i6[2] = 0;
1684 fi->fi_src.i6[3] = 0;
1685 fi->fi_dst.i6[1] = 0;
1686 fi->fi_dst.i6[2] = 0;
1687 fi->fi_dst.i6[3] = 0;
1688
1689 fi->fi_saddr = ip->ip_src.s_addr;
1690 fin->fin_crc += fi->fi_saddr;
1691 fi->fi_daddr = ip->ip_dst.s_addr;
1692 fin->fin_crc += fi->fi_daddr;
1693 if (IN_MULTICAST(ntohl(fi->fi_daddr)))
1694 fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
1695
1696 /*
1697 * set packet attribute flags based on the offset and
1698 * calculate the byte offset that it represents.
1699 */
1700 off &= IP_MF|IP_OFFMASK;
1701 if (off != 0) {
1702 int morefrag = off & IP_MF;
1703
1704 fi->fi_flx |= FI_FRAG;
1705 off &= IP_OFFMASK;
1706 if (off == 1 && p == IPPROTO_TCP) {
1707 fin->fin_flx |= FI_SHORT; /* RFC 3128 */
1708 DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin);
1709 }
1710 if (off != 0) {
1711 fin->fin_flx |= FI_FRAGBODY;
1712 off <<= 3;
1713 if ((off + fin->fin_dlen > 65535) ||
1714 (fin->fin_dlen == 0) ||
1715 ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
1716 /*
1717 * The length of the packet, starting at its
1718 * offset cannot exceed 65535 (0xffff) as the
1719 * length of an IP packet is only 16 bits.
1720 *
1721 * Any fragment that isn't the last fragment
1722 * must have a length greater than 0 and it
1723 * must be an even multiple of 8.
1724 */
1725 fi->fi_flx |= FI_BAD;
1726 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin);
1727 }
1728 }
1729 }
1730 fin->fin_off = off;
1731
1732 /*
1733 * Call per-protocol setup and checking
1734 */
1735 if (p == IPPROTO_AH) {
1736 /*
1737 * Treat AH differently because we expect there to be another
1738 * layer 4 header after it.
1739 */
1740 p = ipf_pr_ah(fin);
1741 }
1742
1743 switch (p)
1744 {
1745 case IPPROTO_UDP :
1746 ipf_pr_udp(fin);
1747 break;
1748 case IPPROTO_TCP :
1749 ipf_pr_tcp(fin);
1750 break;
1751 case IPPROTO_ICMP :
1752 ipf_pr_icmp(fin);
1753 break;
1754 case IPPROTO_ESP :
1755 ipf_pr_esp(fin);
1756 break;
1757 case IPPROTO_GRE :
1758 ipf_pr_gre(fin);
1759 break;
1760 }
1761
1762 ip = fin->fin_ip;
1763 if (ip == NULL)
1764 return;
1765
1766 /*
1767 * If it is a standard IP header (no options), set the flag fields
1768 * which relate to options to 0.
1769 */
1770 if (hlen == sizeof(*ip)) {
1771 fi->fi_optmsk = 0;
1772 fi->fi_secmsk = 0;
1773 fi->fi_auth = 0;
1774 return;
1775 }
1776
1777 /*
1778 * So the IP header has some IP options attached. Walk the entire
1779 * list of options present with this packet and set flags to indicate
1780 * which ones are here and which ones are not. For the somewhat out
1781 * of date and obscure security classification options, set a flag to
1782 * represent which classification is present.
1783 */
1784 fi->fi_flx |= FI_OPTIONS;
1785
1786 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
1787 opt = *s;
1788 if (opt == '\0')
1789 break;
1790 else if (opt == IPOPT_NOP)
1791 ol = 1;
1792 else {
1793 if (hlen < 2)
1794 break;
1795 ol = (int)*(s + 1);
1796 if (ol < 2 || ol > hlen)
1797 break;
1798 }
1799 for (i = 9, mv = 4; mv >= 0; ) {
1800 op = ipopts + i;
1801
1802 if ((opt == (u_char)op->ol_val) && (ol > 4)) {
1803 u_32_t doi;
1804
1805 switch (opt)
1806 {
1807 case IPOPT_SECURITY :
1808 if (optmsk & op->ol_bit) {
1809 fin->fin_flx |= FI_BAD;
1810 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit));
1811 } else {
1812 doi = ipf_checkripso(s);
1813 secmsk = doi >> 16;
1814 auth = doi & 0xffff;
1815 }
1816 break;
1817
1818 case IPOPT_CIPSO :
1819
1820 if (optmsk & op->ol_bit) {
1821 fin->fin_flx |= FI_BAD;
1822 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit));
1823 } else {
1824 doi = ipf_checkcipso(fin,
1825 s, ol);
1826 secmsk = doi >> 16;
1827 auth = doi & 0xffff;
1828 }
1829 break;
1830 }
1831 optmsk |= op->ol_bit;
1832 }
1833
1834 if (opt < op->ol_val)
1835 i -= mv;
1836 else
1837 i += mv;
1838 mv--;
1839 }
1840 hlen -= ol;
1841 s += ol;
1842 }
1843
1844 /*
1845 *
1846 */
1847 if (auth && !(auth & 0x0100))
1848 auth &= 0xff00;
1849 fi->fi_optmsk = optmsk;
1850 fi->fi_secmsk = secmsk;
1851 fi->fi_auth = auth;
1852 }
1853
1854
1855 /* ------------------------------------------------------------------------ */
1856 /* Function: ipf_checkripso */
1857 /* Returns: void */
1858 /* Parameters: s(I) - pointer to start of RIPSO option */
1859 /* */
1860 /* ------------------------------------------------------------------------ */
1861 static u_32_t
ipf_checkripso(u_char * s)1862 ipf_checkripso(u_char *s)
1863 {
1864 const struct optlist *sp;
1865 u_short secmsk = 0, auth = 0;
1866 u_char sec;
1867 int j, m;
1868
1869 sec = *(s + 2); /* classification */
1870 for (j = 3, m = 2; m >= 0; ) {
1871 sp = secopt + j;
1872 if (sec == sp->ol_val) {
1873 secmsk |= sp->ol_bit;
1874 auth = *(s + 3);
1875 auth *= 256;
1876 auth += *(s + 4);
1877 break;
1878 }
1879 if (sec < sp->ol_val)
1880 j -= m;
1881 else
1882 j += m;
1883 m--;
1884 }
1885
1886 return (secmsk << 16) | auth;
1887 }
1888
1889
1890 /* ------------------------------------------------------------------------ */
1891 /* Function: ipf_checkcipso */
1892 /* Returns: u_32_t - 0 = failure, else the doi from the header */
1893 /* Parameters: fin(IO) - pointer to packet information */
1894 /* s(I) - pointer to start of CIPSO option */
1895 /* ol(I) - length of CIPSO option field */
1896 /* */
1897 /* This function returns the domain of integrity (DOI) field from the CIPSO */
1898 /* header and returns that whilst also storing the highest sensitivity */
1899 /* value found in the fr_info_t structure. */
1900 /* */
1901 /* No attempt is made to extract the category bitmaps as these are defined */
1902 /* by the user (rather than the protocol) and can be rather numerous on the */
1903 /* end nodes. */
1904 /* ------------------------------------------------------------------------ */
1905 static u_32_t
ipf_checkcipso(fr_info_t * fin,u_char * s,int ol)1906 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol)
1907 {
1908 ipf_main_softc_t *softc = fin->fin_main_soft;
1909 fr_ip_t *fi;
1910 u_32_t doi;
1911 u_char *t, tag, tlen, sensitivity;
1912 int len;
1913
1914 if (ol < 6 || ol > 40) {
1915 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad);
1916 fin->fin_flx |= FI_BAD;
1917 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol);
1918 return (0);
1919 }
1920
1921 fi = &fin->fin_fi;
1922 fi->fi_sensitivity = 0;
1923 /*
1924 * The DOI field MUST be there.
1925 */
1926 bcopy(s + 2, &doi, sizeof(doi));
1927
1928 t = (u_char *)s + 6;
1929 for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) {
1930 tag = *t;
1931 tlen = *(t + 1);
1932 if (tlen > len || tlen < 4 || tlen > 34) {
1933 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen);
1934 fin->fin_flx |= FI_BAD;
1935 DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen);
1936 return (0);
1937 }
1938
1939 sensitivity = 0;
1940 /*
1941 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet
1942 * draft (16 July 1992) that has expired.
1943 */
1944 if (tag == 0) {
1945 fin->fin_flx |= FI_BAD;
1946 DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag);
1947 continue;
1948 } else if (tag == 1) {
1949 if (*(t + 2) != 0) {
1950 fin->fin_flx |= FI_BAD;
1951 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2));
1952 continue;
1953 }
1954 sensitivity = *(t + 3);
1955 /* Category bitmap for categories 0-239 */
1956
1957 } else if (tag == 4) {
1958 if (*(t + 2) != 0) {
1959 fin->fin_flx |= FI_BAD;
1960 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2));
1961 continue;
1962 }
1963 sensitivity = *(t + 3);
1964 /* Enumerated categories, 16bits each, upto 15 */
1965
1966 } else if (tag == 5) {
1967 if (*(t + 2) != 0) {
1968 fin->fin_flx |= FI_BAD;
1969 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2));
1970 continue;
1971 }
1972 sensitivity = *(t + 3);
1973 /* Range of categories (2*16bits), up to 7 pairs */
1974
1975 } else if (tag > 127) {
1976 /* Custom defined DOI */
1977 ;
1978 } else {
1979 fin->fin_flx |= FI_BAD;
1980 DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag);
1981 continue;
1982 }
1983
1984 if (sensitivity > fi->fi_sensitivity)
1985 fi->fi_sensitivity = sensitivity;
1986 }
1987
1988 return (doi);
1989 }
1990
1991
1992 /* ------------------------------------------------------------------------ */
1993 /* Function: ipf_makefrip */
1994 /* Returns: int - 0 == packet ok, -1 == packet freed */
1995 /* Parameters: hlen(I) - length of IP packet header */
1996 /* ip(I) - pointer to the IP header */
1997 /* fin(IO) - pointer to packet information */
1998 /* */
1999 /* Compact the IP header into a structure which contains just the info. */
2000 /* which is useful for comparing IP headers with and store this information */
2001 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */
2002 /* this function will be called with either an IPv4 or IPv6 packet. */
2003 /* ------------------------------------------------------------------------ */
2004 int
ipf_makefrip(int hlen,ip_t * ip,fr_info_t * fin)2005 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin)
2006 {
2007 ipf_main_softc_t *softc = fin->fin_main_soft;
2008 int v;
2009
2010 fin->fin_depth = 0;
2011 fin->fin_hlen = (u_short)hlen;
2012 fin->fin_ip = ip;
2013 fin->fin_rule = 0xffffffff;
2014 fin->fin_group[0] = -1;
2015 fin->fin_group[1] = '\0';
2016 fin->fin_dp = (char *)ip + hlen;
2017
2018 v = fin->fin_v;
2019 if (v == 4) {
2020 fin->fin_plen = ntohs(ip->ip_len);
2021 fin->fin_dlen = fin->fin_plen - hlen;
2022 ipf_pr_ipv4hdr(fin);
2023 #ifdef USE_INET6
2024 } else if (v == 6) {
2025 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
2026 fin->fin_dlen = fin->fin_plen;
2027 fin->fin_plen += hlen;
2028
2029 ipf_pr_ipv6hdr(fin);
2030 #endif
2031 }
2032 if (fin->fin_ip == NULL) {
2033 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed);
2034 return (-1);
2035 }
2036 return (0);
2037 }
2038
2039
2040 /* ------------------------------------------------------------------------ */
2041 /* Function: ipf_portcheck */
2042 /* Returns: int - 1 == port matched, 0 == port match failed */
2043 /* Parameters: frp(I) - pointer to port check `expression' */
2044 /* pop(I) - port number to evaluate */
2045 /* */
2046 /* Perform a comparison of a port number against some other(s), using a */
2047 /* structure with compare information stored in it. */
2048 /* ------------------------------------------------------------------------ */
2049 static inline int
ipf_portcheck(frpcmp_t * frp,u_32_t pop)2050 ipf_portcheck(frpcmp_t *frp, u_32_t pop)
2051 {
2052 int err = 1;
2053 u_32_t po;
2054
2055 po = frp->frp_port;
2056
2057 /*
2058 * Do opposite test to that required and continue if that succeeds.
2059 */
2060 switch (frp->frp_cmp)
2061 {
2062 case FR_EQUAL :
2063 if (pop != po) /* EQUAL */
2064 err = 0;
2065 break;
2066 case FR_NEQUAL :
2067 if (pop == po) /* NOTEQUAL */
2068 err = 0;
2069 break;
2070 case FR_LESST :
2071 if (pop >= po) /* LESSTHAN */
2072 err = 0;
2073 break;
2074 case FR_GREATERT :
2075 if (pop <= po) /* GREATERTHAN */
2076 err = 0;
2077 break;
2078 case FR_LESSTE :
2079 if (pop > po) /* LT or EQ */
2080 err = 0;
2081 break;
2082 case FR_GREATERTE :
2083 if (pop < po) /* GT or EQ */
2084 err = 0;
2085 break;
2086 case FR_OUTRANGE :
2087 if (pop >= po && pop <= frp->frp_top) /* Out of range */
2088 err = 0;
2089 break;
2090 case FR_INRANGE :
2091 if (pop <= po || pop >= frp->frp_top) /* In range */
2092 err = 0;
2093 break;
2094 case FR_INCRANGE :
2095 if (pop < po || pop > frp->frp_top) /* Inclusive range */
2096 err = 0;
2097 break;
2098 default :
2099 break;
2100 }
2101 return (err);
2102 }
2103
2104
2105 /* ------------------------------------------------------------------------ */
2106 /* Function: ipf_tcpudpchk */
2107 /* Returns: int - 1 == protocol matched, 0 == check failed */
2108 /* Parameters: fda(I) - pointer to packet information */
2109 /* ft(I) - pointer to structure with comparison data */
2110 /* */
2111 /* Compares the current pcket (assuming it is TCP/UDP) information with a */
2112 /* structure containing information that we want to match against. */
2113 /* ------------------------------------------------------------------------ */
2114 int
ipf_tcpudpchk(fr_ip_t * fi,frtuc_t * ft)2115 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft)
2116 {
2117 int err = 1;
2118
2119 /*
2120 * Both ports should *always* be in the first fragment.
2121 * So far, I cannot find any cases where they can not be.
2122 *
2123 * compare destination ports
2124 */
2125 if (ft->ftu_dcmp)
2126 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]);
2127
2128 /*
2129 * compare source ports
2130 */
2131 if (err && ft->ftu_scmp)
2132 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]);
2133
2134 /*
2135 * If we don't have all the TCP/UDP header, then how can we
2136 * expect to do any sort of match on it ? If we were looking for
2137 * TCP flags, then NO match. If not, then match (which should
2138 * satisfy the "short" class too).
2139 */
2140 if (err && (fi->fi_p == IPPROTO_TCP)) {
2141 if (fi->fi_flx & FI_SHORT)
2142 return (!(ft->ftu_tcpf | ft->ftu_tcpfm));
2143 /*
2144 * Match the flags ? If not, abort this match.
2145 */
2146 if (ft->ftu_tcpfm &&
2147 ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) {
2148 FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf,
2149 ft->ftu_tcpfm, ft->ftu_tcpf));
2150 err = 0;
2151 }
2152 }
2153 return (err);
2154 }
2155
2156
2157 /* ------------------------------------------------------------------------ */
2158 /* Function: ipf_check_ipf */
2159 /* Returns: int - 0 == match, else no match */
2160 /* Parameters: fin(I) - pointer to packet information */
2161 /* fr(I) - pointer to filter rule */
2162 /* portcmp(I) - flag indicating whether to attempt matching on */
2163 /* TCP/UDP port data. */
2164 /* */
2165 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */
2166 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
2167 /* this function. */
2168 /* ------------------------------------------------------------------------ */
2169 static inline int
ipf_check_ipf(fr_info_t * fin,frentry_t * fr,int portcmp)2170 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp)
2171 {
2172 u_32_t *ld, *lm, *lip;
2173 fripf_t *fri;
2174 fr_ip_t *fi;
2175 int i;
2176
2177 fi = &fin->fin_fi;
2178 fri = fr->fr_ipf;
2179 lip = (u_32_t *)fi;
2180 lm = (u_32_t *)&fri->fri_mip;
2181 ld = (u_32_t *)&fri->fri_ip;
2182
2183 /*
2184 * first 32 bits to check coversion:
2185 * IP version, TOS, TTL, protocol
2186 */
2187 i = ((*lip & *lm) != *ld);
2188 FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
2189 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2190 if (i)
2191 return (1);
2192
2193 /*
2194 * Next 32 bits is a constructed bitmask indicating which IP options
2195 * are present (if any) in this packet.
2196 */
2197 lip++, lm++, ld++;
2198 i = ((*lip & *lm) != *ld);
2199 FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
2200 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2201 if (i != 0)
2202 return (1);
2203
2204 lip++, lm++, ld++;
2205 /*
2206 * Unrolled loops (4 each, for 32 bits) for address checks.
2207 */
2208 /*
2209 * Check the source address.
2210 */
2211 if (fr->fr_satype == FRI_LOOKUP) {
2212 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr,
2213 fi->fi_v, lip, fin->fin_plen);
2214 if (i == -1)
2215 return (1);
2216 lip += 3;
2217 lm += 3;
2218 ld += 3;
2219 } else {
2220 i = ((*lip & *lm) != *ld);
2221 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
2222 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2223 if (fi->fi_v == 6) {
2224 lip++, lm++, ld++;
2225 i |= ((*lip & *lm) != *ld);
2226 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
2227 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2228 lip++, lm++, ld++;
2229 i |= ((*lip & *lm) != *ld);
2230 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
2231 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2232 lip++, lm++, ld++;
2233 i |= ((*lip & *lm) != *ld);
2234 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
2235 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2236 } else {
2237 lip += 3;
2238 lm += 3;
2239 ld += 3;
2240 }
2241 }
2242 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
2243 if (i != 0)
2244 return (1);
2245
2246 /*
2247 * Check the destination address.
2248 */
2249 lip++, lm++, ld++;
2250 if (fr->fr_datype == FRI_LOOKUP) {
2251 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr,
2252 fi->fi_v, lip, fin->fin_plen);
2253 if (i == -1)
2254 return (1);
2255 lip += 3;
2256 lm += 3;
2257 ld += 3;
2258 } else {
2259 i = ((*lip & *lm) != *ld);
2260 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
2261 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2262 if (fi->fi_v == 6) {
2263 lip++, lm++, ld++;
2264 i |= ((*lip & *lm) != *ld);
2265 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
2266 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2267 lip++, lm++, ld++;
2268 i |= ((*lip & *lm) != *ld);
2269 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
2270 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2271 lip++, lm++, ld++;
2272 i |= ((*lip & *lm) != *ld);
2273 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
2274 ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2275 } else {
2276 lip += 3;
2277 lm += 3;
2278 ld += 3;
2279 }
2280 }
2281 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
2282 if (i != 0)
2283 return (1);
2284 /*
2285 * IP addresses matched. The next 32bits contains:
2286 * mast of old IP header security & authentication bits.
2287 */
2288 lip++, lm++, ld++;
2289 i = (*ld - (*lip & *lm));
2290 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
2291
2292 /*
2293 * Next we have 32 bits of packet flags.
2294 */
2295 lip++, lm++, ld++;
2296 i |= (*ld - (*lip & *lm));
2297 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
2298
2299 if (i == 0) {
2300 /*
2301 * If a fragment, then only the first has what we're
2302 * looking for here...
2303 */
2304 if (portcmp) {
2305 if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc))
2306 i = 1;
2307 } else {
2308 if (fr->fr_dcmp || fr->fr_scmp ||
2309 fr->fr_tcpf || fr->fr_tcpfm)
2310 i = 1;
2311 if (fr->fr_icmpm || fr->fr_icmp) {
2312 if (((fi->fi_p != IPPROTO_ICMP) &&
2313 (fi->fi_p != IPPROTO_ICMPV6)) ||
2314 fin->fin_off || (fin->fin_dlen < 2))
2315 i = 1;
2316 else if ((fin->fin_data[0] & fr->fr_icmpm) !=
2317 fr->fr_icmp) {
2318 FR_DEBUG(("i. %#x & %#x != %#x\n",
2319 fin->fin_data[0],
2320 fr->fr_icmpm, fr->fr_icmp));
2321 i = 1;
2322 }
2323 }
2324 }
2325 }
2326 return (i);
2327 }
2328
2329
2330 /* ------------------------------------------------------------------------ */
2331 /* Function: ipf_scanlist */
2332 /* Returns: int - result flags of scanning filter list */
2333 /* Parameters: fin(I) - pointer to packet information */
2334 /* pass(I) - default result to return for filtering */
2335 /* */
2336 /* Check the input/output list of rules for a match to the current packet. */
2337 /* If a match is found, the value of fr_flags from the rule becomes the */
2338 /* return value and fin->fin_fr points to the matched rule. */
2339 /* */
2340 /* This function may be called recursively upto 16 times (limit inbuilt.) */
2341 /* When unwinding, it should finish up with fin_depth as 0. */
2342 /* */
2343 /* Could be per interface, but this gets real nasty when you don't have, */
2344 /* or can't easily change, the kernel source code to . */
2345 /* ------------------------------------------------------------------------ */
2346 int
ipf_scanlist(fr_info_t * fin,u_32_t pass)2347 ipf_scanlist(fr_info_t *fin, u_32_t pass)
2348 {
2349 ipf_main_softc_t *softc = fin->fin_main_soft;
2350 int rulen, portcmp, off, skip;
2351 struct frentry *fr, *fnext;
2352 u_32_t passt, passo;
2353
2354 /*
2355 * Do not allow nesting deeper than 16 levels.
2356 */
2357 if (fin->fin_depth >= 16)
2358 return (pass);
2359
2360 fr = fin->fin_fr;
2361
2362 /*
2363 * If there are no rules in this list, return now.
2364 */
2365 if (fr == NULL)
2366 return (pass);
2367
2368 skip = 0;
2369 portcmp = 0;
2370 fin->fin_depth++;
2371 fin->fin_fr = NULL;
2372 off = fin->fin_off;
2373
2374 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
2375 portcmp = 1;
2376
2377 for (rulen = 0; fr; fr = fnext, rulen++) {
2378 fnext = fr->fr_next;
2379 if (skip != 0) {
2380 FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags));
2381 skip--;
2382 continue;
2383 }
2384
2385 /*
2386 * In all checks below, a null (zero) value in the
2387 * filter struture is taken to mean a wildcard.
2388 *
2389 * check that we are working for the right interface
2390 */
2391 #ifdef _KERNEL
2392 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
2393 continue;
2394 #else
2395 if (opts & (OPT_VERBOSE|OPT_DEBUG))
2396 printf("\n");
2397 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' :
2398 FR_ISPASS(pass) ? 'p' :
2399 FR_ISACCOUNT(pass) ? 'A' :
2400 FR_ISAUTH(pass) ? 'a' :
2401 (pass & FR_NOMATCH) ? 'n' :'b'));
2402 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
2403 continue;
2404 FR_VERBOSE((":i"));
2405 #endif
2406
2407 switch (fr->fr_type)
2408 {
2409 case FR_T_IPF :
2410 case FR_T_IPF_BUILTIN :
2411 if (ipf_check_ipf(fin, fr, portcmp))
2412 continue;
2413 break;
2414 #if defined(IPFILTER_BPF)
2415 case FR_T_BPFOPC :
2416 case FR_T_BPFOPC_BUILTIN :
2417 {
2418 u_char *mc;
2419 int wlen;
2420
2421 if (*fin->fin_mp == NULL)
2422 continue;
2423 if (fin->fin_family != fr->fr_family)
2424 continue;
2425 mc = (u_char *)fin->fin_m;
2426 wlen = fin->fin_dlen + fin->fin_hlen;
2427 if (!bpf_filter(fr->fr_data, mc, wlen, 0))
2428 continue;
2429 break;
2430 }
2431 #endif
2432 case FR_T_CALLFUNC_BUILTIN :
2433 {
2434 frentry_t *f;
2435
2436 f = (*fr->fr_func)(fin, &pass);
2437 if (f != NULL)
2438 fr = f;
2439 else
2440 continue;
2441 break;
2442 }
2443
2444 case FR_T_IPFEXPR :
2445 case FR_T_IPFEXPR_BUILTIN :
2446 if (fin->fin_family != fr->fr_family)
2447 continue;
2448 if (ipf_fr_matcharray(fin, fr->fr_data) == 0)
2449 continue;
2450 break;
2451
2452 default :
2453 break;
2454 }
2455
2456 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
2457 if (fin->fin_nattag == NULL)
2458 continue;
2459 if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
2460 continue;
2461 }
2462 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen));
2463
2464 passt = fr->fr_flags;
2465
2466 /*
2467 * If the rule is a "call now" rule, then call the function
2468 * in the rule, if it exists and use the results from that.
2469 * If the function pointer is bad, just make like we ignore
2470 * it, except for increasing the hit counter.
2471 */
2472 if ((passt & FR_CALLNOW) != 0) {
2473 frentry_t *frs;
2474
2475 ATOMIC_INC64(fr->fr_hits);
2476 if ((fr->fr_func == NULL) ||
2477 (fr->fr_func == (ipfunc_t)-1))
2478 continue;
2479
2480 frs = fin->fin_fr;
2481 fin->fin_fr = fr;
2482 fr = (*fr->fr_func)(fin, &passt);
2483 if (fr == NULL) {
2484 fin->fin_fr = frs;
2485 continue;
2486 }
2487 passt = fr->fr_flags;
2488 }
2489 fin->fin_fr = fr;
2490
2491 #ifdef IPFILTER_LOG
2492 /*
2493 * Just log this packet...
2494 */
2495 if ((passt & FR_LOGMASK) == FR_LOG) {
2496 if (ipf_log_pkt(fin, passt) == -1) {
2497 if (passt & FR_LOGORBLOCK) {
2498 DT(frb_logfail);
2499 passt &= ~FR_CMDMASK;
2500 passt |= FR_BLOCK|FR_QUICK;
2501 fin->fin_reason = FRB_LOGFAIL;
2502 }
2503 }
2504 }
2505 #endif /* IPFILTER_LOG */
2506
2507 MUTEX_ENTER(&fr->fr_lock);
2508 fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
2509 fr->fr_hits++;
2510 MUTEX_EXIT(&fr->fr_lock);
2511 fin->fin_rule = rulen;
2512
2513 passo = pass;
2514 if (FR_ISSKIP(passt)) {
2515 skip = fr->fr_arg;
2516 continue;
2517 } else if (((passt & FR_LOGMASK) != FR_LOG) &&
2518 ((passt & FR_LOGMASK) != FR_DECAPSULATE)) {
2519 pass = passt;
2520 }
2521
2522 if (passt & (FR_RETICMP|FR_FAKEICMP))
2523 fin->fin_icode = fr->fr_icode;
2524
2525 if (fr->fr_group != -1) {
2526 (void) strncpy(fin->fin_group,
2527 FR_NAME(fr, fr_group),
2528 strlen(FR_NAME(fr, fr_group)));
2529 } else {
2530 fin->fin_group[0] = '\0';
2531 }
2532
2533 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt));
2534
2535 if (fr->fr_grphead != NULL) {
2536 fin->fin_fr = fr->fr_grphead->fg_start;
2537 FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead)));
2538
2539 if (FR_ISDECAPS(passt))
2540 passt = ipf_decaps(fin, pass, fr->fr_icode);
2541 else
2542 passt = ipf_scanlist(fin, pass);
2543
2544 if (fin->fin_fr == NULL) {
2545 fin->fin_rule = rulen;
2546 if (fr->fr_group != -1)
2547 (void) strncpy(fin->fin_group,
2548 fr->fr_names +
2549 fr->fr_group,
2550 strlen(fr->fr_names +
2551 fr->fr_group));
2552 fin->fin_fr = fr;
2553 passt = pass;
2554 }
2555 pass = passt;
2556 }
2557
2558 if (pass & FR_QUICK) {
2559 /*
2560 * Finally, if we've asked to track state for this
2561 * packet, set it up. Add state for "quick" rules
2562 * here so that if the action fails we can consider
2563 * the rule to "not match" and keep on processing
2564 * filter rules.
2565 */
2566 if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) &&
2567 !(fin->fin_flx & FI_STATE)) {
2568 int out = fin->fin_out;
2569
2570 fin->fin_fr = fr;
2571 if (ipf_state_add(softc, fin, NULL, 0) == 0) {
2572 LBUMPD(ipf_stats[out], fr_ads);
2573 } else {
2574 LBUMPD(ipf_stats[out], fr_bads);
2575 pass = passo;
2576 continue;
2577 }
2578 }
2579 break;
2580 }
2581 }
2582 fin->fin_depth--;
2583 return (pass);
2584 }
2585
2586
2587 /* ------------------------------------------------------------------------ */
2588 /* Function: ipf_acctpkt */
2589 /* Returns: frentry_t* - always returns NULL */
2590 /* Parameters: fin(I) - pointer to packet information */
2591 /* passp(IO) - pointer to current/new filter decision (unused) */
2592 /* */
2593 /* Checks a packet against accounting rules, if there are any for the given */
2594 /* IP protocol version. */
2595 /* */
2596 /* N.B.: this function returns NULL to match the prototype used by other */
2597 /* functions called from the IPFilter "mainline" in ipf_check(). */
2598 /* ------------------------------------------------------------------------ */
2599 frentry_t *
ipf_acctpkt(fr_info_t * fin,u_32_t * passp __unused)2600 ipf_acctpkt(fr_info_t *fin, u_32_t *passp __unused)
2601 {
2602 ipf_main_softc_t *softc = fin->fin_main_soft;
2603 char group[FR_GROUPLEN];
2604 frentry_t *fr, *frsave;
2605 u_32_t pass, rulen;
2606
2607 fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
2608
2609 if (fr != NULL) {
2610 frsave = fin->fin_fr;
2611 bcopy(fin->fin_group, group, FR_GROUPLEN);
2612 rulen = fin->fin_rule;
2613 fin->fin_fr = fr;
2614 pass = ipf_scanlist(fin, FR_NOMATCH);
2615 if (FR_ISACCOUNT(pass)) {
2616 LBUMPD(ipf_stats[0], fr_acct);
2617 }
2618 fin->fin_fr = frsave;
2619 bcopy(group, fin->fin_group, FR_GROUPLEN);
2620 fin->fin_rule = rulen;
2621 }
2622 return (NULL);
2623 }
2624
2625
2626 /* ------------------------------------------------------------------------ */
2627 /* Function: ipf_firewall */
2628 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */
2629 /* were found, returns NULL. */
2630 /* Parameters: fin(I) - pointer to packet information */
2631 /* passp(IO) - pointer to current/new filter decision (unused) */
2632 /* */
2633 /* Applies an appropriate set of firewall rules to the packet, to see if */
2634 /* there are any matches. The first check is to see if a match can be seen */
2635 /* in the cache. If not, then search an appropriate list of rules. Once a */
2636 /* matching rule is found, take any appropriate actions as defined by the */
2637 /* rule - except logging. */
2638 /* ------------------------------------------------------------------------ */
2639 static frentry_t *
ipf_firewall(fr_info_t * fin,u_32_t * passp)2640 ipf_firewall(fr_info_t *fin, u_32_t *passp)
2641 {
2642 ipf_main_softc_t *softc = fin->fin_main_soft;
2643 frentry_t *fr;
2644 u_32_t pass;
2645 int out;
2646
2647 out = fin->fin_out;
2648 pass = *passp;
2649
2650 /*
2651 * This rule cache will only affect packets that are not being
2652 * statefully filtered.
2653 */
2654 fin->fin_fr = softc->ipf_rules[out][softc->ipf_active];
2655 if (fin->fin_fr != NULL)
2656 pass = ipf_scanlist(fin, softc->ipf_pass);
2657
2658 if ((pass & FR_NOMATCH)) {
2659 LBUMPD(ipf_stats[out], fr_nom);
2660 }
2661 fr = fin->fin_fr;
2662
2663 /*
2664 * Apply packets per second rate-limiting to a rule as required.
2665 */
2666 if ((fr != NULL) && (fr->fr_pps != 0) &&
2667 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
2668 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr);
2669 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST);
2670 pass |= FR_BLOCK;
2671 LBUMPD(ipf_stats[out], fr_ppshit);
2672 fin->fin_reason = FRB_PPSRATE;
2673 }
2674
2675 /*
2676 * If we fail to add a packet to the authorization queue, then we
2677 * drop the packet later. However, if it was added then pretend
2678 * we've dropped it already.
2679 */
2680 if (FR_ISAUTH(pass)) {
2681 if (ipf_auth_new(fin->fin_m, fin) != 0) {
2682 DT1(frb_authnew, fr_info_t *, fin);
2683 fin->fin_m = *fin->fin_mp = NULL;
2684 fin->fin_reason = FRB_AUTHNEW;
2685 fin->fin_error = 0;
2686 } else {
2687 IPFERROR(1);
2688 fin->fin_error = ENOSPC;
2689 }
2690 }
2691
2692 if ((fr != NULL) && (fr->fr_func != NULL) &&
2693 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW))
2694 (void) (*fr->fr_func)(fin, &pass);
2695
2696 /*
2697 * If a rule is a pre-auth rule, check again in the list of rules
2698 * loaded for authenticated use. It does not particulary matter
2699 * if this search fails because a "preauth" result, from a rule,
2700 * is treated as "not a pass", hence the packet is blocked.
2701 */
2702 if (FR_ISPREAUTH(pass)) {
2703 pass = ipf_auth_pre_scanlist(softc, fin, pass);
2704 }
2705
2706 /*
2707 * If the rule has "keep frag" and the packet is actually a fragment,
2708 * then create a fragment state entry.
2709 */
2710 if (pass & FR_KEEPFRAG) {
2711 if (fin->fin_flx & FI_FRAG) {
2712 if (ipf_frag_new(softc, fin, pass) == -1) {
2713 LBUMP(ipf_stats[out].fr_bnfr);
2714 } else {
2715 LBUMP(ipf_stats[out].fr_nfr);
2716 }
2717 } else {
2718 LBUMP(ipf_stats[out].fr_cfr);
2719 }
2720 }
2721
2722 fr = fin->fin_fr;
2723 *passp = pass;
2724
2725 return (fr);
2726 }
2727
2728
2729 /* ------------------------------------------------------------------------ */
2730 /* Function: ipf_check */
2731 /* Returns: int - 0 == packet allowed through, */
2732 /* User space: */
2733 /* -1 == packet blocked */
2734 /* 1 == packet not matched */
2735 /* -2 == requires authentication */
2736 /* Kernel: */
2737 /* > 0 == filter error # for packet */
2738 /* Parameters: ctx(I) - pointer to the instance context */
2739 /* ip(I) - pointer to start of IPv4/6 packet */
2740 /* hlen(I) - length of header */
2741 /* ifp(I) - pointer to interface this packet is on */
2742 /* out(I) - 0 == packet going in, 1 == packet going out */
2743 /* mp(IO) - pointer to caller's buffer pointer that holds this */
2744 /* IP packet. */
2745 /* Solaris: */
2746 /* qpi(I) - pointer to STREAMS queue information for this */
2747 /* interface & direction. */
2748 /* */
2749 /* ipf_check() is the master function for all IPFilter packet processing. */
2750 /* It orchestrates: Network Address Translation (NAT), checking for packet */
2751 /* authorisation (or pre-authorisation), presence of related state info., */
2752 /* generating log entries, IP packet accounting, routing of packets as */
2753 /* directed by firewall rules and of course whether or not to allow the */
2754 /* packet to be further processed by the kernel. */
2755 /* */
2756 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */
2757 /* freed. Packets passed may be returned with the pointer pointed to by */
2758 /* by "mp" changed to a new buffer. */
2759 /* ------------------------------------------------------------------------ */
2760 int
ipf_check(void * ctx,ip_t * ip,int hlen,struct ifnet * ifp,int out,void * qif,mb_t ** mp)2761 ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out
2762 #if defined(_KERNEL) && SOLARIS
2763 , void* qif, mb_t **mp)
2764 #else
2765 , mb_t **mp)
2766 #endif
2767 {
2768 /*
2769 * The above really sucks, but short of writing a diff
2770 */
2771 ipf_main_softc_t *softc = ctx;
2772 fr_info_t frinfo;
2773 fr_info_t *fin = &frinfo;
2774 u_32_t pass = softc->ipf_pass;
2775 frentry_t *fr = NULL;
2776 int v = IP_V(ip);
2777 mb_t *mc = NULL;
2778 mb_t *m;
2779 /*
2780 * The first part of ipf_check() deals with making sure that what goes
2781 * into the filtering engine makes some sense. Information about the
2782 * the packet is distilled, collected into a fr_info_t structure and
2783 * the an attempt to ensure the buffer the packet is in is big enough
2784 * to hold all the required packet headers.
2785 */
2786 #ifdef _KERNEL
2787 # if SOLARIS
2788 qpktinfo_t *qpi = qif;
2789
2790 # ifdef __sparc
2791 if ((u_int)ip & 0x3)
2792 return (2);
2793 # endif
2794 # else
2795 SPL_INT(s);
2796 # endif
2797
2798 if (softc->ipf_running <= 0) {
2799 return (0);
2800 }
2801
2802 bzero((char *)fin, sizeof(*fin));
2803
2804 # if SOLARIS
2805 if (qpi->qpi_flags & QF_BROADCAST)
2806 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2807 if (qpi->qpi_flags & QF_MULTICAST)
2808 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2809 m = qpi->qpi_m;
2810 fin->fin_qfm = m;
2811 fin->fin_qpi = qpi;
2812 # else /* SOLARIS */
2813
2814 m = *mp;
2815
2816 # if defined(M_MCAST)
2817 if ((m->m_flags & M_MCAST) != 0)
2818 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2819 # endif
2820 # if defined(M_MLOOP)
2821 if ((m->m_flags & M_MLOOP) != 0)
2822 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2823 # endif
2824 # if defined(M_BCAST)
2825 if ((m->m_flags & M_BCAST) != 0)
2826 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2827 # endif
2828 # ifdef M_CANFASTFWD
2829 /*
2830 * XXX For now, IP Filter and fast-forwarding of cached flows
2831 * XXX are mutually exclusive. Eventually, IP Filter should
2832 * XXX get a "can-fast-forward" filter rule.
2833 */
2834 m->m_flags &= ~M_CANFASTFWD;
2835 # endif /* M_CANFASTFWD */
2836 # if defined(CSUM_DELAY_DATA) && !defined(__FreeBSD__)
2837 /*
2838 * disable delayed checksums.
2839 */
2840 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
2841 in_delayed_cksum(m);
2842 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
2843 }
2844 # endif /* CSUM_DELAY_DATA */
2845 # endif /* SOLARIS */
2846 #else
2847 bzero((char *)fin, sizeof(*fin));
2848 m = *mp;
2849 # if defined(M_MCAST)
2850 if ((m->m_flags & M_MCAST) != 0)
2851 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2852 # endif
2853 # if defined(M_MLOOP)
2854 if ((m->m_flags & M_MLOOP) != 0)
2855 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2856 # endif
2857 # if defined(M_BCAST)
2858 if ((m->m_flags & M_BCAST) != 0)
2859 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2860 # endif
2861 #endif /* _KERNEL */
2862
2863 fin->fin_v = v;
2864 fin->fin_m = m;
2865 fin->fin_ip = ip;
2866 fin->fin_mp = mp;
2867 fin->fin_out = out;
2868 fin->fin_ifp = ifp;
2869 fin->fin_error = ENETUNREACH;
2870 fin->fin_hlen = (u_short)hlen;
2871 fin->fin_dp = (char *)ip + hlen;
2872 fin->fin_main_soft = softc;
2873
2874 fin->fin_ipoff = (char *)ip - MTOD(m, char *);
2875
2876 SPL_NET(s);
2877
2878 #ifdef USE_INET6
2879 if (v == 6) {
2880 LBUMP(ipf_stats[out].fr_ipv6);
2881 /*
2882 * Jumbo grams are quite likely too big for internal buffer
2883 * structures to handle comfortably, for now, so just drop
2884 * them.
2885 */
2886 if (((ip6_t *)ip)->ip6_plen == 0) {
2887 DT1(frb_jumbo, ip6_t *, (ip6_t *)ip);
2888 pass = FR_BLOCK|FR_NOMATCH;
2889 fin->fin_reason = FRB_JUMBO;
2890 goto finished;
2891 }
2892 fin->fin_family = AF_INET6;
2893 } else
2894 #endif
2895 {
2896 fin->fin_family = AF_INET;
2897 }
2898
2899 if (ipf_makefrip(hlen, ip, fin) == -1) {
2900 DT1(frb_makefrip, fr_info_t *, fin);
2901 pass = FR_BLOCK|FR_NOMATCH;
2902 fin->fin_reason = FRB_MAKEFRIP;
2903 goto finished;
2904 }
2905
2906 /*
2907 * For at least IPv6 packets, if a m_pullup() fails then this pointer
2908 * becomes NULL and so we have no packet to free.
2909 */
2910 if (*fin->fin_mp == NULL)
2911 goto finished;
2912
2913 if (!out) {
2914 if (v == 4) {
2915 if (softc->ipf_chksrc && !ipf_verifysrc(fin)) {
2916 LBUMPD(ipf_stats[0], fr_v4_badsrc);
2917 fin->fin_flx |= FI_BADSRC;
2918 }
2919 if (fin->fin_ip->ip_ttl < softc->ipf_minttl) {
2920 LBUMPD(ipf_stats[0], fr_v4_badttl);
2921 fin->fin_flx |= FI_LOWTTL;
2922 }
2923 }
2924 #ifdef USE_INET6
2925 else if (v == 6) {
2926 if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) {
2927 LBUMPD(ipf_stats[0], fr_v6_badttl);
2928 fin->fin_flx |= FI_LOWTTL;
2929 }
2930 }
2931 #endif
2932 }
2933
2934 if (fin->fin_flx & FI_SHORT) {
2935 LBUMPD(ipf_stats[out], fr_short);
2936 }
2937
2938 READ_ENTER(&softc->ipf_mutex);
2939
2940 if (!out) {
2941 switch (fin->fin_v)
2942 {
2943 case 4 :
2944 if (ipf_nat_checkin(fin, &pass) == -1) {
2945 goto filterdone;
2946 }
2947 break;
2948 #ifdef USE_INET6
2949 case 6 :
2950 if (ipf_nat6_checkin(fin, &pass) == -1) {
2951 goto filterdone;
2952 }
2953 break;
2954 #endif
2955 default :
2956 break;
2957 }
2958 }
2959 /*
2960 * Check auth now.
2961 * If a packet is found in the auth table, then skip checking
2962 * the access lists for permission but we do need to consider
2963 * the result as if it were from the ACL's. In addition, being
2964 * found in the auth table means it has been seen before, so do
2965 * not pass it through accounting (again), lest it be counted twice.
2966 */
2967 fr = ipf_auth_check(fin, &pass);
2968 if (!out && (fr == NULL))
2969 (void) ipf_acctpkt(fin, NULL);
2970
2971 if (fr == NULL) {
2972 if ((fin->fin_flx & FI_FRAG) != 0)
2973 fr = ipf_frag_known(fin, &pass);
2974
2975 if (fr == NULL)
2976 fr = ipf_state_check(fin, &pass);
2977 }
2978
2979 if ((pass & FR_NOMATCH) || (fr == NULL))
2980 fr = ipf_firewall(fin, &pass);
2981
2982 /*
2983 * If we've asked to track state for this packet, set it up.
2984 * Here rather than ipf_firewall because ipf_checkauth may decide
2985 * to return a packet for "keep state"
2986 */
2987 if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) &&
2988 !(fin->fin_flx & FI_STATE)) {
2989 if (ipf_state_add(softc, fin, NULL, 0) == 0) {
2990 LBUMP(ipf_stats[out].fr_ads);
2991 } else {
2992 LBUMP(ipf_stats[out].fr_bads);
2993 if (FR_ISPASS(pass)) {
2994 DT(frb_stateadd);
2995 pass &= ~FR_CMDMASK;
2996 pass |= FR_BLOCK;
2997 fin->fin_reason = FRB_STATEADD;
2998 }
2999 }
3000 }
3001
3002 fin->fin_fr = fr;
3003 if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) {
3004 fin->fin_dif = &fr->fr_dif;
3005 fin->fin_tif = &fr->fr_tifs[fin->fin_rev];
3006 }
3007
3008 /*
3009 * Only count/translate packets which will be passed on, out the
3010 * interface.
3011 */
3012 if (out && FR_ISPASS(pass)) {
3013 (void) ipf_acctpkt(fin, NULL);
3014
3015 switch (fin->fin_v)
3016 {
3017 case 4 :
3018 if (ipf_nat_checkout(fin, &pass) == -1) {
3019 ;
3020 } else if ((softc->ipf_update_ipid != 0) && (v == 4)) {
3021 if (ipf_updateipid(fin) == -1) {
3022 DT(frb_updateipid);
3023 LBUMP(ipf_stats[1].fr_ipud);
3024 pass &= ~FR_CMDMASK;
3025 pass |= FR_BLOCK;
3026 fin->fin_reason = FRB_UPDATEIPID;
3027 } else {
3028 LBUMP(ipf_stats[0].fr_ipud);
3029 }
3030 }
3031 break;
3032 #ifdef USE_INET6
3033 case 6 :
3034 (void) ipf_nat6_checkout(fin, &pass);
3035 break;
3036 #endif
3037 default :
3038 break;
3039 }
3040 }
3041
3042 filterdone:
3043 #ifdef IPFILTER_LOG
3044 if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
3045 (void) ipf_dolog(fin, &pass);
3046 }
3047 #endif
3048
3049 /*
3050 * The FI_STATE flag is cleared here so that calling ipf_state_check
3051 * will work when called from inside of fr_fastroute. Although
3052 * there is a similar flag, FI_NATED, for NAT, it does have the same
3053 * impact on code execution.
3054 */
3055 fin->fin_flx &= ~FI_STATE;
3056
3057 #if defined(FASTROUTE_RECURSION)
3058 /*
3059 * Up the reference on fr_lock and exit ipf_mutex. The generation of
3060 * a packet below can sometimes cause a recursive call into IPFilter.
3061 * On those platforms where that does happen, we need to hang onto
3062 * the filter rule just in case someone decides to remove or flush it
3063 * in the meantime.
3064 */
3065 if (fr != NULL) {
3066 MUTEX_ENTER(&fr->fr_lock);
3067 fr->fr_ref++;
3068 MUTEX_EXIT(&fr->fr_lock);
3069 }
3070
3071 RWLOCK_EXIT(&softc->ipf_mutex);
3072 #endif
3073
3074 if ((pass & FR_RETMASK) != 0) {
3075 /*
3076 * Should we return an ICMP packet to indicate error
3077 * status passing through the packet filter ?
3078 * WARNING: ICMP error packets AND TCP RST packets should
3079 * ONLY be sent in repsonse to incoming packets. Sending
3080 * them in response to outbound packets can result in a
3081 * panic on some operating systems.
3082 */
3083 if (!out) {
3084 if (pass & FR_RETICMP) {
3085 int dst;
3086
3087 if ((pass & FR_RETMASK) == FR_FAKEICMP)
3088 dst = 1;
3089 else
3090 dst = 0;
3091 (void) ipf_send_icmp_err(ICMP_UNREACH, fin,
3092 dst);
3093 LBUMP(ipf_stats[0].fr_ret);
3094 } else if (((pass & FR_RETMASK) == FR_RETRST) &&
3095 !(fin->fin_flx & FI_SHORT)) {
3096 if (((fin->fin_flx & FI_OOW) != 0) ||
3097 (ipf_send_reset(fin) == 0)) {
3098 LBUMP(ipf_stats[1].fr_ret);
3099 }
3100 }
3101
3102 /*
3103 * When using return-* with auth rules, the auth code
3104 * takes over disposing of this packet.
3105 */
3106 if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
3107 DT1(frb_authcapture, fr_info_t *, fin);
3108 fin->fin_m = *fin->fin_mp = NULL;
3109 fin->fin_reason = FRB_AUTHCAPTURE;
3110 m = NULL;
3111 }
3112 } else {
3113 if (pass & FR_RETRST) {
3114 fin->fin_error = ECONNRESET;
3115 }
3116 }
3117 }
3118
3119 /*
3120 * After the above so that ICMP unreachables and TCP RSTs get
3121 * created properly.
3122 */
3123 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
3124 ipf_nat_uncreate(fin);
3125
3126 /*
3127 * If we didn't drop off the bottom of the list of rules (and thus
3128 * the 'current' rule fr is not NULL), then we may have some extra
3129 * instructions about what to do with a packet.
3130 * Once we're finished return to our caller, freeing the packet if
3131 * we are dropping it.
3132 */
3133 if (fr != NULL) {
3134 frdest_t *fdp;
3135
3136 /*
3137 * Generate a duplicated packet first because ipf_fastroute
3138 * can lead to fin_m being free'd... not good.
3139 */
3140 fdp = fin->fin_dif;
3141 if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
3142 (fdp->fd_ptr != (void *)-1)) {
3143 mc = M_COPY(fin->fin_m);
3144 if (mc != NULL)
3145 ipf_fastroute(mc, &mc, fin, fdp);
3146 }
3147
3148 fdp = fin->fin_tif;
3149 if (!out && (pass & FR_FASTROUTE)) {
3150 /*
3151 * For fastroute rule, no destination interface defined
3152 * so pass NULL as the frdest_t parameter
3153 */
3154 (void) ipf_fastroute(fin->fin_m, mp, fin, NULL);
3155 m = *mp = NULL;
3156 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
3157 (fdp->fd_ptr != (struct ifnet *)-1)) {
3158 /* this is for to rules: */
3159 ipf_fastroute(fin->fin_m, mp, fin, fdp);
3160 m = *mp = NULL;
3161 }
3162
3163 #if defined(FASTROUTE_RECURSION)
3164 (void) ipf_derefrule(softc, &fr);
3165 #endif
3166 }
3167 #if !defined(FASTROUTE_RECURSION)
3168 RWLOCK_EXIT(&softc->ipf_mutex);
3169 #endif
3170
3171 finished:
3172 if (!FR_ISPASS(pass)) {
3173 LBUMP(ipf_stats[out].fr_block);
3174 if (*mp != NULL) {
3175 #ifdef _KERNEL
3176 FREE_MB_T(*mp);
3177 #endif
3178 m = *mp = NULL;
3179 }
3180 } else {
3181 LBUMP(ipf_stats[out].fr_pass);
3182 }
3183
3184 SPL_X(s);
3185
3186 if (fin->fin_m == NULL && fin->fin_flx & FI_BAD &&
3187 fin->fin_reason == FRB_PULLUP) {
3188 /* m_pullup() has freed the mbuf */
3189 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
3190 return (-1);
3191 }
3192
3193
3194 #ifdef _KERNEL
3195 if (FR_ISPASS(pass))
3196 return (0);
3197 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
3198 return (fin->fin_error);
3199 #else /* _KERNEL */
3200 if (*mp != NULL)
3201 (*mp)->mb_ifp = fin->fin_ifp;
3202 blockreason = fin->fin_reason;
3203 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
3204 /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/
3205 if ((pass & FR_NOMATCH) != 0)
3206 return (1);
3207
3208 if ((pass & FR_RETMASK) != 0)
3209 switch (pass & FR_RETMASK)
3210 {
3211 case FR_RETRST :
3212 return (3);
3213 case FR_RETICMP :
3214 return (4);
3215 case FR_FAKEICMP :
3216 return (5);
3217 }
3218
3219 switch (pass & FR_CMDMASK)
3220 {
3221 case FR_PASS :
3222 return (0);
3223 case FR_BLOCK :
3224 return (-1);
3225 case FR_AUTH :
3226 return (-2);
3227 case FR_ACCOUNT :
3228 return (-3);
3229 case FR_PREAUTH :
3230 return (-4);
3231 }
3232 return (2);
3233 #endif /* _KERNEL */
3234 }
3235
3236
3237 #ifdef IPFILTER_LOG
3238 /* ------------------------------------------------------------------------ */
3239 /* Function: ipf_dolog */
3240 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */
3241 /* Parameters: fin(I) - pointer to packet information */
3242 /* passp(IO) - pointer to current/new filter decision (unused) */
3243 /* */
3244 /* Checks flags set to see how a packet should be logged, if it is to be */
3245 /* logged. Adjust statistics based on its success or not. */
3246 /* ------------------------------------------------------------------------ */
3247 frentry_t *
ipf_dolog(fr_info_t * fin,u_32_t * passp)3248 ipf_dolog(fr_info_t *fin, u_32_t *passp)
3249 {
3250 ipf_main_softc_t *softc = fin->fin_main_soft;
3251 u_32_t pass;
3252 int out;
3253
3254 out = fin->fin_out;
3255 pass = *passp;
3256
3257 if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
3258 pass |= FF_LOGNOMATCH;
3259 LBUMPD(ipf_stats[out], fr_npkl);
3260 goto logit;
3261
3262 } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
3263 (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) {
3264 if ((pass & FR_LOGMASK) != FR_LOGP)
3265 pass |= FF_LOGPASS;
3266 LBUMPD(ipf_stats[out], fr_ppkl);
3267 goto logit;
3268
3269 } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
3270 (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) {
3271 if ((pass & FR_LOGMASK) != FR_LOGB)
3272 pass |= FF_LOGBLOCK;
3273 LBUMPD(ipf_stats[out], fr_bpkl);
3274
3275 logit:
3276 if (ipf_log_pkt(fin, pass) == -1) {
3277 /*
3278 * If the "or-block" option has been used then
3279 * block the packet if we failed to log it.
3280 */
3281 if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) {
3282 DT1(frb_logfail2, u_int, pass);
3283 pass &= ~FR_CMDMASK;
3284 pass |= FR_BLOCK;
3285 fin->fin_reason = FRB_LOGFAIL2;
3286 }
3287 }
3288 *passp = pass;
3289 }
3290
3291 return (fin->fin_fr);
3292 }
3293 #endif /* IPFILTER_LOG */
3294
3295
3296 /* ------------------------------------------------------------------------ */
3297 /* Function: ipf_cksum */
3298 /* Returns: u_short - IP header checksum */
3299 /* Parameters: addr(I) - pointer to start of buffer to checksum */
3300 /* len(I) - length of buffer in bytes */
3301 /* */
3302 /* Calculate the two's complement 16 bit checksum of the buffer passed. */
3303 /* */
3304 /* N.B.: addr should be 16bit aligned. */
3305 /* ------------------------------------------------------------------------ */
3306 u_short
ipf_cksum(u_short * addr,int len)3307 ipf_cksum(u_short *addr, int len)
3308 {
3309 u_32_t sum = 0;
3310
3311 for (sum = 0; len > 1; len -= 2)
3312 sum += *addr++;
3313
3314 /* mop up an odd byte, if necessary */
3315 if (len == 1)
3316 sum += *(u_char *)addr;
3317
3318 /*
3319 * add back carry outs from top 16 bits to low 16 bits
3320 */
3321 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
3322 sum += (sum >> 16); /* add carry */
3323 return (u_short)(~sum);
3324 }
3325
3326
3327 /* ------------------------------------------------------------------------ */
3328 /* Function: fr_cksum */
3329 /* Returns: u_short - layer 4 checksum */
3330 /* Parameters: fin(I) - pointer to packet information */
3331 /* ip(I) - pointer to IP header */
3332 /* l4proto(I) - protocol to caclulate checksum for */
3333 /* l4hdr(I) - pointer to layer 4 header */
3334 /* */
3335 /* Calculates the TCP checksum for the packet held in "m", using the data */
3336 /* in the IP header "ip" to seed it. */
3337 /* */
3338 /* NB: This function assumes we've pullup'd enough for all of the IP header */
3339 /* and the TCP header. We also assume that data blocks aren't allocated in */
3340 /* odd sizes. */
3341 /* */
3342 /* Expects ip_len and ip_off to be in network byte order when called. */
3343 /* ------------------------------------------------------------------------ */
3344 u_short
fr_cksum(fr_info_t * fin,ip_t * ip,int l4proto,void * l4hdr)3345 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr)
3346 {
3347 u_short *sp, slen, sumsave, *csump;
3348 u_int sum, sum2;
3349 int hlen;
3350 int off;
3351 #ifdef USE_INET6
3352 ip6_t *ip6;
3353 #endif
3354
3355 csump = NULL;
3356 sumsave = 0;
3357 sp = NULL;
3358 slen = 0;
3359 hlen = 0;
3360 sum = 0;
3361
3362 sum = htons((u_short)l4proto);
3363 /*
3364 * Add up IP Header portion
3365 */
3366 #ifdef USE_INET6
3367 if (IP_V(ip) == 4) {
3368 #endif
3369 hlen = IP_HL(ip) << 2;
3370 off = hlen;
3371 sp = (u_short *)&ip->ip_src;
3372 sum += *sp++; /* ip_src */
3373 sum += *sp++;
3374 sum += *sp++; /* ip_dst */
3375 sum += *sp++;
3376 slen = fin->fin_plen - off;
3377 sum += htons(slen);
3378 #ifdef USE_INET6
3379 } else if (IP_V(ip) == 6) {
3380 mb_t *m;
3381
3382 m = fin->fin_m;
3383 ip6 = (ip6_t *)ip;
3384 off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr);
3385 int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6));
3386 return (ipf_pcksum6(m, ip6, off, len));
3387 } else {
3388 return (0xffff);
3389 }
3390 #endif
3391
3392 switch (l4proto)
3393 {
3394 case IPPROTO_UDP :
3395 csump = &((udphdr_t *)l4hdr)->uh_sum;
3396 break;
3397
3398 case IPPROTO_TCP :
3399 csump = &((tcphdr_t *)l4hdr)->th_sum;
3400 break;
3401 case IPPROTO_ICMP :
3402 csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
3403 sum = 0; /* Pseudo-checksum is not included */
3404 break;
3405 #ifdef USE_INET6
3406 case IPPROTO_ICMPV6 :
3407 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum;
3408 break;
3409 #endif
3410 default :
3411 break;
3412 }
3413
3414 if (csump != NULL) {
3415 sumsave = *csump;
3416 *csump = 0;
3417 }
3418
3419 sum2 = ipf_pcksum(fin, off, sum);
3420 if (csump != NULL)
3421 *csump = sumsave;
3422 return (sum2);
3423 }
3424
3425
3426 /* ------------------------------------------------------------------------ */
3427 /* Function: ipf_findgroup */
3428 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */
3429 /* Parameters: softc(I) - pointer to soft context main structure */
3430 /* group(I) - group name to search for */
3431 /* unit(I) - device to which this group belongs */
3432 /* set(I) - which set of rules (inactive/inactive) this is */
3433 /* fgpp(O) - pointer to place to store pointer to the pointer */
3434 /* to where to add the next (last) group or where */
3435 /* to delete group from. */
3436 /* */
3437 /* Search amongst the defined groups for a particular group number. */
3438 /* ------------------------------------------------------------------------ */
3439 frgroup_t *
ipf_findgroup(ipf_main_softc_t * softc,char * group,minor_t unit,int set,frgroup_t *** fgpp)3440 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set,
3441 frgroup_t ***fgpp)
3442 {
3443 frgroup_t *fg, **fgp;
3444
3445 /*
3446 * Which list of groups to search in is dependent on which list of
3447 * rules are being operated on.
3448 */
3449 fgp = &softc->ipf_groups[unit][set];
3450
3451 while ((fg = *fgp) != NULL) {
3452 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
3453 break;
3454 else
3455 fgp = &fg->fg_next;
3456 }
3457 if (fgpp != NULL)
3458 *fgpp = fgp;
3459 return (fg);
3460 }
3461
3462
3463 /* ------------------------------------------------------------------------ */
3464 /* Function: ipf_group_add */
3465 /* Returns: frgroup_t * - NULL == did not create group, */
3466 /* != NULL == pointer to the group */
3467 /* Parameters: softc(I) - pointer to soft context main structure */
3468 /* num(I) - group number to add */
3469 /* head(I) - rule pointer that is using this as the head */
3470 /* flags(I) - rule flags which describe the type of rule it is */
3471 /* unit(I) - device to which this group will belong to */
3472 /* set(I) - which set of rules (inactive/inactive) this is */
3473 /* Write Locks: ipf_mutex */
3474 /* */
3475 /* Add a new group head, or if it already exists, increase the reference */
3476 /* count to it. */
3477 /* ------------------------------------------------------------------------ */
3478 frgroup_t *
ipf_group_add(ipf_main_softc_t * softc,char * group,void * head,u_32_t flags,minor_t unit,int set)3479 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags,
3480 minor_t unit, int set)
3481 {
3482 frgroup_t *fg, **fgp;
3483 u_32_t gflags;
3484
3485 if (group == NULL)
3486 return (NULL);
3487
3488 if (unit == IPL_LOGIPF && *group == '\0')
3489 return (NULL);
3490
3491 fgp = NULL;
3492 gflags = flags & FR_INOUT;
3493
3494 fg = ipf_findgroup(softc, group, unit, set, &fgp);
3495 if (fg != NULL) {
3496 if (fg->fg_head == NULL && head != NULL)
3497 fg->fg_head = head;
3498 if (fg->fg_flags == 0)
3499 fg->fg_flags = gflags;
3500 else if (gflags != fg->fg_flags)
3501 return (NULL);
3502 fg->fg_ref++;
3503 return (fg);
3504 }
3505
3506 KMALLOC(fg, frgroup_t *);
3507 if (fg != NULL) {
3508 fg->fg_head = head;
3509 fg->fg_start = NULL;
3510 fg->fg_next = *fgp;
3511 bcopy(group, fg->fg_name, strnlen(group, FR_GROUPLEN) + 1);
3512 fg->fg_flags = gflags;
3513 fg->fg_ref = 1;
3514 fg->fg_set = &softc->ipf_groups[unit][set];
3515 *fgp = fg;
3516 }
3517 return (fg);
3518 }
3519
3520
3521 /* ------------------------------------------------------------------------ */
3522 /* Function: ipf_group_del */
3523 /* Returns: int - number of rules deleted */
3524 /* Parameters: softc(I) - pointer to soft context main structure */
3525 /* group(I) - group name to delete */
3526 /* fr(I) - filter rule from which group is referenced */
3527 /* Write Locks: ipf_mutex */
3528 /* */
3529 /* This function is called whenever a reference to a group is to be dropped */
3530 /* and thus its reference count needs to be lowered and the group free'd if */
3531 /* the reference count reaches zero. Passing in fr is really for the sole */
3532 /* purpose of knowing when the head rule is being deleted. */
3533 /* ------------------------------------------------------------------------ */
3534 void
ipf_group_del(ipf_main_softc_t * softc,frgroup_t * group,frentry_t * fr)3535 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr)
3536 {
3537
3538 if (group->fg_head == fr)
3539 group->fg_head = NULL;
3540
3541 group->fg_ref--;
3542 if ((group->fg_ref == 0) && (group->fg_start == NULL))
3543 ipf_group_free(group);
3544 }
3545
3546
3547 /* ------------------------------------------------------------------------ */
3548 /* Function: ipf_group_free */
3549 /* Returns: Nil */
3550 /* Parameters: group(I) - pointer to filter rule group */
3551 /* */
3552 /* Remove the group from the list of groups and free it. */
3553 /* ------------------------------------------------------------------------ */
3554 static void
ipf_group_free(frgroup_t * group)3555 ipf_group_free(frgroup_t *group)
3556 {
3557 frgroup_t **gp;
3558
3559 for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) {
3560 if (*gp == group) {
3561 *gp = group->fg_next;
3562 break;
3563 }
3564 }
3565 KFREE(group);
3566 }
3567
3568
3569 /* ------------------------------------------------------------------------ */
3570 /* Function: ipf_group_flush */
3571 /* Returns: int - number of rules flush from group */
3572 /* Parameters: softc(I) - pointer to soft context main structure */
3573 /* Parameters: group(I) - pointer to filter rule group */
3574 /* */
3575 /* Remove all of the rules that currently are listed under the given group. */
3576 /* ------------------------------------------------------------------------ */
3577 static int
ipf_group_flush(ipf_main_softc_t * softc,frgroup_t * group)3578 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group)
3579 {
3580 int gone = 0;
3581
3582 (void) ipf_flushlist(softc, &gone, &group->fg_start);
3583
3584 return (gone);
3585 }
3586
3587
3588 /* ------------------------------------------------------------------------ */
3589 /* Function: ipf_getrulen */
3590 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */
3591 /* Parameters: softc(I) - pointer to soft context main structure */
3592 /* Parameters: unit(I) - device for which to count the rule's number */
3593 /* flags(I) - which set of rules to find the rule in */
3594 /* group(I) - group name */
3595 /* n(I) - rule number to find */
3596 /* */
3597 /* Find rule # n in group # g and return a pointer to it. Return NULl if */
3598 /* group # g doesn't exist or there are less than n rules in the group. */
3599 /* ------------------------------------------------------------------------ */
3600 frentry_t *
ipf_getrulen(ipf_main_softc_t * softc,int unit,char * group,u_32_t n)3601 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n)
3602 {
3603 frentry_t *fr;
3604 frgroup_t *fg;
3605
3606 fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL);
3607 if (fg == NULL)
3608 return (NULL);
3609 for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--)
3610 ;
3611 if (n != 0)
3612 return (NULL);
3613 return (fr);
3614 }
3615
3616
3617 /* ------------------------------------------------------------------------ */
3618 /* Function: ipf_flushlist */
3619 /* Returns: int - >= 0 - number of flushed rules */
3620 /* Parameters: softc(I) - pointer to soft context main structure */
3621 /* nfreedp(O) - pointer to int where flush count is stored */
3622 /* listp(I) - pointer to list to flush pointer */
3623 /* Write Locks: ipf_mutex */
3624 /* */
3625 /* Recursively flush rules from the list, descending groups as they are */
3626 /* encountered. if a rule is the head of a group and it has lost all its */
3627 /* group members, then also delete the group reference. nfreedp is needed */
3628 /* to store the accumulating count of rules removed, whereas the returned */
3629 /* value is just the number removed from the current list. The latter is */
3630 /* needed to correctly adjust reference counts on rules that define groups. */
3631 /* */
3632 /* NOTE: Rules not loaded from user space cannot be flushed. */
3633 /* ------------------------------------------------------------------------ */
3634 static int
ipf_flushlist(ipf_main_softc_t * softc,int * nfreedp,frentry_t ** listp)3635 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp)
3636 {
3637 int freed = 0;
3638 frentry_t *fp;
3639
3640 while ((fp = *listp) != NULL) {
3641 if ((fp->fr_type & FR_T_BUILTIN) ||
3642 !(fp->fr_flags & FR_COPIED)) {
3643 listp = &fp->fr_next;
3644 continue;
3645 }
3646 *listp = fp->fr_next;
3647 if (fp->fr_next != NULL)
3648 fp->fr_next->fr_pnext = fp->fr_pnext;
3649 fp->fr_pnext = NULL;
3650
3651 if (fp->fr_grphead != NULL) {
3652 freed += ipf_group_flush(softc, fp->fr_grphead);
3653 fp->fr_names[fp->fr_grhead] = '\0';
3654 }
3655
3656 if (fp->fr_icmpgrp != NULL) {
3657 freed += ipf_group_flush(softc, fp->fr_icmpgrp);
3658 fp->fr_names[fp->fr_icmphead] = '\0';
3659 }
3660
3661 if (fp->fr_srctrack.ht_max_nodes)
3662 ipf_rb_ht_flush(&fp->fr_srctrack);
3663
3664 fp->fr_next = NULL;
3665
3666 ASSERT(fp->fr_ref > 0);
3667 if (ipf_derefrule(softc, &fp) == 0)
3668 freed++;
3669 }
3670 *nfreedp += freed;
3671 return (freed);
3672 }
3673
3674
3675 /* ------------------------------------------------------------------------ */
3676 /* Function: ipf_flush */
3677 /* Returns: int - >= 0 - number of flushed rules */
3678 /* Parameters: softc(I) - pointer to soft context main structure */
3679 /* unit(I) - device for which to flush rules */
3680 /* flags(I) - which set of rules to flush */
3681 /* */
3682 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
3683 /* and IPv6) as defined by the value of flags. */
3684 /* ------------------------------------------------------------------------ */
3685 int
ipf_flush(ipf_main_softc_t * softc,minor_t unit,int flags)3686 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags)
3687 {
3688 int flushed = 0, set;
3689
3690 WRITE_ENTER(&softc->ipf_mutex);
3691
3692 set = softc->ipf_active;
3693 if ((flags & FR_INACTIVE) == FR_INACTIVE)
3694 set = 1 - set;
3695
3696 if (flags & FR_OUTQUE) {
3697 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]);
3698 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]);
3699 }
3700 if (flags & FR_INQUE) {
3701 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]);
3702 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]);
3703 }
3704
3705 flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set],
3706 flags & (FR_INQUE|FR_OUTQUE));
3707
3708 RWLOCK_EXIT(&softc->ipf_mutex);
3709
3710 if (unit == IPL_LOGIPF) {
3711 int tmp;
3712
3713 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags);
3714 if (tmp >= 0)
3715 flushed += tmp;
3716 }
3717 return (flushed);
3718 }
3719
3720
3721 /* ------------------------------------------------------------------------ */
3722 /* Function: ipf_flush_groups */
3723 /* Returns: int - >= 0 - number of flushed rules */
3724 /* Parameters: softc(I) - soft context pointerto work with */
3725 /* grhead(I) - pointer to the start of the group list to flush */
3726 /* flags(I) - which set of rules to flush */
3727 /* */
3728 /* Walk through all of the groups under the given group head and remove all */
3729 /* of those that match the flags passed in. The for loop here is bit more */
3730 /* complicated than usual because the removal of a rule with ipf_derefrule */
3731 /* may end up removing not only the structure pointed to by "fg" but also */
3732 /* what is fg_next and fg_next after that. So if a filter rule is actually */
3733 /* removed from the group then it is necessary to start again. */
3734 /* ------------------------------------------------------------------------ */
3735 static int
ipf_flush_groups(ipf_main_softc_t * softc,frgroup_t ** grhead,int flags)3736 ipf_flush_groups(ipf_main_softc_t *softc, frgroup_t **grhead, int flags)
3737 {
3738 frentry_t *fr, **frp;
3739 frgroup_t *fg, **fgp;
3740 int flushed = 0;
3741 int removed = 0;
3742
3743 for (fgp = grhead; (fg = *fgp) != NULL; ) {
3744 while ((fg != NULL) && ((fg->fg_flags & flags) == 0))
3745 fg = fg->fg_next;
3746 if (fg == NULL)
3747 break;
3748 removed = 0;
3749 frp = &fg->fg_start;
3750 while ((removed == 0) && ((fr = *frp) != NULL)) {
3751 if ((fr->fr_flags & flags) == 0) {
3752 frp = &fr->fr_next;
3753 } else {
3754 if (fr->fr_next != NULL)
3755 fr->fr_next->fr_pnext = fr->fr_pnext;
3756 *frp = fr->fr_next;
3757 fr->fr_pnext = NULL;
3758 fr->fr_next = NULL;
3759 (void) ipf_derefrule(softc, &fr);
3760 flushed++;
3761 removed++;
3762 }
3763 }
3764 if (removed == 0)
3765 fgp = &fg->fg_next;
3766 }
3767 return (flushed);
3768 }
3769
3770
3771 /* ------------------------------------------------------------------------ */
3772 /* Function: memstr */
3773 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */
3774 /* Parameters: src(I) - pointer to byte sequence to match */
3775 /* dst(I) - pointer to byte sequence to search */
3776 /* slen(I) - match length */
3777 /* dlen(I) - length available to search in */
3778 /* */
3779 /* Search dst for a sequence of bytes matching those at src and extend for */
3780 /* slen bytes. */
3781 /* ------------------------------------------------------------------------ */
3782 char *
memstr(const char * src,char * dst,size_t slen,size_t dlen)3783 memstr(const char *src, char *dst, size_t slen, size_t dlen)
3784 {
3785 char *s = NULL;
3786
3787 while (dlen >= slen) {
3788 if (bcmp(src, dst, slen) == 0) {
3789 s = dst;
3790 break;
3791 }
3792 dst++;
3793 dlen--;
3794 }
3795 return (s);
3796 }
3797 /* ------------------------------------------------------------------------ */
3798 /* Function: ipf_fixskip */
3799 /* Returns: Nil */
3800 /* Parameters: listp(IO) - pointer to start of list with skip rule */
3801 /* rp(I) - rule added/removed with skip in it. */
3802 /* addremove(I) - adjustment (-1/+1) to make to skip count, */
3803 /* depending on whether a rule was just added */
3804 /* or removed. */
3805 /* */
3806 /* Adjust all the rules in a list which would have skip'd past the position */
3807 /* where we are inserting to skip to the right place given the change. */
3808 /* ------------------------------------------------------------------------ */
3809 void
ipf_fixskip(frentry_t ** listp,frentry_t * rp,int addremove)3810 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove)
3811 {
3812 int rules, rn;
3813 frentry_t *fp;
3814
3815 rules = 0;
3816 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next)
3817 rules++;
3818
3819 if (fp == NULL)
3820 return;
3821
3822 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
3823 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules))
3824 fp->fr_arg += addremove;
3825 }
3826
3827
3828 #ifdef _KERNEL
3829 /* ------------------------------------------------------------------------ */
3830 /* Function: count4bits */
3831 /* Returns: int - >= 0 - number of consecutive bits in input */
3832 /* Parameters: ip(I) - 32bit IP address */
3833 /* */
3834 /* IPv4 ONLY */
3835 /* count consecutive 1's in bit mask. If the mask generated by counting */
3836 /* consecutive 1's is different to that passed, return -1, else return # */
3837 /* of bits. */
3838 /* ------------------------------------------------------------------------ */
3839 int
count4bits(u_32_t ip)3840 count4bits(u_32_t ip)
3841 {
3842 u_32_t ipn;
3843 int cnt = 0, i, j;
3844
3845 ip = ipn = ntohl(ip);
3846 for (i = 32; i; i--, ipn *= 2)
3847 if (ipn & 0x80000000)
3848 cnt++;
3849 else
3850 break;
3851 ipn = 0;
3852 for (i = 32, j = cnt; i; i--, j--) {
3853 ipn *= 2;
3854 if (j > 0)
3855 ipn++;
3856 }
3857 if (ipn == ip)
3858 return (cnt);
3859 return (-1);
3860 }
3861
3862
3863 /* ------------------------------------------------------------------------ */
3864 /* Function: count6bits */
3865 /* Returns: int - >= 0 - number of consecutive bits in input */
3866 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */
3867 /* */
3868 /* IPv6 ONLY */
3869 /* count consecutive 1's in bit mask. */
3870 /* ------------------------------------------------------------------------ */
3871 # ifdef USE_INET6
3872 int
count6bits(u_32_t * msk)3873 count6bits(u_32_t *msk)
3874 {
3875 int i = 0, k;
3876 u_32_t j;
3877
3878 for (k = 3; k >= 0; k--)
3879 if (msk[k] == 0xffffffff)
3880 i += 32;
3881 else {
3882 for (j = msk[k]; j; j <<= 1)
3883 if (j & 0x80000000)
3884 i++;
3885 }
3886 return (i);
3887 }
3888 # endif
3889 #endif /* _KERNEL */
3890
3891
3892 /* ------------------------------------------------------------------------ */
3893 /* Function: ipf_synclist */
3894 /* Returns: int - 0 = no failures, else indication of first failure */
3895 /* Parameters: fr(I) - start of filter list to sync interface names for */
3896 /* ifp(I) - interface pointer for limiting sync lookups */
3897 /* Write Locks: ipf_mutex */
3898 /* */
3899 /* Walk through a list of filter rules and resolve any interface names into */
3900 /* pointers. Where dynamic addresses are used, also update the IP address */
3901 /* used in the rule. The interface pointer is used to limit the lookups to */
3902 /* a specific set of matching names if it is non-NULL. */
3903 /* Errors can occur when resolving the destination name of to/dup-to fields */
3904 /* when the name points to a pool and that pool doest not exist. If this */
3905 /* does happen then it is necessary to check if there are any lookup refs */
3906 /* that need to be dropped before returning with an error. */
3907 /* ------------------------------------------------------------------------ */
3908 static int
ipf_synclist(ipf_main_softc_t * softc,frentry_t * fr,void * ifp)3909 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp)
3910 {
3911 frentry_t *frt, *start = fr;
3912 frdest_t *fdp;
3913 char *name;
3914 int error, interr;
3915 void *ifa;
3916 int v, i;
3917
3918 error = 0;
3919
3920 for (; fr; fr = fr->fr_next) {
3921 if (fr->fr_family == AF_INET)
3922 v = 4;
3923 else if (fr->fr_family == AF_INET6)
3924 v = 6;
3925 else
3926 v = 0;
3927
3928 /*
3929 * Lookup all the interface names that are part of the rule.
3930 */
3931 for (i = 0; i < FR_NUM(fr->fr_ifas); i++) {
3932 if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
3933 continue;
3934 if (fr->fr_ifnames[i] == -1)
3935 continue;
3936 name = FR_NAME(fr, fr_ifnames[i]);
3937 fr->fr_ifas[i] = ipf_resolvenic(softc, name, v);
3938 }
3939
3940 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
3941 /*
3942 * We do the validation for fr_sifpidx here because
3943 * it is a union that contains an offset only when
3944 * fr_sifpidx points to an interface name, an offset
3945 * into fr_names. The union is an offset into
3946 * fr_names in this case only.
3947 *
3948 * Note that sifpidx is only used in ipf_sync() which
3949 * implments ipf -y.
3950 */
3951 if ((interr = ipf_check_names_string(fr->fr_names, fr->fr_namelen, fr->fr_sifpidx)) != 0) {
3952 IPFERROR(interr_tbl[interr-1]);
3953 error = EINVAL;
3954 goto unwind;
3955 }
3956 if (fr->fr_satype != FRI_NORMAL &&
3957 fr->fr_satype != FRI_LOOKUP) {
3958 ifa = ipf_resolvenic(softc, fr->fr_names +
3959 fr->fr_sifpidx, v);
3960 ipf_ifpaddr(softc, v, fr->fr_satype, ifa,
3961 &fr->fr_src6, &fr->fr_smsk6);
3962 }
3963 if (fr->fr_datype != FRI_NORMAL &&
3964 fr->fr_datype != FRI_LOOKUP) {
3965 ifa = ipf_resolvenic(softc, fr->fr_names +
3966 fr->fr_sifpidx, v);
3967 ipf_ifpaddr(softc, v, fr->fr_datype, ifa,
3968 &fr->fr_dst6, &fr->fr_dmsk6);
3969 }
3970 }
3971
3972 fdp = &fr->fr_tifs[0];
3973 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
3974 error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
3975 if (error != 0)
3976 goto unwind;
3977 }
3978
3979 fdp = &fr->fr_tifs[1];
3980 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
3981 error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
3982 if (error != 0)
3983 goto unwind;
3984 }
3985
3986 fdp = &fr->fr_dif;
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 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
3994 (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) {
3995 fr->fr_srcptr = ipf_lookup_res_num(softc,
3996 fr->fr_srctype,
3997 IPL_LOGIPF,
3998 fr->fr_srcnum,
3999 &fr->fr_srcfunc);
4000 }
4001 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4002 (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) {
4003 fr->fr_dstptr = ipf_lookup_res_num(softc,
4004 fr->fr_dsttype,
4005 IPL_LOGIPF,
4006 fr->fr_dstnum,
4007 &fr->fr_dstfunc);
4008 }
4009 }
4010 return (0);
4011
4012 unwind:
4013 for (frt = start; frt != fr; fr = fr->fr_next) {
4014 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4015 (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL))
4016 ipf_lookup_deref(softc, frt->fr_srctype,
4017 frt->fr_srcptr);
4018 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4019 (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL))
4020 ipf_lookup_deref(softc, frt->fr_dsttype,
4021 frt->fr_dstptr);
4022 }
4023 return (error);
4024 }
4025
4026
4027 /* ------------------------------------------------------------------------ */
4028 /* Function: ipf_sync */
4029 /* Returns: void */
4030 /* Parameters: Nil */
4031 /* */
4032 /* ipf_sync() is called when we suspect that the interface list or */
4033 /* information about interfaces (like IP#) has changed. Go through all */
4034 /* filter rules, NAT entries and the state table and check if anything */
4035 /* needs to be changed/updated. */
4036 /* ------------------------------------------------------------------------ */
4037 int
ipf_sync(ipf_main_softc_t * softc,void * ifp)4038 ipf_sync(ipf_main_softc_t *softc, void *ifp)
4039 {
4040 int i;
4041
4042 #if !SOLARIS
4043 ipf_nat_sync(softc, ifp);
4044 ipf_state_sync(softc, ifp);
4045 ipf_lookup_sync(softc, ifp);
4046 #endif
4047
4048 WRITE_ENTER(&softc->ipf_mutex);
4049 (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp);
4050 (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp);
4051 (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp);
4052 (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp);
4053
4054 for (i = 0; i < IPL_LOGSIZE; i++) {
4055 frgroup_t *g;
4056
4057 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next)
4058 (void) ipf_synclist(softc, g->fg_start, ifp);
4059 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next)
4060 (void) ipf_synclist(softc, g->fg_start, ifp);
4061 }
4062 RWLOCK_EXIT(&softc->ipf_mutex);
4063
4064 return (0);
4065 }
4066
4067
4068 /*
4069 * In the functions below, bcopy() is called because the pointer being
4070 * copied _from_ in this instance is a pointer to a char buf (which could
4071 * end up being unaligned) and on the kernel's local stack.
4072 */
4073 /* ------------------------------------------------------------------------ */
4074 /* Function: ipf_copyin_indirect */
4075 /* Returns: int - 0 = success, else failure */
4076 /* Parameters: src(I) - pointer to the source address */
4077 /* dst(I) - destination address */
4078 /* size(I) - number of bytes to copy */
4079 /* */
4080 /* Copy a block of data in from user space, given a pointer to the pointer */
4081 /* to start copying from (src) and a pointer to where to store it (dst). */
4082 /* NB: src - pointer to user space pointer, dst - kernel space pointer */
4083 /* ------------------------------------------------------------------------ */
4084 int
ipf_copyin_indirect(ipf_main_softc_t * softc,void * src,void * dst,size_t size)4085 ipf_copyin_indirect(ipf_main_softc_t *softc, void *src, void *dst, size_t size)
4086 {
4087 caddr_t ca;
4088 int error;
4089
4090 #if SOLARIS
4091 error = COPYIN(src, &ca, sizeof(ca));
4092 if (error != 0)
4093 return (error);
4094 #else
4095 bcopy(src, (caddr_t)&ca, sizeof(ca));
4096 #endif
4097 error = COPYIN(ca, dst, size);
4098 if (error != 0) {
4099 IPFERROR(3);
4100 error = EFAULT;
4101 }
4102 return (error);
4103 }
4104
4105
4106 /* ------------------------------------------------------------------------ */
4107 /* Function: ipf_copyout_indirect */
4108 /* Returns: int - 0 = success, else failure */
4109 /* Parameters: src(I) - pointer to the source address */
4110 /* dst(I) - destination address */
4111 /* size(I) - number of bytes to copy */
4112 /* */
4113 /* Copy a block of data out to user space, given a pointer to the pointer */
4114 /* to start copying from (src) and a pointer to where to store it (dst). */
4115 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */
4116 /* ------------------------------------------------------------------------ */
4117 int
ipf_copyout_indirect(ipf_main_softc_t * softc,void * src,void * dst,size_t size)4118 ipf_copyout_indirect(ipf_main_softc_t *softc, void *src, void *dst, size_t size)
4119 {
4120 caddr_t ca;
4121 int error;
4122
4123 bcopy(dst, (caddr_t)&ca, sizeof(ca));
4124 error = COPYOUT(src, ca, size);
4125 if (error != 0) {
4126 IPFERROR(4);
4127 error = EFAULT;
4128 }
4129 return (error);
4130 }
4131
4132
4133 /* ------------------------------------------------------------------------ */
4134 /* Function: ipf_lock */
4135 /* Returns: int - 0 = success, else error */
4136 /* Parameters: data(I) - pointer to lock value to set */
4137 /* lockp(O) - pointer to location to store old lock value */
4138 /* */
4139 /* Get the new value for the lock integer, set it and return the old value */
4140 /* in *lockp. */
4141 /* ------------------------------------------------------------------------ */
4142 int
ipf_lock(caddr_t data,int * lockp)4143 ipf_lock(caddr_t data, int *lockp)
4144 {
4145 int arg, err;
4146
4147 err = BCOPYIN(data, &arg, sizeof(arg));
4148 if (err != 0)
4149 return (EFAULT);
4150 err = BCOPYOUT(lockp, data, sizeof(*lockp));
4151 if (err != 0)
4152 return (EFAULT);
4153 *lockp = arg;
4154 return (0);
4155 }
4156
4157
4158 /* ------------------------------------------------------------------------ */
4159 /* Function: ipf_getstat */
4160 /* Returns: Nil */
4161 /* Parameters: softc(I) - pointer to soft context main structure */
4162 /* fiop(I) - pointer to ipfilter stats structure */
4163 /* rev(I) - version claim by program doing ioctl */
4164 /* */
4165 /* Stores a copy of current pointers, counters, etc, in the friostat */
4166 /* structure. */
4167 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */
4168 /* program is looking for. This ensure that validation of the version it */
4169 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */
4170 /* allow older binaries to work but kernels without it will not. */
4171 /* ------------------------------------------------------------------------ */
4172 /*ARGSUSED*/
4173 static void
ipf_getstat(ipf_main_softc_t * softc,friostat_t * fiop,int rev)4174 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev)
4175 {
4176 int i;
4177
4178 bcopy((char *)softc->ipf_stats, (char *)fiop->f_st,
4179 sizeof(ipf_statistics_t) * 2);
4180 fiop->f_locks[IPL_LOGSTATE] = -1;
4181 fiop->f_locks[IPL_LOGNAT] = -1;
4182 fiop->f_locks[IPL_LOGIPF] = -1;
4183 fiop->f_locks[IPL_LOGAUTH] = -1;
4184
4185 fiop->f_ipf[0][0] = softc->ipf_rules[0][0];
4186 fiop->f_acct[0][0] = softc->ipf_acct[0][0];
4187 fiop->f_ipf[0][1] = softc->ipf_rules[0][1];
4188 fiop->f_acct[0][1] = softc->ipf_acct[0][1];
4189 fiop->f_ipf[1][0] = softc->ipf_rules[1][0];
4190 fiop->f_acct[1][0] = softc->ipf_acct[1][0];
4191 fiop->f_ipf[1][1] = softc->ipf_rules[1][1];
4192 fiop->f_acct[1][1] = softc->ipf_acct[1][1];
4193
4194 fiop->f_ticks = softc->ipf_ticks;
4195 fiop->f_active = softc->ipf_active;
4196 fiop->f_froute[0] = softc->ipf_frouteok[0];
4197 fiop->f_froute[1] = softc->ipf_frouteok[1];
4198 fiop->f_rb_no_mem = softc->ipf_rb_no_mem;
4199 fiop->f_rb_node_max = softc->ipf_rb_node_max;
4200
4201 fiop->f_running = softc->ipf_running;
4202 for (i = 0; i < IPL_LOGSIZE; i++) {
4203 fiop->f_groups[i][0] = softc->ipf_groups[i][0];
4204 fiop->f_groups[i][1] = softc->ipf_groups[i][1];
4205 }
4206 #ifdef IPFILTER_LOG
4207 fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF);
4208 fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF);
4209 fiop->f_logging = 1;
4210 #else
4211 fiop->f_log_ok = 0;
4212 fiop->f_log_fail = 0;
4213 fiop->f_logging = 0;
4214 #endif
4215 fiop->f_defpass = softc->ipf_pass;
4216 fiop->f_features = ipf_features;
4217
4218 #ifdef IPFILTER_COMPAT
4219 snprintf(fiop->f_version, sizeof(friostat.f_version), "IP Filter: v%d.%d.%d",
4220 (rev / 1000000) % 100,
4221 (rev / 10000) % 100,
4222 (rev / 100) % 100);
4223 #else
4224 (void)rev; /* UNUSED */
4225 (void) strncpy(fiop->f_version, ipfilter_version,
4226 sizeof(fiop->f_version));
4227 #endif
4228 }
4229
4230
4231 #ifdef USE_INET6
4232 int icmptoicmp6types[ICMP_MAXTYPE+1] = {
4233 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */
4234 -1, /* 1: UNUSED */
4235 -1, /* 2: UNUSED */
4236 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */
4237 -1, /* 4: ICMP_SOURCEQUENCH */
4238 ND_REDIRECT, /* 5: ICMP_REDIRECT */
4239 -1, /* 6: UNUSED */
4240 -1, /* 7: UNUSED */
4241 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */
4242 -1, /* 9: UNUSED */
4243 -1, /* 10: UNUSED */
4244 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */
4245 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */
4246 -1, /* 13: ICMP_TSTAMP */
4247 -1, /* 14: ICMP_TSTAMPREPLY */
4248 -1, /* 15: ICMP_IREQ */
4249 -1, /* 16: ICMP_IREQREPLY */
4250 -1, /* 17: ICMP_MASKREQ */
4251 -1, /* 18: ICMP_MASKREPLY */
4252 };
4253
4254
4255 int icmptoicmp6unreach[ICMP_MAX_UNREACH] = {
4256 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */
4257 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */
4258 -1, /* 2: ICMP_UNREACH_PROTOCOL */
4259 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */
4260 -1, /* 4: ICMP_UNREACH_NEEDFRAG */
4261 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */
4262 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */
4263 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */
4264 -1, /* 8: ICMP_UNREACH_ISOLATED */
4265 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */
4266 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */
4267 -1, /* 11: ICMP_UNREACH_TOSNET */
4268 -1, /* 12: ICMP_UNREACH_TOSHOST */
4269 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
4270 };
4271 int icmpreplytype6[ICMP6_MAXTYPE + 1];
4272 #endif
4273
4274 int icmpreplytype4[ICMP_MAXTYPE + 1];
4275
4276
4277 /* ------------------------------------------------------------------------ */
4278 /* Function: ipf_matchicmpqueryreply */
4279 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */
4280 /* Parameters: v(I) - IP protocol version (4 or 6) */
4281 /* ic(I) - ICMP information */
4282 /* icmp(I) - ICMP packet header */
4283 /* rev(I) - direction (0 = forward/1 = reverse) of packet */
4284 /* */
4285 /* Check if the ICMP packet defined by the header pointed to by icmp is a */
4286 /* reply to one as described by what's in ic. If it is a match, return 1, */
4287 /* else return 0 for no match. */
4288 /* ------------------------------------------------------------------------ */
4289 int
ipf_matchicmpqueryreply(int v,icmpinfo_t * ic,icmphdr_t * icmp,int rev)4290 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev)
4291 {
4292 int ictype;
4293
4294 ictype = ic->ici_type;
4295
4296 if (v == 4) {
4297 /*
4298 * If we matched its type on the way in, then when going out
4299 * it will still be the same type.
4300 */
4301 if ((!rev && (icmp->icmp_type == ictype)) ||
4302 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) {
4303 if (icmp->icmp_type != ICMP_ECHOREPLY)
4304 return (1);
4305 if (icmp->icmp_id == ic->ici_id)
4306 return (1);
4307 }
4308 }
4309 #ifdef USE_INET6
4310 else if (v == 6) {
4311 if ((!rev && (icmp->icmp_type == ictype)) ||
4312 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) {
4313 if (icmp->icmp_type != ICMP6_ECHO_REPLY)
4314 return (1);
4315 if (icmp->icmp_id == ic->ici_id)
4316 return (1);
4317 }
4318 }
4319 #endif
4320 return (0);
4321 }
4322
4323
4324 /*
4325 * IFNAMES are located in the variable length field starting at
4326 * frentry.fr_names. As pointers within the struct cannot be passed
4327 * to the kernel from ipf(8), an offset is used. An offset of -1 means it
4328 * is unused (invalid). If it is used (valid) it is an offset to the
4329 * character string of an interface name or a comment. The following
4330 * macros will assist those who follow to understand the code.
4331 */
4332 #define IPF_IFNAME_VALID(_a) (_a != -1)
4333 #define IPF_IFNAME_INVALID(_a) (_a == -1)
4334 #define IPF_IFNAMES_DIFFERENT(_a) \
4335 !((IPF_IFNAME_INVALID(fr1->_a) && \
4336 IPF_IFNAME_INVALID(fr2->_a)) || \
4337 (IPF_IFNAME_VALID(fr1->_a) && \
4338 IPF_IFNAME_VALID(fr2->_a) && \
4339 !strcmp(FR_NAME(fr1, _a), FR_NAME(fr2, _a))))
4340 #define IPF_FRDEST_DIFFERENT(_a) \
4341 (memcmp(&fr1->_a.fd_addr, &fr2->_a.fd_addr, \
4342 offsetof(frdest_t, fd_name) - offsetof(frdest_t, fd_addr)) || \
4343 IPF_IFNAMES_DIFFERENT(_a.fd_name))
4344
4345
4346 /* ------------------------------------------------------------------------ */
4347 /* Function: ipf_rule_compare */
4348 /* Parameters: fr1(I) - first rule structure to compare */
4349 /* fr2(I) - second rule structure to compare */
4350 /* Returns: int - 0 == rules are the same, else mismatch */
4351 /* */
4352 /* Compare two rules and return 0 if they match or a number indicating */
4353 /* which of the individual checks failed. */
4354 /* ------------------------------------------------------------------------ */
4355 static int
ipf_rule_compare(frentry_t * fr1,frentry_t * fr2)4356 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2)
4357 {
4358 int i;
4359
4360 if (fr1->fr_cksum != fr2->fr_cksum)
4361 return (1);
4362 if (fr1->fr_size != fr2->fr_size)
4363 return (2);
4364 if (fr1->fr_dsize != fr2->fr_dsize)
4365 return (3);
4366 if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func, FR_CMPSIZ)
4367 != 0)
4368 return (4);
4369 /*
4370 * XXX: There is still a bug here as different rules with the
4371 * the same interfaces but in a different order will compare
4372 * differently. But since multiple interfaces in a rule doesn't
4373 * work anyway a simple straightforward compare is performed
4374 * here. Ultimately frentry_t creation will need to be
4375 * revisited in ipf_y.y. While the other issue, recognition
4376 * of only the first interface in a list of interfaces will
4377 * need to be separately addressed along with why only four.
4378 */
4379 for (i = 0; i < FR_NUM(fr1->fr_ifnames); i++) {
4380 /*
4381 * XXX: It's either the same index or uninitialized.
4382 * We assume this because multiple interfaces
4383 * referenced by the same rule doesn't work anyway.
4384 */
4385 if (IPF_IFNAMES_DIFFERENT(fr_ifnames[i]))
4386 return (5);
4387 }
4388
4389 if (IPF_FRDEST_DIFFERENT(fr_tif))
4390 return (6);
4391 if (IPF_FRDEST_DIFFERENT(fr_rif))
4392 return (7);
4393 if (IPF_FRDEST_DIFFERENT(fr_dif))
4394 return (8);
4395 if (!fr1->fr_data && !fr2->fr_data)
4396 return (0); /* move along, nothing to see here */
4397 if (fr1->fr_data && fr2->fr_data) {
4398 if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize) == 0)
4399 return (0); /* same */
4400 }
4401 return (9);
4402 }
4403
4404
4405 /* ------------------------------------------------------------------------ */
4406 /* Function: frrequest */
4407 /* Returns: int - 0 == success, > 0 == errno value */
4408 /* Parameters: unit(I) - device for which this is for */
4409 /* req(I) - ioctl command (SIOC*) */
4410 /* data(I) - pointr to ioctl data */
4411 /* set(I) - 1 or 0 (filter set) */
4412 /* makecopy(I) - flag indicating whether data points to a rule */
4413 /* in kernel space & hence doesn't need copying. */
4414 /* */
4415 /* This function handles all the requests which operate on the list of */
4416 /* filter rules. This includes adding, deleting, insertion. It is also */
4417 /* responsible for creating groups when a "head" rule is loaded. Interface */
4418 /* names are resolved here and other sanity checks are made on the content */
4419 /* of the rule structure being loaded. If a rule has user defined timeouts */
4420 /* then make sure they are created and initialised before exiting. */
4421 /* ------------------------------------------------------------------------ */
4422 int
frrequest(ipf_main_softc_t * softc,int unit,ioctlcmd_t req,caddr_t data,int set,int makecopy)4423 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data,
4424 int set, int makecopy)
4425 {
4426 int error = 0, in, family, need_free = 0, interr, i;
4427 enum { OP_ADD, /* add rule */
4428 OP_REM, /* remove rule */
4429 OP_ZERO /* zero statistics and counters */ }
4430 addrem = OP_ADD;
4431 frentry_t frd, *fp, *f, **fprev, **ftail;
4432 void *ptr, *uptr;
4433 u_int *p, *pp;
4434 frgroup_t *fg;
4435 char *group;
4436
4437 ptr = NULL;
4438 fg = NULL;
4439 fp = &frd;
4440 if (makecopy != 0) {
4441 bzero(fp, sizeof(frd));
4442 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY);
4443 if (error) {
4444 return (error);
4445 }
4446 if ((fp->fr_type & FR_T_BUILTIN) != 0) {
4447 IPFERROR(6);
4448 return (EINVAL);
4449 }
4450 if (fp->fr_size < sizeof(frd)) {
4451 return (EINVAL);
4452 }
4453 if (sizeof(frd) + fp->fr_namelen != fp->fr_size ) {
4454 IPFERROR(155);
4455 return (EINVAL);
4456 }
4457 if (fp->fr_namelen < 0 || fp->fr_namelen > softc->ipf_max_namelen) {
4458 IPFERROR(156);
4459 return (EINVAL);
4460 }
4461 KMALLOCS(f, frentry_t *, fp->fr_size);
4462 if (f == NULL) {
4463 IPFERROR(131);
4464 return (ENOMEM);
4465 }
4466 bzero(f, fp->fr_size);
4467 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY,
4468 fp->fr_size);
4469 if (error) {
4470 KFREES(f, fp->fr_size);
4471 return (error);
4472 }
4473
4474 fp = f;
4475 f = NULL;
4476 fp->fr_next = NULL;
4477 fp->fr_dnext = NULL;
4478 fp->fr_pnext = NULL;
4479 fp->fr_pdnext = NULL;
4480 fp->fr_grp = NULL;
4481 fp->fr_grphead = NULL;
4482 fp->fr_icmpgrp = NULL;
4483 fp->fr_isc = (void *)-1;
4484 fp->fr_ptr = NULL;
4485 fp->fr_ref = 0;
4486 fp->fr_flags |= FR_COPIED;
4487
4488 for (i = 0; i <= 3; i++) {
4489 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_ifnames[i])) != 0) {
4490 IPFERROR(interr_tbl[interr-1]);
4491 error = EINVAL;
4492 goto donenolock;
4493 }
4494 }
4495 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_comment)) != 0) {
4496 IPFERROR(interr_tbl[interr-1]);
4497 error = EINVAL;
4498 goto donenolock;
4499 }
4500 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_group)) != 0) {
4501 IPFERROR(interr_tbl[interr-1]);
4502 error = EINVAL;
4503 goto donenolock;
4504 }
4505 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_grhead)) != 0) {
4506 IPFERROR(interr_tbl[interr-1]);
4507 error = EINVAL;
4508 goto donenolock;
4509 }
4510 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_tif.fd_name)) != 0) {
4511 IPFERROR(interr_tbl[interr-1]);
4512 error = EINVAL;
4513 goto donenolock;
4514 }
4515 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_rif.fd_name)) != 0) {
4516 IPFERROR(interr_tbl[interr-1]);
4517 error = EINVAL;
4518 goto donenolock;
4519 }
4520 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_dif.fd_name)) != 0) {
4521 IPFERROR(interr_tbl[interr-1]);
4522 error = EINVAL;
4523 goto donenolock;
4524 }
4525 } else {
4526 fp = (frentry_t *)data;
4527 if ((fp->fr_type & FR_T_BUILTIN) == 0) {
4528 IPFERROR(7);
4529 return (EINVAL);
4530 }
4531 fp->fr_flags &= ~FR_COPIED;
4532 }
4533
4534 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
4535 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) {
4536 IPFERROR(8);
4537 error = EINVAL;
4538 goto donenolock;
4539 }
4540
4541 family = fp->fr_family;
4542 uptr = fp->fr_data;
4543
4544 if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR ||
4545 req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR)
4546 addrem = OP_ADD; /* Add rule */
4547 else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR)
4548 addrem = OP_REM; /* Remove rule */
4549 else if (req == (ioctlcmd_t)SIOCZRLST)
4550 addrem = OP_ZERO; /* Zero statistics and counters */
4551 else {
4552 IPFERROR(9);
4553 error = EINVAL;
4554 goto donenolock;
4555 }
4556
4557 /*
4558 * Only filter rules for IPv4 or IPv6 are accepted.
4559 */
4560 if (family == AF_INET) {
4561 /*EMPTY*/;
4562 #ifdef USE_INET6
4563 } else if (family == AF_INET6) {
4564 /*EMPTY*/;
4565 #endif
4566 } else if (family != 0) {
4567 IPFERROR(10);
4568 error = EINVAL;
4569 goto donenolock;
4570 }
4571
4572 /*
4573 * If the rule is being loaded from user space, i.e. we had to copy it
4574 * into kernel space, then do not trust the function pointer in the
4575 * rule.
4576 */
4577 if ((makecopy == 1) && (fp->fr_func != NULL)) {
4578 if (ipf_findfunc(fp->fr_func) == NULL) {
4579 IPFERROR(11);
4580 error = ESRCH;
4581 goto donenolock;
4582 }
4583
4584 if (addrem == OP_ADD) {
4585 error = ipf_funcinit(softc, fp);
4586 if (error != 0)
4587 goto donenolock;
4588 }
4589 }
4590 if ((fp->fr_flags & FR_CALLNOW) &&
4591 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
4592 IPFERROR(142);
4593 error = ESRCH;
4594 goto donenolock;
4595 }
4596 if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) &&
4597 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
4598 IPFERROR(143);
4599 error = ESRCH;
4600 goto donenolock;
4601 }
4602
4603 ptr = NULL;
4604
4605 if (FR_ISACCOUNT(fp->fr_flags))
4606 unit = IPL_LOGCOUNT;
4607
4608 /*
4609 * Check that each group name in the rule has a start index that
4610 * is valid.
4611 */
4612 if (fp->fr_icmphead != -1) {
4613 if ((fp->fr_icmphead < 0) ||
4614 (fp->fr_icmphead >= fp->fr_namelen)) {
4615 IPFERROR(136);
4616 error = EINVAL;
4617 goto donenolock;
4618 }
4619 if (!strcmp(FR_NAME(fp, fr_icmphead), "0"))
4620 fp->fr_names[fp->fr_icmphead] = '\0';
4621 }
4622
4623 if (fp->fr_grhead != -1) {
4624 if ((fp->fr_grhead < 0) ||
4625 (fp->fr_grhead >= fp->fr_namelen)) {
4626 IPFERROR(137);
4627 error = EINVAL;
4628 goto donenolock;
4629 }
4630 if (!strcmp(FR_NAME(fp, fr_grhead), "0"))
4631 fp->fr_names[fp->fr_grhead] = '\0';
4632 }
4633
4634 if (fp->fr_group != -1) {
4635 if ((fp->fr_group < 0) ||
4636 (fp->fr_group >= fp->fr_namelen)) {
4637 IPFERROR(138);
4638 error = EINVAL;
4639 goto donenolock;
4640 }
4641 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) {
4642 /*
4643 * Allow loading rules that are in groups to cause
4644 * them to be created if they don't already exit.
4645 */
4646 group = FR_NAME(fp, fr_group);
4647 if (addrem == OP_ADD) {
4648 fg = ipf_group_add(softc, group, NULL,
4649 fp->fr_flags, unit, set);
4650 fp->fr_grp = fg;
4651 } else {
4652 fg = ipf_findgroup(softc, group, unit,
4653 set, NULL);
4654 if (fg == NULL) {
4655 IPFERROR(12);
4656 error = ESRCH;
4657 goto donenolock;
4658 }
4659 }
4660
4661 if (fg->fg_flags == 0) {
4662 fg->fg_flags = fp->fr_flags & FR_INOUT;
4663 } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) {
4664 IPFERROR(13);
4665 error = ESRCH;
4666 goto donenolock;
4667 }
4668 }
4669 } else {
4670 /*
4671 * If a rule is going to be part of a group then it does
4672 * not matter whether it is an in or out rule, but if it
4673 * isn't in a group, then it does...
4674 */
4675 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) {
4676 IPFERROR(14);
4677 error = EINVAL;
4678 goto donenolock;
4679 }
4680 }
4681 in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
4682
4683 /*
4684 * Work out which rule list this change is being applied to.
4685 */
4686 ftail = NULL;
4687 fprev = NULL;
4688 if (unit == IPL_LOGAUTH) {
4689 if ((fp->fr_tifs[0].fd_ptr != NULL) ||
4690 (fp->fr_tifs[1].fd_ptr != NULL) ||
4691 (fp->fr_dif.fd_ptr != NULL) ||
4692 (fp->fr_flags & FR_FASTROUTE)) {
4693 softc->ipf_interror = 145;
4694 error = EINVAL;
4695 goto donenolock;
4696 }
4697 fprev = ipf_auth_rulehead(softc);
4698 } else {
4699 if (FR_ISACCOUNT(fp->fr_flags))
4700 fprev = &softc->ipf_acct[in][set];
4701 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
4702 fprev = &softc->ipf_rules[in][set];
4703 }
4704 if (fprev == NULL) {
4705 IPFERROR(15);
4706 error = ESRCH;
4707 goto donenolock;
4708 }
4709
4710 if (fg != NULL)
4711 fprev = &fg->fg_start;
4712
4713 /*
4714 * Copy in extra data for the rule.
4715 */
4716 if (fp->fr_dsize != 0) {
4717 if (makecopy != 0) {
4718 KMALLOCS(ptr, void *, fp->fr_dsize);
4719 if (ptr == NULL) {
4720 IPFERROR(16);
4721 error = ENOMEM;
4722 goto donenolock;
4723 }
4724
4725 /*
4726 * The bcopy case is for when the data is appended
4727 * to the rule by ipf_in_compat().
4728 */
4729 if (uptr >= (void *)fp &&
4730 uptr < (void *)((char *)fp + fp->fr_size)) {
4731 bcopy(uptr, ptr, fp->fr_dsize);
4732 error = 0;
4733 } else {
4734 error = COPYIN(uptr, ptr, fp->fr_dsize);
4735 if (error != 0) {
4736 IPFERROR(17);
4737 error = EFAULT;
4738 goto donenolock;
4739 }
4740 }
4741 } else {
4742 ptr = uptr;
4743 }
4744 fp->fr_data = ptr;
4745 } else {
4746 fp->fr_data = NULL;
4747 }
4748
4749 /*
4750 * Perform per-rule type sanity checks of their members.
4751 * All code after this needs to be aware that allocated memory
4752 * may need to be free'd before exiting.
4753 */
4754 switch (fp->fr_type & ~FR_T_BUILTIN)
4755 {
4756 #if defined(IPFILTER_BPF)
4757 case FR_T_BPFOPC :
4758 if (fp->fr_dsize == 0) {
4759 IPFERROR(19);
4760 error = EINVAL;
4761 break;
4762 }
4763 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
4764 IPFERROR(20);
4765 error = EINVAL;
4766 break;
4767 }
4768 break;
4769 #endif
4770 case FR_T_IPF :
4771 /*
4772 * Preparation for error case at the bottom of this function.
4773 */
4774 if (fp->fr_datype == FRI_LOOKUP)
4775 fp->fr_dstptr = NULL;
4776 if (fp->fr_satype == FRI_LOOKUP)
4777 fp->fr_srcptr = NULL;
4778
4779 if (fp->fr_dsize != sizeof(fripf_t)) {
4780 IPFERROR(21);
4781 error = EINVAL;
4782 break;
4783 }
4784
4785 /*
4786 * Allowing a rule with both "keep state" and "with oow" is
4787 * pointless because adding a state entry to the table will
4788 * fail with the out of window (oow) flag set.
4789 */
4790 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) {
4791 IPFERROR(22);
4792 error = EINVAL;
4793 break;
4794 }
4795
4796 switch (fp->fr_satype)
4797 {
4798 case FRI_BROADCAST :
4799 case FRI_DYNAMIC :
4800 case FRI_NETWORK :
4801 case FRI_NETMASKED :
4802 case FRI_PEERADDR :
4803 if (fp->fr_sifpidx < 0) {
4804 IPFERROR(23);
4805 error = EINVAL;
4806 }
4807 break;
4808 case FRI_LOOKUP :
4809 fp->fr_srcptr = ipf_findlookup(softc, unit, fp,
4810 &fp->fr_src6,
4811 &fp->fr_smsk6);
4812 if (fp->fr_srcfunc == NULL) {
4813 IPFERROR(132);
4814 error = ESRCH;
4815 break;
4816 }
4817 break;
4818 case FRI_NORMAL :
4819 break;
4820 default :
4821 IPFERROR(133);
4822 error = EINVAL;
4823 break;
4824 }
4825 if (error != 0)
4826 break;
4827
4828 switch (fp->fr_datype)
4829 {
4830 case FRI_BROADCAST :
4831 case FRI_DYNAMIC :
4832 case FRI_NETWORK :
4833 case FRI_NETMASKED :
4834 case FRI_PEERADDR :
4835 if (fp->fr_difpidx < 0) {
4836 IPFERROR(24);
4837 error = EINVAL;
4838 }
4839 break;
4840 case FRI_LOOKUP :
4841 fp->fr_dstptr = ipf_findlookup(softc, unit, fp,
4842 &fp->fr_dst6,
4843 &fp->fr_dmsk6);
4844 if (fp->fr_dstfunc == NULL) {
4845 IPFERROR(134);
4846 error = ESRCH;
4847 }
4848 break;
4849 case FRI_NORMAL :
4850 break;
4851 default :
4852 IPFERROR(135);
4853 error = EINVAL;
4854 }
4855 break;
4856
4857 case FR_T_NONE :
4858 case FR_T_CALLFUNC :
4859 case FR_T_COMPIPF :
4860 break;
4861
4862 case FR_T_IPFEXPR :
4863 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) {
4864 IPFERROR(25);
4865 error = EINVAL;
4866 }
4867 break;
4868
4869 default :
4870 IPFERROR(26);
4871 error = EINVAL;
4872 break;
4873 }
4874 if (error != 0)
4875 goto donenolock;
4876
4877 if (fp->fr_tif.fd_name != -1) {
4878 if ((fp->fr_tif.fd_name < 0) ||
4879 (fp->fr_tif.fd_name >= fp->fr_namelen)) {
4880 IPFERROR(139);
4881 error = EINVAL;
4882 goto donenolock;
4883 }
4884 }
4885
4886 if (fp->fr_dif.fd_name != -1) {
4887 if ((fp->fr_dif.fd_name < 0) ||
4888 (fp->fr_dif.fd_name >= fp->fr_namelen)) {
4889 IPFERROR(140);
4890 error = EINVAL;
4891 goto donenolock;
4892 }
4893 }
4894
4895 if (fp->fr_rif.fd_name != -1) {
4896 if ((fp->fr_rif.fd_name < 0) ||
4897 (fp->fr_rif.fd_name >= fp->fr_namelen)) {
4898 IPFERROR(141);
4899 error = EINVAL;
4900 goto donenolock;
4901 }
4902 }
4903
4904 /*
4905 * Lookup all the interface names that are part of the rule.
4906 */
4907 error = ipf_synclist(softc, fp, NULL);
4908 if (error != 0)
4909 goto donenolock;
4910 fp->fr_statecnt = 0;
4911 if (fp->fr_srctrack.ht_max_nodes != 0)
4912 ipf_rb_ht_init(&fp->fr_srctrack);
4913
4914 /*
4915 * Look for an existing matching filter rule, but don't include the
4916 * next or interface pointer in the comparison (fr_next, fr_ifa).
4917 * This elminates rules which are indentical being loaded. Checksum
4918 * the constant part of the filter rule to make comparisons quicker
4919 * (this meaning no pointers are included).
4920 */
4921 pp = (u_int *)(fp->fr_caddr + fp->fr_dsize);
4922 for (fp->fr_cksum = 0, p = (u_int *)fp->fr_data; p < pp; p++)
4923 fp->fr_cksum += *p;
4924
4925 WRITE_ENTER(&softc->ipf_mutex);
4926
4927 /*
4928 * Now that the filter rule lists are locked, we can walk the
4929 * chain of them without fear.
4930 */
4931 ftail = fprev;
4932 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) {
4933 if (fp->fr_collect <= f->fr_collect) {
4934 ftail = fprev;
4935 f = NULL;
4936 break;
4937 }
4938 fprev = ftail;
4939 }
4940
4941 for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
4942 if (ipf_rule_compare(fp, f) == 0)
4943 break;
4944 }
4945
4946 /*
4947 * If zero'ing statistics, copy current to caller and zero.
4948 */
4949 if (addrem == OP_ZERO) {
4950 if (f == NULL) {
4951 IPFERROR(27);
4952 error = ESRCH;
4953 } else {
4954 /*
4955 * Copy and reduce lock because of impending copyout.
4956 * Well we should, but if we do then the atomicity of
4957 * this call and the correctness of fr_hits and
4958 * fr_bytes cannot be guaranteed. As it is, this code
4959 * only resets them to 0 if they are successfully
4960 * copied out into user space.
4961 */
4962 bcopy((char *)f, (char *)fp, f->fr_size);
4963 /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */
4964
4965 /*
4966 * When we copy this rule back out, set the data
4967 * pointer to be what it was in user space.
4968 */
4969 fp->fr_data = uptr;
4970 error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY);
4971
4972 if (error == 0) {
4973 if ((f->fr_dsize != 0) && (uptr != NULL)) {
4974 error = COPYOUT(f->fr_data, uptr,
4975 f->fr_dsize);
4976 if (error == 0) {
4977 f->fr_hits = 0;
4978 f->fr_bytes = 0;
4979 } else {
4980 IPFERROR(28);
4981 error = EFAULT;
4982 }
4983 }
4984 }
4985 }
4986
4987 if (makecopy != 0) {
4988 if (ptr != NULL) {
4989 KFREES(ptr, fp->fr_dsize);
4990 }
4991 KFREES(fp, fp->fr_size);
4992 }
4993 RWLOCK_EXIT(&softc->ipf_mutex);
4994 return (error);
4995 }
4996
4997 if (f == NULL) {
4998 /*
4999 * At the end of this, ftail must point to the place where the
5000 * new rule is to be saved/inserted/added.
5001 * For SIOCAD*FR, this should be the last rule in the group of
5002 * rules that have equal fr_collect fields.
5003 * For SIOCIN*FR, ...
5004 */
5005 if (req == (ioctlcmd_t)SIOCADAFR ||
5006 req == (ioctlcmd_t)SIOCADIFR) {
5007
5008 for (ftail = fprev; (f = *ftail) != NULL; ) {
5009 if (f->fr_collect > fp->fr_collect)
5010 break;
5011 ftail = &f->fr_next;
5012 fprev = ftail;
5013 }
5014 ftail = fprev;
5015 f = NULL;
5016 ptr = NULL;
5017 } else if (req == (ioctlcmd_t)SIOCINAFR ||
5018 req == (ioctlcmd_t)SIOCINIFR) {
5019 while ((f = *fprev) != NULL) {
5020 if (f->fr_collect >= fp->fr_collect)
5021 break;
5022 fprev = &f->fr_next;
5023 }
5024 ftail = fprev;
5025 if (fp->fr_hits != 0) {
5026 while (fp->fr_hits && (f = *ftail)) {
5027 if (f->fr_collect != fp->fr_collect)
5028 break;
5029 fprev = ftail;
5030 ftail = &f->fr_next;
5031 fp->fr_hits--;
5032 }
5033 }
5034 f = NULL;
5035 ptr = NULL;
5036 }
5037 }
5038
5039 /*
5040 * Request to remove a rule.
5041 */
5042 if (addrem == OP_REM) {
5043 if (f == NULL) {
5044 IPFERROR(29);
5045 error = ESRCH;
5046 } else {
5047 /*
5048 * Do not allow activity from user space to interfere
5049 * with rules not loaded that way.
5050 */
5051 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
5052 IPFERROR(30);
5053 error = EPERM;
5054 goto done;
5055 }
5056
5057 /*
5058 * Return EBUSY if the rule is being reference by
5059 * something else (eg state information.)
5060 */
5061 if (f->fr_ref > 1) {
5062 IPFERROR(31);
5063 error = EBUSY;
5064 goto done;
5065 }
5066 #ifdef IPFILTER_SCAN
5067 if (f->fr_isctag != -1 &&
5068 (f->fr_isc != (struct ipscan *)-1))
5069 ipf_scan_detachfr(f);
5070 #endif
5071
5072 if (unit == IPL_LOGAUTH) {
5073 error = ipf_auth_precmd(softc, req, f, ftail);
5074 goto done;
5075 }
5076
5077 ipf_rule_delete(softc, f, unit, set);
5078
5079 need_free = makecopy;
5080 }
5081 } else {
5082 /*
5083 * Not removing, so we must be adding/inserting a rule.
5084 */
5085 if (f != NULL) {
5086 IPFERROR(32);
5087 error = EEXIST;
5088 goto done;
5089 }
5090 if (unit == IPL_LOGAUTH) {
5091 error = ipf_auth_precmd(softc, req, fp, ftail);
5092 goto done;
5093 }
5094
5095 MUTEX_NUKE(&fp->fr_lock);
5096 MUTEX_INIT(&fp->fr_lock, "filter rule lock");
5097 if (fp->fr_die != 0)
5098 ipf_rule_expire_insert(softc, fp, set);
5099
5100 fp->fr_hits = 0;
5101 if (makecopy != 0)
5102 fp->fr_ref = 1;
5103 fp->fr_pnext = ftail;
5104 fp->fr_next = *ftail;
5105 if (fp->fr_next != NULL)
5106 fp->fr_next->fr_pnext = &fp->fr_next;
5107 *ftail = fp;
5108 ipf_fixskip(ftail, fp, 1);
5109
5110 fp->fr_icmpgrp = NULL;
5111 if (fp->fr_icmphead != -1) {
5112 group = FR_NAME(fp, fr_icmphead);
5113 fg = ipf_group_add(softc, group, fp, 0, unit, set);
5114 fp->fr_icmpgrp = fg;
5115 }
5116
5117 fp->fr_grphead = NULL;
5118 if (fp->fr_grhead != -1) {
5119 group = FR_NAME(fp, fr_grhead);
5120 fg = ipf_group_add(softc, group, fp, fp->fr_flags,
5121 unit, set);
5122 fp->fr_grphead = fg;
5123 }
5124 }
5125 done:
5126 RWLOCK_EXIT(&softc->ipf_mutex);
5127 donenolock:
5128 if (need_free || (error != 0)) {
5129 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
5130 if ((fp->fr_satype == FRI_LOOKUP) &&
5131 (fp->fr_srcptr != NULL))
5132 ipf_lookup_deref(softc, fp->fr_srctype,
5133 fp->fr_srcptr);
5134 if ((fp->fr_datype == FRI_LOOKUP) &&
5135 (fp->fr_dstptr != NULL))
5136 ipf_lookup_deref(softc, fp->fr_dsttype,
5137 fp->fr_dstptr);
5138 }
5139 if (fp->fr_grp != NULL) {
5140 WRITE_ENTER(&softc->ipf_mutex);
5141 ipf_group_del(softc, fp->fr_grp, fp);
5142 RWLOCK_EXIT(&softc->ipf_mutex);
5143 }
5144 if ((ptr != NULL) && (makecopy != 0)) {
5145 KFREES(ptr, fp->fr_dsize);
5146 }
5147 KFREES(fp, fp->fr_size);
5148 }
5149 return (error);
5150 }
5151
5152
5153 /* ------------------------------------------------------------------------ */
5154 /* Function: ipf_rule_delete */
5155 /* Returns: Nil */
5156 /* Parameters: softc(I) - pointer to soft context main structure */
5157 /* f(I) - pointer to the rule being deleted */
5158 /* ftail(I) - pointer to the pointer to f */
5159 /* unit(I) - device for which this is for */
5160 /* set(I) - 1 or 0 (filter set) */
5161 /* */
5162 /* This function attempts to do what it can to delete a filter rule: remove */
5163 /* it from any linked lists and remove any groups it is responsible for. */
5164 /* But in the end, removing a rule can only drop the reference count - we */
5165 /* must use that as the guide for whether or not it can be freed. */
5166 /* ------------------------------------------------------------------------ */
5167 static void
ipf_rule_delete(ipf_main_softc_t * softc,frentry_t * f,int unit,int set)5168 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set)
5169 {
5170
5171 /*
5172 * If fr_pdnext is set, then the rule is on the expire list, so
5173 * remove it from there.
5174 */
5175 if (f->fr_pdnext != NULL) {
5176 *f->fr_pdnext = f->fr_dnext;
5177 if (f->fr_dnext != NULL)
5178 f->fr_dnext->fr_pdnext = f->fr_pdnext;
5179 f->fr_pdnext = NULL;
5180 f->fr_dnext = NULL;
5181 }
5182
5183 ipf_fixskip(f->fr_pnext, f, -1);
5184 if (f->fr_pnext != NULL)
5185 *f->fr_pnext = f->fr_next;
5186 if (f->fr_next != NULL)
5187 f->fr_next->fr_pnext = f->fr_pnext;
5188 f->fr_pnext = NULL;
5189 f->fr_next = NULL;
5190
5191 (void) ipf_derefrule(softc, &f);
5192 }
5193
5194 /* ------------------------------------------------------------------------ */
5195 /* Function: ipf_rule_expire_insert */
5196 /* Returns: Nil */
5197 /* Parameters: softc(I) - pointer to soft context main structure */
5198 /* f(I) - pointer to rule to be added to expire list */
5199 /* set(I) - 1 or 0 (filter set) */
5200 /* */
5201 /* If the new rule has a given expiration time, insert it into the list of */
5202 /* expiring rules with the ones to be removed first added to the front of */
5203 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */
5204 /* expiration interval checks. */
5205 /* ------------------------------------------------------------------------ */
5206 static void
ipf_rule_expire_insert(ipf_main_softc_t * softc,frentry_t * f,int set)5207 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set)
5208 {
5209 frentry_t *fr;
5210
5211 /*
5212 */
5213
5214 f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die);
5215 for (fr = softc->ipf_rule_explist[set]; fr != NULL;
5216 fr = fr->fr_dnext) {
5217 if (f->fr_die < fr->fr_die)
5218 break;
5219 if (fr->fr_dnext == NULL) {
5220 /*
5221 * We've got to the last rule and everything
5222 * wanted to be expired before this new node,
5223 * so we have to tack it on the end...
5224 */
5225 fr->fr_dnext = f;
5226 f->fr_pdnext = &fr->fr_dnext;
5227 fr = NULL;
5228 break;
5229 }
5230 }
5231
5232 if (softc->ipf_rule_explist[set] == NULL) {
5233 softc->ipf_rule_explist[set] = f;
5234 f->fr_pdnext = &softc->ipf_rule_explist[set];
5235 } else if (fr != NULL) {
5236 f->fr_dnext = fr;
5237 f->fr_pdnext = fr->fr_pdnext;
5238 fr->fr_pdnext = &f->fr_dnext;
5239 }
5240 }
5241
5242
5243 /* ------------------------------------------------------------------------ */
5244 /* Function: ipf_findlookup */
5245 /* Returns: NULL = failure, else success */
5246 /* Parameters: softc(I) - pointer to soft context main structure */
5247 /* unit(I) - ipf device we want to find match for */
5248 /* fp(I) - rule for which lookup is for */
5249 /* addrp(I) - pointer to lookup information in address struct */
5250 /* maskp(O) - pointer to lookup information for storage */
5251 /* */
5252 /* When using pools and hash tables to store addresses for matching in */
5253 /* rules, it is necessary to resolve both the object referred to by the */
5254 /* name or address (and return that pointer) and also provide the means by */
5255 /* which to determine if an address belongs to that object to make the */
5256 /* packet matching quicker. */
5257 /* ------------------------------------------------------------------------ */
5258 static void *
ipf_findlookup(ipf_main_softc_t * softc,int unit,frentry_t * fr,i6addr_t * addrp,i6addr_t * maskp)5259 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr,
5260 i6addr_t *addrp, i6addr_t *maskp)
5261 {
5262 void *ptr = NULL;
5263
5264 switch (addrp->iplookupsubtype)
5265 {
5266 case 0 :
5267 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype,
5268 addrp->iplookupnum,
5269 &maskp->iplookupfunc);
5270 break;
5271 case 1 :
5272 if (addrp->iplookupname < 0)
5273 break;
5274 if (addrp->iplookupname >= fr->fr_namelen)
5275 break;
5276 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype,
5277 fr->fr_names + addrp->iplookupname,
5278 &maskp->iplookupfunc);
5279 break;
5280 default :
5281 break;
5282 }
5283
5284 return (ptr);
5285 }
5286
5287
5288 /* ------------------------------------------------------------------------ */
5289 /* Function: ipf_funcinit */
5290 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */
5291 /* Parameters: softc(I) - pointer to soft context main structure */
5292 /* fr(I) - pointer to filter rule */
5293 /* */
5294 /* If a rule is a call rule, then check if the function it points to needs */
5295 /* an init function to be called now the rule has been loaded. */
5296 /* ------------------------------------------------------------------------ */
5297 static int
ipf_funcinit(ipf_main_softc_t * softc,frentry_t * fr)5298 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr)
5299 {
5300 ipfunc_resolve_t *ft;
5301 int err;
5302
5303 IPFERROR(34);
5304 err = ESRCH;
5305
5306 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5307 if (ft->ipfu_addr == fr->fr_func) {
5308 err = 0;
5309 if (ft->ipfu_init != NULL)
5310 err = (*ft->ipfu_init)(softc, fr);
5311 break;
5312 }
5313 return (err);
5314 }
5315
5316
5317 /* ------------------------------------------------------------------------ */
5318 /* Function: ipf_funcfini */
5319 /* Returns: Nil */
5320 /* Parameters: softc(I) - pointer to soft context main structure */
5321 /* fr(I) - pointer to filter rule */
5322 /* */
5323 /* For a given filter rule, call the matching "fini" function if the rule */
5324 /* is using a known function that would have resulted in the "init" being */
5325 /* called for ealier. */
5326 /* ------------------------------------------------------------------------ */
5327 static void
ipf_funcfini(ipf_main_softc_t * softc,frentry_t * fr)5328 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr)
5329 {
5330 ipfunc_resolve_t *ft;
5331
5332 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5333 if (ft->ipfu_addr == fr->fr_func) {
5334 if (ft->ipfu_fini != NULL)
5335 (void) (*ft->ipfu_fini)(softc, fr);
5336 break;
5337 }
5338 }
5339
5340
5341 /* ------------------------------------------------------------------------ */
5342 /* Function: ipf_findfunc */
5343 /* Returns: ipfunc_t - pointer to function if found, else NULL */
5344 /* Parameters: funcptr(I) - function pointer to lookup */
5345 /* */
5346 /* Look for a function in the table of known functions. */
5347 /* ------------------------------------------------------------------------ */
5348 static ipfunc_t
ipf_findfunc(ipfunc_t funcptr)5349 ipf_findfunc(ipfunc_t funcptr)
5350 {
5351 ipfunc_resolve_t *ft;
5352
5353 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5354 if (ft->ipfu_addr == funcptr)
5355 return (funcptr);
5356 return (NULL);
5357 }
5358
5359
5360 /* ------------------------------------------------------------------------ */
5361 /* Function: ipf_resolvefunc */
5362 /* Returns: int - 0 == success, else error */
5363 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */
5364 /* */
5365 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */
5366 /* This will either be the function name (if the pointer is set) or the */
5367 /* function pointer if the name is set. When found, fill in the other one */
5368 /* so that the entire, complete, structure can be copied back to user space.*/
5369 /* ------------------------------------------------------------------------ */
5370 int
ipf_resolvefunc(ipf_main_softc_t * softc,void * data)5371 ipf_resolvefunc(ipf_main_softc_t *softc, void *data)
5372 {
5373 ipfunc_resolve_t res, *ft;
5374 int error;
5375
5376 error = BCOPYIN(data, &res, sizeof(res));
5377 if (error != 0) {
5378 IPFERROR(123);
5379 return (EFAULT);
5380 }
5381
5382 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
5383 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5384 if (strncmp(res.ipfu_name, ft->ipfu_name,
5385 sizeof(res.ipfu_name)) == 0) {
5386 res.ipfu_addr = ft->ipfu_addr;
5387 res.ipfu_init = ft->ipfu_init;
5388 if (COPYOUT(&res, data, sizeof(res)) != 0) {
5389 IPFERROR(35);
5390 return (EFAULT);
5391 }
5392 return (0);
5393 }
5394 }
5395 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
5396 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5397 if (ft->ipfu_addr == res.ipfu_addr) {
5398 (void) strncpy(res.ipfu_name, ft->ipfu_name,
5399 sizeof(res.ipfu_name));
5400 res.ipfu_init = ft->ipfu_init;
5401 if (COPYOUT(&res, data, sizeof(res)) != 0) {
5402 IPFERROR(36);
5403 return (EFAULT);
5404 }
5405 return (0);
5406 }
5407 }
5408 IPFERROR(37);
5409 return (ESRCH);
5410 }
5411
5412
5413 #if !defined(_KERNEL) || SOLARIS
5414 /*
5415 * From: NetBSD
5416 * ppsratecheck(): packets (or events) per second limitation.
5417 */
5418 int
ppsratecheck(struct timeval * lasttime,int * curpps,int maxpps)5419 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
5420 /* maxpps: maximum pps allowed */
5421 {
5422 struct timeval tv, delta;
5423 int rv;
5424
5425 GETKTIME(&tv);
5426
5427 delta.tv_sec = tv.tv_sec - lasttime->tv_sec;
5428 delta.tv_usec = tv.tv_usec - lasttime->tv_usec;
5429 if (delta.tv_usec < 0) {
5430 delta.tv_sec--;
5431 delta.tv_usec += 1000000;
5432 }
5433
5434 /*
5435 * check for 0,0 is so that the message will be seen at least once.
5436 * if more than one second have passed since the last update of
5437 * lasttime, reset the counter.
5438 *
5439 * we do increment *curpps even in *curpps < maxpps case, as some may
5440 * try to use *curpps for stat purposes as well.
5441 */
5442 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
5443 delta.tv_sec >= 1) {
5444 *lasttime = tv;
5445 *curpps = 0;
5446 rv = 1;
5447 } else if (maxpps < 0)
5448 rv = 1;
5449 else if (*curpps < maxpps)
5450 rv = 1;
5451 else
5452 rv = 0;
5453 *curpps = *curpps + 1;
5454
5455 return (rv);
5456 }
5457 #endif
5458
5459
5460 /* ------------------------------------------------------------------------ */
5461 /* Function: ipf_derefrule */
5462 /* Returns: int - 0 == rule freed up, else rule not freed */
5463 /* Parameters: fr(I) - pointer to filter rule */
5464 /* */
5465 /* Decrement the reference counter to a rule by one. If it reaches zero, */
5466 /* free it and any associated storage space being used by it. */
5467 /* ------------------------------------------------------------------------ */
5468 int
ipf_derefrule(ipf_main_softc_t * softc,frentry_t ** frp)5469 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp)
5470 {
5471 frentry_t *fr;
5472 frdest_t *fdp;
5473
5474 fr = *frp;
5475 *frp = NULL;
5476
5477 MUTEX_ENTER(&fr->fr_lock);
5478 fr->fr_ref--;
5479 if (fr->fr_ref == 0) {
5480 MUTEX_EXIT(&fr->fr_lock);
5481 MUTEX_DESTROY(&fr->fr_lock);
5482
5483 ipf_funcfini(softc, fr);
5484
5485 fdp = &fr->fr_tif;
5486 if (fdp->fd_type == FRD_DSTLIST)
5487 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5488
5489 fdp = &fr->fr_rif;
5490 if (fdp->fd_type == FRD_DSTLIST)
5491 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5492
5493 fdp = &fr->fr_dif;
5494 if (fdp->fd_type == FRD_DSTLIST)
5495 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5496
5497 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
5498 fr->fr_satype == FRI_LOOKUP)
5499 ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr);
5500 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
5501 fr->fr_datype == FRI_LOOKUP)
5502 ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr);
5503
5504 if (fr->fr_grp != NULL)
5505 ipf_group_del(softc, fr->fr_grp, fr);
5506
5507 if (fr->fr_grphead != NULL)
5508 ipf_group_del(softc, fr->fr_grphead, fr);
5509
5510 if (fr->fr_icmpgrp != NULL)
5511 ipf_group_del(softc, fr->fr_icmpgrp, fr);
5512
5513 if ((fr->fr_flags & FR_COPIED) != 0) {
5514 if (fr->fr_dsize) {
5515 KFREES(fr->fr_data, fr->fr_dsize);
5516 }
5517 KFREES(fr, fr->fr_size);
5518 return (0);
5519 }
5520 return (1);
5521 } else {
5522 MUTEX_EXIT(&fr->fr_lock);
5523 }
5524 return (-1);
5525 }
5526
5527
5528 /* ------------------------------------------------------------------------ */
5529 /* Function: ipf_grpmapinit */
5530 /* Returns: int - 0 == success, else ESRCH because table entry not found*/
5531 /* Parameters: fr(I) - pointer to rule to find hash table for */
5532 /* */
5533 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */
5534 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */
5535 /* ------------------------------------------------------------------------ */
5536 static int
ipf_grpmapinit(ipf_main_softc_t * softc,frentry_t * fr)5537 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr)
5538 {
5539 char name[FR_GROUPLEN];
5540 iphtable_t *iph;
5541
5542 (void) snprintf(name, sizeof(name), "%d", fr->fr_arg);
5543 iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name);
5544 if (iph == NULL) {
5545 IPFERROR(38);
5546 return (ESRCH);
5547 }
5548 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) {
5549 IPFERROR(39);
5550 return (ESRCH);
5551 }
5552 iph->iph_ref++;
5553 fr->fr_ptr = iph;
5554 return (0);
5555 }
5556
5557
5558 /* ------------------------------------------------------------------------ */
5559 /* Function: ipf_grpmapfini */
5560 /* Returns: int - 0 == success, else ESRCH because table entry not found*/
5561 /* Parameters: softc(I) - pointer to soft context main structure */
5562 /* fr(I) - pointer to rule to release hash table for */
5563 /* */
5564 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */
5565 /* be called to undo what ipf_grpmapinit caused to be done. */
5566 /* ------------------------------------------------------------------------ */
5567 static int
ipf_grpmapfini(ipf_main_softc_t * softc,frentry_t * fr)5568 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr)
5569 {
5570 iphtable_t *iph;
5571 iph = fr->fr_ptr;
5572 if (iph != NULL)
5573 ipf_lookup_deref(softc, IPLT_HASH, iph);
5574 return (0);
5575 }
5576
5577
5578 /* ------------------------------------------------------------------------ */
5579 /* Function: ipf_srcgrpmap */
5580 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
5581 /* Parameters: fin(I) - pointer to packet information */
5582 /* passp(IO) - pointer to current/new filter decision (unused) */
5583 /* */
5584 /* Look for a rule group head in a hash table, using the source address as */
5585 /* the key, and descend into that group and continue matching rules against */
5586 /* the packet. */
5587 /* ------------------------------------------------------------------------ */
5588 frentry_t *
ipf_srcgrpmap(fr_info_t * fin,u_32_t * passp)5589 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp)
5590 {
5591 frgroup_t *fg;
5592 void *rval;
5593
5594 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
5595 &fin->fin_src);
5596 if (rval == NULL)
5597 return (NULL);
5598
5599 fg = rval;
5600 fin->fin_fr = fg->fg_start;
5601 (void) ipf_scanlist(fin, *passp);
5602 return (fin->fin_fr);
5603 }
5604
5605
5606 /* ------------------------------------------------------------------------ */
5607 /* Function: ipf_dstgrpmap */
5608 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
5609 /* Parameters: fin(I) - pointer to packet information */
5610 /* passp(IO) - pointer to current/new filter decision (unused) */
5611 /* */
5612 /* Look for a rule group head in a hash table, using the destination */
5613 /* address as the key, and descend into that group and continue matching */
5614 /* rules against the packet. */
5615 /* ------------------------------------------------------------------------ */
5616 frentry_t *
ipf_dstgrpmap(fr_info_t * fin,u_32_t * passp)5617 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp)
5618 {
5619 frgroup_t *fg;
5620 void *rval;
5621
5622 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
5623 &fin->fin_dst);
5624 if (rval == NULL)
5625 return (NULL);
5626
5627 fg = rval;
5628 fin->fin_fr = fg->fg_start;
5629 (void) ipf_scanlist(fin, *passp);
5630 return (fin->fin_fr);
5631 }
5632
5633 /*
5634 * Queue functions
5635 * ===============
5636 * These functions manage objects on queues for efficient timeouts. There
5637 * are a number of system defined queues as well as user defined timeouts.
5638 * It is expected that a lock is held in the domain in which the queue
5639 * belongs (i.e. either state or NAT) when calling any of these functions
5640 * that prevents ipf_freetimeoutqueue() from being called at the same time
5641 * as any other.
5642 */
5643
5644
5645 /* ------------------------------------------------------------------------ */
5646 /* Function: ipf_addtimeoutqueue */
5647 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */
5648 /* timeout queue with given interval. */
5649 /* Parameters: parent(I) - pointer to pointer to parent node of this list */
5650 /* of interface queues. */
5651 /* seconds(I) - timeout value in seconds for this queue. */
5652 /* */
5653 /* This routine first looks for a timeout queue that matches the interval */
5654 /* being requested. If it finds one, increments the reference counter and */
5655 /* returns a pointer to it. If none are found, it allocates a new one and */
5656 /* inserts it at the top of the list. */
5657 /* */
5658 /* Locking. */
5659 /* It is assumed that the caller of this function has an appropriate lock */
5660 /* held (exclusively) in the domain that encompases 'parent'. */
5661 /* ------------------------------------------------------------------------ */
5662 ipftq_t *
ipf_addtimeoutqueue(ipf_main_softc_t * softc,ipftq_t ** parent,u_int seconds)5663 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds)
5664 {
5665 ipftq_t *ifq;
5666 u_int period;
5667
5668 period = seconds * IPF_HZ_DIVIDE;
5669
5670 MUTEX_ENTER(&softc->ipf_timeoutlock);
5671 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
5672 if (ifq->ifq_ttl == period) {
5673 /*
5674 * Reset the delete flag, if set, so the structure
5675 * gets reused rather than freed and reallocated.
5676 */
5677 MUTEX_ENTER(&ifq->ifq_lock);
5678 ifq->ifq_flags &= ~IFQF_DELETE;
5679 ifq->ifq_ref++;
5680 MUTEX_EXIT(&ifq->ifq_lock);
5681 MUTEX_EXIT(&softc->ipf_timeoutlock);
5682
5683 return (ifq);
5684 }
5685 }
5686
5687 KMALLOC(ifq, ipftq_t *);
5688 if (ifq != NULL) {
5689 MUTEX_NUKE(&ifq->ifq_lock);
5690 IPFTQ_INIT(ifq, period, "ipftq mutex");
5691 ifq->ifq_next = *parent;
5692 ifq->ifq_pnext = parent;
5693 ifq->ifq_flags = IFQF_USER;
5694 ifq->ifq_ref++;
5695 *parent = ifq;
5696 softc->ipf_userifqs++;
5697 }
5698 MUTEX_EXIT(&softc->ipf_timeoutlock);
5699 return (ifq);
5700 }
5701
5702
5703 /* ------------------------------------------------------------------------ */
5704 /* Function: ipf_deletetimeoutqueue */
5705 /* Returns: int - new reference count value of the timeout queue */
5706 /* Parameters: ifq(I) - timeout queue which is losing a reference. */
5707 /* Locks: ifq->ifq_lock */
5708 /* */
5709 /* This routine must be called when we're discarding a pointer to a timeout */
5710 /* queue object, taking care of the reference counter. */
5711 /* */
5712 /* Now that this just sets a DELETE flag, it requires the expire code to */
5713 /* check the list of user defined timeout queues and call the free function */
5714 /* below (currently commented out) to stop memory leaking. It is done this */
5715 /* way because the locking may not be sufficient to safely do a free when */
5716 /* this function is called. */
5717 /* ------------------------------------------------------------------------ */
5718 int
ipf_deletetimeoutqueue(ipftq_t * ifq)5719 ipf_deletetimeoutqueue(ipftq_t *ifq)
5720 {
5721
5722 ifq->ifq_ref--;
5723 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) {
5724 ifq->ifq_flags |= IFQF_DELETE;
5725 }
5726
5727 return (ifq->ifq_ref);
5728 }
5729
5730
5731 /* ------------------------------------------------------------------------ */
5732 /* Function: ipf_freetimeoutqueue */
5733 /* Parameters: ifq(I) - timeout queue which is losing a reference. */
5734 /* Returns: Nil */
5735 /* */
5736 /* Locking: */
5737 /* It is assumed that the caller of this function has an appropriate lock */
5738 /* held (exclusively) in the domain that encompases the callers "domain". */
5739 /* The ifq_lock for this structure should not be held. */
5740 /* */
5741 /* Remove a user defined timeout queue from the list of queues it is in and */
5742 /* tidy up after this is done. */
5743 /* ------------------------------------------------------------------------ */
5744 void
ipf_freetimeoutqueue(ipf_main_softc_t * softc,ipftq_t * ifq)5745 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq)
5746 {
5747
5748 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
5749 ((ifq->ifq_flags & IFQF_USER) == 0)) {
5750 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
5751 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
5752 ifq->ifq_ref);
5753 return;
5754 }
5755
5756 /*
5757 * Remove from its position in the list.
5758 */
5759 *ifq->ifq_pnext = ifq->ifq_next;
5760 if (ifq->ifq_next != NULL)
5761 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
5762 ifq->ifq_next = NULL;
5763 ifq->ifq_pnext = NULL;
5764
5765 MUTEX_DESTROY(&ifq->ifq_lock);
5766 ATOMIC_DEC(softc->ipf_userifqs);
5767 KFREE(ifq);
5768 }
5769
5770
5771 /* ------------------------------------------------------------------------ */
5772 /* Function: ipf_deletequeueentry */
5773 /* Returns: Nil */
5774 /* Parameters: tqe(I) - timeout queue entry to delete */
5775 /* */
5776 /* Remove a tail queue entry from its queue and make it an orphan. */
5777 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */
5778 /* queue is correct. We can't, however, call ipf_freetimeoutqueue because */
5779 /* the correct lock(s) may not be held that would make it safe to do so. */
5780 /* ------------------------------------------------------------------------ */
5781 void
ipf_deletequeueentry(ipftqent_t * tqe)5782 ipf_deletequeueentry(ipftqent_t *tqe)
5783 {
5784 ipftq_t *ifq;
5785
5786 ifq = tqe->tqe_ifq;
5787
5788 MUTEX_ENTER(&ifq->ifq_lock);
5789
5790 if (tqe->tqe_pnext != NULL) {
5791 *tqe->tqe_pnext = tqe->tqe_next;
5792 if (tqe->tqe_next != NULL)
5793 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5794 else /* we must be the tail anyway */
5795 ifq->ifq_tail = tqe->tqe_pnext;
5796
5797 tqe->tqe_pnext = NULL;
5798 tqe->tqe_ifq = NULL;
5799 }
5800
5801 (void) ipf_deletetimeoutqueue(ifq);
5802 ASSERT(ifq->ifq_ref > 0);
5803
5804 MUTEX_EXIT(&ifq->ifq_lock);
5805 }
5806
5807
5808 /* ------------------------------------------------------------------------ */
5809 /* Function: ipf_queuefront */
5810 /* Returns: Nil */
5811 /* Parameters: tqe(I) - pointer to timeout queue entry */
5812 /* */
5813 /* Move a queue entry to the front of the queue, if it isn't already there. */
5814 /* ------------------------------------------------------------------------ */
5815 void
ipf_queuefront(ipftqent_t * tqe)5816 ipf_queuefront(ipftqent_t *tqe)
5817 {
5818 ipftq_t *ifq;
5819
5820 ifq = tqe->tqe_ifq;
5821 if (ifq == NULL)
5822 return;
5823
5824 MUTEX_ENTER(&ifq->ifq_lock);
5825 if (ifq->ifq_head != tqe) {
5826 *tqe->tqe_pnext = tqe->tqe_next;
5827 if (tqe->tqe_next)
5828 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5829 else
5830 ifq->ifq_tail = tqe->tqe_pnext;
5831
5832 tqe->tqe_next = ifq->ifq_head;
5833 ifq->ifq_head->tqe_pnext = &tqe->tqe_next;
5834 ifq->ifq_head = tqe;
5835 tqe->tqe_pnext = &ifq->ifq_head;
5836 }
5837 MUTEX_EXIT(&ifq->ifq_lock);
5838 }
5839
5840
5841 /* ------------------------------------------------------------------------ */
5842 /* Function: ipf_queueback */
5843 /* Returns: Nil */
5844 /* Parameters: ticks(I) - ipf tick time to use with this call */
5845 /* tqe(I) - pointer to timeout queue entry */
5846 /* */
5847 /* Move a queue entry to the back of the queue, if it isn't already there. */
5848 /* We use use ticks to calculate the expiration and mark for when we last */
5849 /* touched the structure. */
5850 /* ------------------------------------------------------------------------ */
5851 void
ipf_queueback(u_long ticks,ipftqent_t * tqe)5852 ipf_queueback(u_long ticks, ipftqent_t *tqe)
5853 {
5854 ipftq_t *ifq;
5855
5856 ifq = tqe->tqe_ifq;
5857 if (ifq == NULL)
5858 return;
5859 tqe->tqe_die = ticks + ifq->ifq_ttl;
5860 tqe->tqe_touched = ticks;
5861
5862 MUTEX_ENTER(&ifq->ifq_lock);
5863 if (tqe->tqe_next != NULL) { /* at the end already ? */
5864 /*
5865 * Remove from list
5866 */
5867 *tqe->tqe_pnext = tqe->tqe_next;
5868 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5869
5870 /*
5871 * Make it the last entry.
5872 */
5873 tqe->tqe_next = NULL;
5874 tqe->tqe_pnext = ifq->ifq_tail;
5875 *ifq->ifq_tail = tqe;
5876 ifq->ifq_tail = &tqe->tqe_next;
5877 }
5878 MUTEX_EXIT(&ifq->ifq_lock);
5879 }
5880
5881
5882 /* ------------------------------------------------------------------------ */
5883 /* Function: ipf_queueappend */
5884 /* Returns: Nil */
5885 /* Parameters: ticks(I) - ipf tick time to use with this call */
5886 /* tqe(I) - pointer to timeout queue entry */
5887 /* ifq(I) - pointer to timeout queue */
5888 /* parent(I) - owing object pointer */
5889 /* */
5890 /* Add a new item to this queue and put it on the very end. */
5891 /* We use use ticks to calculate the expiration and mark for when we last */
5892 /* touched the structure. */
5893 /* ------------------------------------------------------------------------ */
5894 void
ipf_queueappend(u_long ticks,ipftqent_t * tqe,ipftq_t * ifq,void * parent)5895 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent)
5896 {
5897
5898 MUTEX_ENTER(&ifq->ifq_lock);
5899 tqe->tqe_parent = parent;
5900 tqe->tqe_pnext = ifq->ifq_tail;
5901 *ifq->ifq_tail = tqe;
5902 ifq->ifq_tail = &tqe->tqe_next;
5903 tqe->tqe_next = NULL;
5904 tqe->tqe_ifq = ifq;
5905 tqe->tqe_die = ticks + ifq->ifq_ttl;
5906 tqe->tqe_touched = ticks;
5907 ifq->ifq_ref++;
5908 MUTEX_EXIT(&ifq->ifq_lock);
5909 }
5910
5911
5912 /* ------------------------------------------------------------------------ */
5913 /* Function: ipf_movequeue */
5914 /* Returns: Nil */
5915 /* Parameters: tq(I) - pointer to timeout queue information */
5916 /* oifp(I) - old timeout queue entry was on */
5917 /* nifp(I) - new timeout queue to put entry on */
5918 /* */
5919 /* Move a queue entry from one timeout queue to another timeout queue. */
5920 /* If it notices that the current entry is already last and does not need */
5921 /* to move queue, the return. */
5922 /* ------------------------------------------------------------------------ */
5923 void
ipf_movequeue(u_long ticks,ipftqent_t * tqe,ipftq_t * oifq,ipftq_t * nifq)5924 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq)
5925 {
5926
5927 /*
5928 * If the queue hasn't changed and we last touched this entry at the
5929 * same ipf time, then we're not going to achieve anything by either
5930 * changing the ttl or moving it on the queue.
5931 */
5932 if (oifq == nifq && tqe->tqe_touched == ticks)
5933 return;
5934
5935 /*
5936 * For any of this to be outside the lock, there is a risk that two
5937 * packets entering simultaneously, with one changing to a different
5938 * queue and one not, could end up with things in a bizarre state.
5939 */
5940 MUTEX_ENTER(&oifq->ifq_lock);
5941
5942 tqe->tqe_touched = ticks;
5943 tqe->tqe_die = ticks + nifq->ifq_ttl;
5944 /*
5945 * Is the operation here going to be a no-op ?
5946 */
5947 if (oifq == nifq) {
5948 if ((tqe->tqe_next == NULL) ||
5949 (tqe->tqe_next->tqe_die == tqe->tqe_die)) {
5950 MUTEX_EXIT(&oifq->ifq_lock);
5951 return;
5952 }
5953 }
5954
5955 /*
5956 * Remove from the old queue
5957 */
5958 *tqe->tqe_pnext = tqe->tqe_next;
5959 if (tqe->tqe_next)
5960 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5961 else
5962 oifq->ifq_tail = tqe->tqe_pnext;
5963 tqe->tqe_next = NULL;
5964
5965 /*
5966 * If we're moving from one queue to another, release the
5967 * lock on the old queue and get a lock on the new queue.
5968 * For user defined queues, if we're moving off it, call
5969 * delete in case it can now be freed.
5970 */
5971 if (oifq != nifq) {
5972 tqe->tqe_ifq = NULL;
5973
5974 (void) ipf_deletetimeoutqueue(oifq);
5975
5976 MUTEX_EXIT(&oifq->ifq_lock);
5977
5978 MUTEX_ENTER(&nifq->ifq_lock);
5979
5980 tqe->tqe_ifq = nifq;
5981 nifq->ifq_ref++;
5982 }
5983
5984 /*
5985 * Add to the bottom of the new queue
5986 */
5987 tqe->tqe_pnext = nifq->ifq_tail;
5988 *nifq->ifq_tail = tqe;
5989 nifq->ifq_tail = &tqe->tqe_next;
5990 MUTEX_EXIT(&nifq->ifq_lock);
5991 }
5992
5993
5994 /* ------------------------------------------------------------------------ */
5995 /* Function: ipf_updateipid */
5996 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */
5997 /* Parameters: fin(I) - pointer to packet information */
5998 /* */
5999 /* When we are doing NAT, change the IP of every packet to represent a */
6000 /* single sequence of packets coming from the host, hiding any host */
6001 /* specific sequencing that might otherwise be revealed. If the packet is */
6002 /* a fragment, then store the 'new' IPid in the fragment cache and look up */
6003 /* the fragment cache for non-leading fragments. If a non-leading fragment */
6004 /* has no match in the cache, return an error. */
6005 /* ------------------------------------------------------------------------ */
6006 static int
ipf_updateipid(fr_info_t * fin)6007 ipf_updateipid(fr_info_t *fin)
6008 {
6009 u_short id, ido, sums;
6010 u_32_t sumd, sum;
6011 ip_t *ip;
6012
6013 ip = fin->fin_ip;
6014 ido = ntohs(ip->ip_id);
6015 if (fin->fin_off != 0) {
6016 sum = ipf_frag_ipidknown(fin);
6017 if (sum == 0xffffffff)
6018 return (-1);
6019 sum &= 0xffff;
6020 id = (u_short)sum;
6021 ip->ip_id = htons(id);
6022 } else {
6023 ip_fillid(ip, V_ip_random_id);
6024 id = ntohs(ip->ip_id);
6025 if ((fin->fin_flx & FI_FRAG) != 0)
6026 (void) ipf_frag_ipidnew(fin, (u_32_t)id);
6027 }
6028
6029 if (id == ido)
6030 return (0);
6031 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */
6032 sum = (~ntohs(ip->ip_sum)) & 0xffff;
6033 sum += sumd;
6034 sum = (sum >> 16) + (sum & 0xffff);
6035 sum = (sum >> 16) + (sum & 0xffff);
6036 sums = ~(u_short)sum;
6037 ip->ip_sum = htons(sums);
6038 return (0);
6039 }
6040
6041
6042 #ifdef NEED_FRGETIFNAME
6043 /* ------------------------------------------------------------------------ */
6044 /* Function: ipf_getifname */
6045 /* Returns: char * - pointer to interface name */
6046 /* Parameters: ifp(I) - pointer to network interface */
6047 /* buffer(O) - pointer to where to store interface name */
6048 /* */
6049 /* Constructs an interface name in the buffer passed. The buffer passed is */
6050 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */
6051 /* as a NULL pointer then return a pointer to a static array. */
6052 /* ------------------------------------------------------------------------ */
6053 char *
ipf_getifname(struct ifnet * ifp,char * buffer)6054 ipf_getifname(struct ifnet *ifp, char *buffer)
6055 {
6056 static char namebuf[LIFNAMSIZ];
6057 # if SOLARIS || defined(__FreeBSD__)
6058 int unit, space;
6059 char temp[20];
6060 char *s;
6061 # endif
6062
6063 if (buffer == NULL)
6064 buffer = namebuf;
6065 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ);
6066 buffer[LIFNAMSIZ - 1] = '\0';
6067 # if SOLARIS || defined(__FreeBSD__)
6068 for (s = buffer; *s; s++)
6069 ;
6070 unit = ifp->if_unit;
6071 space = LIFNAMSIZ - (s - buffer);
6072 if ((space > 0) && (unit >= 0)) {
6073 (void) snprintf(temp, sizeof(name), "%d", unit);
6074 (void) strncpy(s, temp, space);
6075 }
6076 # endif
6077 return (buffer);
6078 }
6079 #endif
6080
6081
6082 /* ------------------------------------------------------------------------ */
6083 /* Function: ipf_ioctlswitch */
6084 /* Returns: int - -1 continue processing, else ioctl return value */
6085 /* Parameters: unit(I) - device unit opened */
6086 /* data(I) - pointer to ioctl data */
6087 /* cmd(I) - ioctl command */
6088 /* mode(I) - mode value */
6089 /* uid(I) - uid making the ioctl call */
6090 /* ctx(I) - pointer to context data */
6091 /* */
6092 /* Based on the value of unit, call the appropriate ioctl handler or return */
6093 /* EIO if ipfilter is not running. Also checks if write perms are req'd */
6094 /* for the device in order to execute the ioctl. A special case is made */
6095 /* SIOCIPFINTERROR so that the same code isn't required in every handler. */
6096 /* The context data pointer is passed through as this is used as the key */
6097 /* for locating a matching token for continued access for walking lists, */
6098 /* etc. */
6099 /* ------------------------------------------------------------------------ */
6100 int
ipf_ioctlswitch(ipf_main_softc_t * softc,int unit,void * data,ioctlcmd_t cmd,int mode,int uid,void * ctx)6101 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd,
6102 int mode, int uid, void *ctx)
6103 {
6104 int error = 0;
6105
6106 switch (cmd)
6107 {
6108 case SIOCIPFINTERROR :
6109 error = BCOPYOUT(&softc->ipf_interror, data,
6110 sizeof(softc->ipf_interror));
6111 if (error != 0) {
6112 IPFERROR(40);
6113 error = EFAULT;
6114 }
6115 return (error);
6116 default :
6117 break;
6118 }
6119
6120 switch (unit)
6121 {
6122 case IPL_LOGIPF :
6123 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx);
6124 break;
6125 case IPL_LOGNAT :
6126 if (softc->ipf_running > 0) {
6127 error = ipf_nat_ioctl(softc, data, cmd, mode,
6128 uid, ctx);
6129 } else {
6130 IPFERROR(42);
6131 error = EIO;
6132 }
6133 break;
6134 case IPL_LOGSTATE :
6135 if (softc->ipf_running > 0) {
6136 error = ipf_state_ioctl(softc, data, cmd, mode,
6137 uid, ctx);
6138 } else {
6139 IPFERROR(43);
6140 error = EIO;
6141 }
6142 break;
6143 case IPL_LOGAUTH :
6144 if (softc->ipf_running > 0) {
6145 error = ipf_auth_ioctl(softc, data, cmd, mode,
6146 uid, ctx);
6147 } else {
6148 IPFERROR(44);
6149 error = EIO;
6150 }
6151 break;
6152 case IPL_LOGSYNC :
6153 if (softc->ipf_running > 0) {
6154 error = ipf_sync_ioctl(softc, data, cmd, mode,
6155 uid, ctx);
6156 } else {
6157 error = EIO;
6158 IPFERROR(45);
6159 }
6160 break;
6161 case IPL_LOGSCAN :
6162 #ifdef IPFILTER_SCAN
6163 if (softc->ipf_running > 0)
6164 error = ipf_scan_ioctl(softc, data, cmd, mode,
6165 uid, ctx);
6166 else
6167 #endif
6168 {
6169 error = EIO;
6170 IPFERROR(46);
6171 }
6172 break;
6173 case IPL_LOGLOOKUP :
6174 if (softc->ipf_running > 0) {
6175 error = ipf_lookup_ioctl(softc, data, cmd, mode,
6176 uid, ctx);
6177 } else {
6178 error = EIO;
6179 IPFERROR(47);
6180 }
6181 break;
6182 default :
6183 IPFERROR(48);
6184 error = EIO;
6185 break;
6186 }
6187
6188 return (error);
6189 }
6190
6191
6192 /*
6193 * This array defines the expected size of objects coming into the kernel
6194 * for the various recognised object types. The first column is flags (see
6195 * below), 2nd column is current size, 3rd column is the version number of
6196 * when the current size became current.
6197 * Flags:
6198 * 1 = minimum size, not absolute size
6199 */
6200 static const int ipf_objbytes[IPFOBJ_COUNT][3] = {
6201 { 1, sizeof(struct frentry), 5010000 }, /* 0 */
6202 { 1, sizeof(struct friostat), 5010000 },
6203 { 0, sizeof(struct fr_info), 5010000 },
6204 { 0, sizeof(struct ipf_authstat), 4010100 },
6205 { 0, sizeof(struct ipfrstat), 5010000 },
6206 { 1, sizeof(struct ipnat), 5010000 }, /* 5 */
6207 { 0, sizeof(struct natstat), 5010000 },
6208 { 0, sizeof(struct ipstate_save), 5010000 },
6209 { 1, sizeof(struct nat_save), 5010000 },
6210 { 0, sizeof(struct natlookup), 5010000 },
6211 { 1, sizeof(struct ipstate), 5010000 }, /* 10 */
6212 { 0, sizeof(struct ips_stat), 5010000 },
6213 { 0, sizeof(struct frauth), 5010000 },
6214 { 0, sizeof(struct ipftune), 4010100 },
6215 { 0, sizeof(struct nat), 5010000 },
6216 { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */
6217 { 0, sizeof(struct ipfgeniter), 4011400 },
6218 { 0, sizeof(struct ipftable), 4011400 },
6219 { 0, sizeof(struct ipflookupiter), 4011400 },
6220 { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES },
6221 { 1, 0, 0 }, /* IPFEXPR */
6222 { 0, 0, 0 }, /* PROXYCTL */
6223 { 0, sizeof (struct fripf), 5010000 }
6224 };
6225
6226
6227 /* ------------------------------------------------------------------------ */
6228 /* Function: ipf_inobj */
6229 /* Returns: int - 0 = success, else failure */
6230 /* Parameters: softc(I) - soft context pointerto work with */
6231 /* data(I) - pointer to ioctl data */
6232 /* objp(O) - where to store ipfobj structure */
6233 /* ptr(I) - pointer to data to copy out */
6234 /* type(I) - type of structure being moved */
6235 /* */
6236 /* Copy in the contents of what the ipfobj_t points to. In future, we */
6237 /* add things to check for version numbers, sizes, etc, to make it backward */
6238 /* compatible at the ABI for user land. */
6239 /* If objp is not NULL then we assume that the caller wants to see what is */
6240 /* in the ipfobj_t structure being copied in. As an example, this can tell */
6241 /* the caller what version of ipfilter the ioctl program was written to. */
6242 /* ------------------------------------------------------------------------ */
6243 int
ipf_inobj(ipf_main_softc_t * softc,void * data,ipfobj_t * objp,void * ptr,int type)6244 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr,
6245 int type)
6246 {
6247 ipfobj_t obj;
6248 int error;
6249 int size;
6250
6251 if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6252 IPFERROR(49);
6253 return (EINVAL);
6254 }
6255
6256 if (objp == NULL)
6257 objp = &obj;
6258 error = BCOPYIN(data, objp, sizeof(*objp));
6259 if (error != 0) {
6260 IPFERROR(124);
6261 return (EFAULT);
6262 }
6263
6264 if (objp->ipfo_type != type) {
6265 IPFERROR(50);
6266 return (EINVAL);
6267 }
6268
6269 if (objp->ipfo_rev >= ipf_objbytes[type][2]) {
6270 if ((ipf_objbytes[type][0] & 1) != 0) {
6271 if (objp->ipfo_size < ipf_objbytes[type][1]) {
6272 IPFERROR(51);
6273 return (EINVAL);
6274 }
6275 size = ipf_objbytes[type][1];
6276 } else if (objp->ipfo_size == ipf_objbytes[type][1]) {
6277 size = objp->ipfo_size;
6278 } else {
6279 IPFERROR(52);
6280 return (EINVAL);
6281 }
6282 error = COPYIN(objp->ipfo_ptr, ptr, size);
6283 if (error != 0) {
6284 IPFERROR(55);
6285 error = EFAULT;
6286 }
6287 } else {
6288 #ifdef IPFILTER_COMPAT
6289 error = ipf_in_compat(softc, objp, ptr, 0);
6290 #else
6291 IPFERROR(54);
6292 error = EINVAL;
6293 #endif
6294 }
6295 return (error);
6296 }
6297
6298
6299 /* ------------------------------------------------------------------------ */
6300 /* Function: ipf_inobjsz */
6301 /* Returns: int - 0 = success, else failure */
6302 /* Parameters: softc(I) - soft context pointerto work with */
6303 /* data(I) - pointer to ioctl data */
6304 /* ptr(I) - pointer to store real data in */
6305 /* type(I) - type of structure being moved */
6306 /* sz(I) - size of data to copy */
6307 /* */
6308 /* As per ipf_inobj, except the size of the object to copy in is passed in */
6309 /* but it must not be smaller than the size defined for the type and the */
6310 /* type must allow for varied sized objects. The extra requirement here is */
6311 /* that sz must match the size of the object being passed in - this is not */
6312 /* not possible nor required in ipf_inobj(). */
6313 /* ------------------------------------------------------------------------ */
6314 int
ipf_inobjsz(ipf_main_softc_t * softc,void * data,void * ptr,int type,int sz)6315 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz)
6316 {
6317 ipfobj_t obj;
6318 int error;
6319
6320 if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6321 IPFERROR(56);
6322 return (EINVAL);
6323 }
6324
6325 error = BCOPYIN(data, &obj, sizeof(obj));
6326 if (error != 0) {
6327 IPFERROR(125);
6328 return (EFAULT);
6329 }
6330
6331 if (obj.ipfo_type != type) {
6332 IPFERROR(58);
6333 return (EINVAL);
6334 }
6335
6336 if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6337 if (((ipf_objbytes[type][0] & 1) == 0) ||
6338 (sz < ipf_objbytes[type][1])) {
6339 IPFERROR(57);
6340 return (EINVAL);
6341 }
6342 error = COPYIN(obj.ipfo_ptr, ptr, sz);
6343 if (error != 0) {
6344 IPFERROR(61);
6345 error = EFAULT;
6346 }
6347 } else {
6348 #ifdef IPFILTER_COMPAT
6349 error = ipf_in_compat(softc, &obj, ptr, sz);
6350 #else
6351 IPFERROR(60);
6352 error = EINVAL;
6353 #endif
6354 }
6355 return (error);
6356 }
6357
6358
6359 /* ------------------------------------------------------------------------ */
6360 /* Function: ipf_outobjsz */
6361 /* Returns: int - 0 = success, else failure */
6362 /* Parameters: data(I) - pointer to ioctl data */
6363 /* ptr(I) - pointer to store real data in */
6364 /* type(I) - type of structure being moved */
6365 /* sz(I) - size of data to copy */
6366 /* */
6367 /* As per ipf_outobj, except the size of the object to copy out is passed in*/
6368 /* but it must not be smaller than the size defined for the type and the */
6369 /* type must allow for varied sized objects. The extra requirement here is */
6370 /* that sz must match the size of the object being passed in - this is not */
6371 /* not possible nor required in ipf_outobj(). */
6372 /* ------------------------------------------------------------------------ */
6373 int
ipf_outobjsz(ipf_main_softc_t * softc,void * data,void * ptr,int type,int sz)6374 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz)
6375 {
6376 ipfobj_t obj;
6377 int error;
6378
6379 if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6380 IPFERROR(62);
6381 return (EINVAL);
6382 }
6383
6384 error = BCOPYIN(data, &obj, sizeof(obj));
6385 if (error != 0) {
6386 IPFERROR(127);
6387 return (EFAULT);
6388 }
6389
6390 if (obj.ipfo_type != type) {
6391 IPFERROR(63);
6392 return (EINVAL);
6393 }
6394
6395 if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6396 if (((ipf_objbytes[type][0] & 1) == 0) ||
6397 (sz < ipf_objbytes[type][1])) {
6398 IPFERROR(146);
6399 return (EINVAL);
6400 }
6401 error = COPYOUT(ptr, obj.ipfo_ptr, sz);
6402 if (error != 0) {
6403 IPFERROR(66);
6404 error = EFAULT;
6405 }
6406 } else {
6407 #ifdef IPFILTER_COMPAT
6408 error = ipf_out_compat(softc, &obj, ptr);
6409 #else
6410 IPFERROR(65);
6411 error = EINVAL;
6412 #endif
6413 }
6414 return (error);
6415 }
6416
6417
6418 /* ------------------------------------------------------------------------ */
6419 /* Function: ipf_outobj */
6420 /* Returns: int - 0 = success, else failure */
6421 /* Parameters: data(I) - pointer to ioctl data */
6422 /* ptr(I) - pointer to store real data in */
6423 /* type(I) - type of structure being moved */
6424 /* */
6425 /* Copy out the contents of what ptr is to where ipfobj points to. In */
6426 /* future, we add things to check for version numbers, sizes, etc, to make */
6427 /* it backward compatible at the ABI for user land. */
6428 /* ------------------------------------------------------------------------ */
6429 int
ipf_outobj(ipf_main_softc_t * softc,void * data,void * ptr,int type)6430 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type)
6431 {
6432 ipfobj_t obj;
6433 int error;
6434
6435 if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6436 IPFERROR(67);
6437 return (EINVAL);
6438 }
6439
6440 error = BCOPYIN(data, &obj, sizeof(obj));
6441 if (error != 0) {
6442 IPFERROR(126);
6443 return (EFAULT);
6444 }
6445
6446 if (obj.ipfo_type != type) {
6447 IPFERROR(68);
6448 return (EINVAL);
6449 }
6450
6451 if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6452 if ((ipf_objbytes[type][0] & 1) != 0) {
6453 if (obj.ipfo_size < ipf_objbytes[type][1]) {
6454 IPFERROR(69);
6455 return (EINVAL);
6456 }
6457 } else if (obj.ipfo_size != ipf_objbytes[type][1]) {
6458 IPFERROR(70);
6459 return (EINVAL);
6460 }
6461
6462 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
6463 if (error != 0) {
6464 IPFERROR(73);
6465 error = EFAULT;
6466 }
6467 } else {
6468 #ifdef IPFILTER_COMPAT
6469 error = ipf_out_compat(softc, &obj, ptr);
6470 #else
6471 IPFERROR(72);
6472 error = EINVAL;
6473 #endif
6474 }
6475 return (error);
6476 }
6477
6478
6479 /* ------------------------------------------------------------------------ */
6480 /* Function: ipf_outobjk */
6481 /* Returns: int - 0 = success, else failure */
6482 /* Parameters: obj(I) - pointer to data description structure */
6483 /* ptr(I) - pointer to kernel data to copy out */
6484 /* */
6485 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/
6486 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */
6487 /* already populated with information and now we just need to use it. */
6488 /* There is no need for this function to have a "type" parameter as there */
6489 /* is no point in validating information that comes from the kernel with */
6490 /* itself. */
6491 /* ------------------------------------------------------------------------ */
6492 int
ipf_outobjk(ipf_main_softc_t * softc,ipfobj_t * obj,void * ptr)6493 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr)
6494 {
6495 int type = obj->ipfo_type;
6496 int error;
6497
6498 if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6499 IPFERROR(147);
6500 return (EINVAL);
6501 }
6502
6503 if (obj->ipfo_rev >= ipf_objbytes[type][2]) {
6504 if ((ipf_objbytes[type][0] & 1) != 0) {
6505 if (obj->ipfo_size < ipf_objbytes[type][1]) {
6506 IPFERROR(148);
6507 return (EINVAL);
6508 }
6509
6510 } else if (obj->ipfo_size != ipf_objbytes[type][1]) {
6511 IPFERROR(149);
6512 return (EINVAL);
6513 }
6514
6515 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size);
6516 if (error != 0) {
6517 IPFERROR(150);
6518 error = EFAULT;
6519 }
6520 } else {
6521 #ifdef IPFILTER_COMPAT
6522 error = ipf_out_compat(softc, obj, ptr);
6523 #else
6524 IPFERROR(151);
6525 error = EINVAL;
6526 #endif
6527 }
6528 return (error);
6529 }
6530
6531
6532 /* ------------------------------------------------------------------------ */
6533 /* Function: ipf_checkl4sum */
6534 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */
6535 /* Parameters: fin(I) - pointer to packet information */
6536 /* */
6537 /* If possible, calculate the layer 4 checksum for the packet. If this is */
6538 /* not possible, return without indicating a failure or success but in a */
6539 /* way that is ditinguishable. This function should only be called by the */
6540 /* ipf_checkv6sum() for each platform. */
6541 /* ------------------------------------------------------------------------ */
6542 inline int
ipf_checkl4sum(fr_info_t * fin)6543 ipf_checkl4sum(fr_info_t *fin)
6544 {
6545 u_short sum, hdrsum, *csump;
6546 udphdr_t *udp;
6547 int dosum;
6548
6549 /*
6550 * If the TCP packet isn't a fragment, isn't too short and otherwise
6551 * isn't already considered "bad", then validate the checksum. If
6552 * this check fails then considered the packet to be "bad".
6553 */
6554 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0)
6555 return (1);
6556
6557 DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p);
6558 if (fin->fin_out == 1) {
6559 fin->fin_cksum = FI_CK_SUMOK;
6560 return (0);
6561 }
6562
6563 csump = NULL;
6564 hdrsum = 0;
6565 dosum = 0;
6566 sum = 0;
6567
6568 switch (fin->fin_p)
6569 {
6570 case IPPROTO_TCP :
6571 csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
6572 dosum = 1;
6573 break;
6574
6575 case IPPROTO_UDP :
6576 udp = fin->fin_dp;
6577 if (udp->uh_sum != 0) {
6578 csump = &udp->uh_sum;
6579 dosum = 1;
6580 }
6581 break;
6582
6583 #ifdef USE_INET6
6584 case IPPROTO_ICMPV6 :
6585 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum;
6586 dosum = 1;
6587 break;
6588 #endif
6589
6590 case IPPROTO_ICMP :
6591 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
6592 dosum = 1;
6593 break;
6594
6595 default :
6596 return (1);
6597 /*NOTREACHED*/
6598 }
6599
6600 if (csump != NULL) {
6601 hdrsum = *csump;
6602 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff)
6603 hdrsum = 0x0000;
6604 }
6605
6606 if (dosum) {
6607 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp);
6608 }
6609 #if !defined(_KERNEL)
6610 if (sum == hdrsum) {
6611 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
6612 } else {
6613 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
6614 }
6615 #endif
6616 DT3(l4sums, u_short, hdrsum, u_short, sum, fr_info_t *, fin);
6617 #ifdef USE_INET6
6618 if (hdrsum == sum || (sum == 0 && IP_V(fin->fin_ip) == 6)) {
6619 #else
6620 if (hdrsum == sum) {
6621 #endif
6622 fin->fin_cksum = FI_CK_SUMOK;
6623 return (0);
6624 }
6625 fin->fin_cksum = FI_CK_BAD;
6626 return (-1);
6627 }
6628
6629
6630 /* ------------------------------------------------------------------------ */
6631 /* Function: ipf_ifpfillv4addr */
6632 /* Returns: int - 0 = address update, -1 = address not updated */
6633 /* Parameters: atype(I) - type of network address update to perform */
6634 /* sin(I) - pointer to source of address information */
6635 /* mask(I) - pointer to source of netmask information */
6636 /* inp(I) - pointer to destination address store */
6637 /* inpmask(I) - pointer to destination netmask store */
6638 /* */
6639 /* Given a type of network address update (atype) to perform, copy */
6640 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */
6641 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */
6642 /* which case the operation fails. For all values of atype other than */
6643 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
6644 /* value. */
6645 /* ------------------------------------------------------------------------ */
6646 int
6647 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask,
6648 struct in_addr *inp, struct in_addr *inpmask)
6649 {
6650 if (inpmask != NULL && atype != FRI_NETMASKED)
6651 inpmask->s_addr = 0xffffffff;
6652
6653 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
6654 if (atype == FRI_NETMASKED) {
6655 if (inpmask == NULL)
6656 return (-1);
6657 inpmask->s_addr = mask->sin_addr.s_addr;
6658 }
6659 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr;
6660 } else {
6661 inp->s_addr = sin->sin_addr.s_addr;
6662 }
6663 return (0);
6664 }
6665
6666
6667 #ifdef USE_INET6
6668 /* ------------------------------------------------------------------------ */
6669 /* Function: ipf_ifpfillv6addr */
6670 /* Returns: int - 0 = address update, -1 = address not updated */
6671 /* Parameters: atype(I) - type of network address update to perform */
6672 /* sin(I) - pointer to source of address information */
6673 /* mask(I) - pointer to source of netmask information */
6674 /* inp(I) - pointer to destination address store */
6675 /* inpmask(I) - pointer to destination netmask store */
6676 /* */
6677 /* Given a type of network address update (atype) to perform, copy */
6678 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */
6679 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */
6680 /* which case the operation fails. For all values of atype other than */
6681 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
6682 /* value. */
6683 /* ------------------------------------------------------------------------ */
6684 int
6685 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin,
6686 struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask)
6687 {
6688 i6addr_t *src, *and;
6689
6690 src = (i6addr_t *)&sin->sin6_addr;
6691 and = (i6addr_t *)&mask->sin6_addr;
6692
6693 if (inpmask != NULL && atype != FRI_NETMASKED) {
6694 inpmask->i6[0] = 0xffffffff;
6695 inpmask->i6[1] = 0xffffffff;
6696 inpmask->i6[2] = 0xffffffff;
6697 inpmask->i6[3] = 0xffffffff;
6698 }
6699
6700 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
6701 if (atype == FRI_NETMASKED) {
6702 if (inpmask == NULL)
6703 return (-1);
6704 inpmask->i6[0] = and->i6[0];
6705 inpmask->i6[1] = and->i6[1];
6706 inpmask->i6[2] = and->i6[2];
6707 inpmask->i6[3] = and->i6[3];
6708 }
6709
6710 inp->i6[0] = src->i6[0] & and->i6[0];
6711 inp->i6[1] = src->i6[1] & and->i6[1];
6712 inp->i6[2] = src->i6[2] & and->i6[2];
6713 inp->i6[3] = src->i6[3] & and->i6[3];
6714 } else {
6715 inp->i6[0] = src->i6[0];
6716 inp->i6[1] = src->i6[1];
6717 inp->i6[2] = src->i6[2];
6718 inp->i6[3] = src->i6[3];
6719 }
6720 return (0);
6721 }
6722 #endif
6723
6724
6725 /* ------------------------------------------------------------------------ */
6726 /* Function: ipf_matchtag */
6727 /* Returns: 0 == mismatch, 1 == match. */
6728 /* Parameters: tag1(I) - pointer to first tag to compare */
6729 /* tag2(I) - pointer to second tag to compare */
6730 /* */
6731 /* Returns true (non-zero) or false(0) if the two tag structures can be */
6732 /* considered to be a match or not match, respectively. The tag is 16 */
6733 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */
6734 /* compare the ints instead, for speed. tag1 is the master of the */
6735 /* comparison. This function should only be called with both tag1 and tag2 */
6736 /* as non-NULL pointers. */
6737 /* ------------------------------------------------------------------------ */
6738 int
6739 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2)
6740 {
6741 if (tag1 == tag2)
6742 return (1);
6743
6744 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0))
6745 return (1);
6746
6747 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) &&
6748 (tag1->ipt_num[1] == tag2->ipt_num[1]) &&
6749 (tag1->ipt_num[2] == tag2->ipt_num[2]) &&
6750 (tag1->ipt_num[3] == tag2->ipt_num[3]))
6751 return (1);
6752 return (0);
6753 }
6754
6755
6756 /* ------------------------------------------------------------------------ */
6757 /* Function: ipf_coalesce */
6758 /* Returns: 1 == success, -1 == failure, 0 == no change */
6759 /* Parameters: fin(I) - pointer to packet information */
6760 /* */
6761 /* Attempt to get all of the packet data into a single, contiguous buffer. */
6762 /* If this call returns a failure then the buffers have also been freed. */
6763 /* ------------------------------------------------------------------------ */
6764 int
6765 ipf_coalesce(fr_info_t *fin)
6766 {
6767
6768 if ((fin->fin_flx & FI_COALESCE) != 0)
6769 return (1);
6770
6771 /*
6772 * If the mbuf pointers indicate that there is no mbuf to work with,
6773 * return but do not indicate success or failure.
6774 */
6775 if (fin->fin_m == NULL || fin->fin_mp == NULL)
6776 return (0);
6777
6778 #if defined(_KERNEL)
6779 if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
6780 ipf_main_softc_t *softc = fin->fin_main_soft;
6781
6782 DT1(frb_coalesce, fr_info_t *, fin);
6783 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces);
6784 # if SOLARIS
6785 FREE_MB_T(*fin->fin_mp);
6786 # endif
6787 fin->fin_reason = FRB_COALESCE;
6788 *fin->fin_mp = NULL;
6789 fin->fin_m = NULL;
6790 return (-1);
6791 }
6792 #else
6793 fin = fin; /* LINT */
6794 #endif
6795 return (1);
6796 }
6797
6798
6799 /*
6800 * The following table lists all of the tunable variables that can be
6801 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row
6802 * in the table below is as follows:
6803 *
6804 * pointer to value, name of value, minimum, maximum, size of the value's
6805 * container, value attribute flags
6806 *
6807 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED
6808 * means the value can only be written to when IPFilter is loaded but disabled.
6809 * The obvious implication is if neither of these are set then the value can be
6810 * changed at any time without harm.
6811 */
6812
6813
6814 /* ------------------------------------------------------------------------ */
6815 /* Function: ipf_tune_findbycookie */
6816 /* Returns: NULL = search failed, else pointer to tune struct */
6817 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */
6818 /* next(O) - pointer to place to store the cookie for the */
6819 /* "next" tuneable, if it is desired. */
6820 /* */
6821 /* This function is used to walk through all of the existing tunables with */
6822 /* successive calls. It searches the known tunables for the one which has */
6823 /* a matching value for "cookie" - ie its address. When returning a match, */
6824 /* the next one to be found may be returned inside next. */
6825 /* ------------------------------------------------------------------------ */
6826 static ipftuneable_t *
6827 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next)
6828 {
6829 ipftuneable_t *ta, **tap;
6830
6831 for (ta = *ptop; ta->ipft_name != NULL; ta++)
6832 if (ta == cookie) {
6833 if (next != NULL) {
6834 /*
6835 * If the next entry in the array has a name
6836 * present, then return a pointer to it for
6837 * where to go next, else return a pointer to
6838 * the dynaminc list as a key to search there
6839 * next. This facilitates a weak linking of
6840 * the two "lists" together.
6841 */
6842 if ((ta + 1)->ipft_name != NULL)
6843 *next = ta + 1;
6844 else
6845 *next = ptop;
6846 }
6847 return (ta);
6848 }
6849
6850 for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next)
6851 if (tap == cookie) {
6852 if (next != NULL)
6853 *next = &ta->ipft_next;
6854 return (ta);
6855 }
6856
6857 if (next != NULL)
6858 *next = NULL;
6859 return (NULL);
6860 }
6861
6862
6863 /* ------------------------------------------------------------------------ */
6864 /* Function: ipf_tune_findbyname */
6865 /* Returns: NULL = search failed, else pointer to tune struct */
6866 /* Parameters: name(I) - name of the tuneable entry to find. */
6867 /* */
6868 /* Search the static array of tuneables and the list of dynamic tuneables */
6869 /* for an entry with a matching name. If we can find one, return a pointer */
6870 /* to the matching structure. */
6871 /* ------------------------------------------------------------------------ */
6872 static ipftuneable_t *
6873 ipf_tune_findbyname(ipftuneable_t *top, const char *name)
6874 {
6875 ipftuneable_t *ta;
6876
6877 for (ta = top; ta != NULL; ta = ta->ipft_next)
6878 if (!strcmp(ta->ipft_name, name)) {
6879 return (ta);
6880 }
6881
6882 return (NULL);
6883 }
6884
6885
6886 /* ------------------------------------------------------------------------ */
6887 /* Function: ipf_tune_add_array */
6888 /* Returns: int - 0 == success, else failure */
6889 /* Parameters: newtune - pointer to new tune array to add to tuneables */
6890 /* */
6891 /* Appends tune structures from the array passed in (newtune) to the end of */
6892 /* the current list of "dynamic" tuneable parameters. */
6893 /* If any entry to be added is already present (by name) then the operation */
6894 /* is aborted - entries that have been added are removed before returning. */
6895 /* An entry with no name (NULL) is used as the indication that the end of */
6896 /* the array has been reached. */
6897 /* ------------------------------------------------------------------------ */
6898 int
6899 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune)
6900 {
6901 ipftuneable_t *nt, *dt;
6902 int error = 0;
6903
6904 for (nt = newtune; nt->ipft_name != NULL; nt++) {
6905 error = ipf_tune_add(softc, nt);
6906 if (error != 0) {
6907 for (dt = newtune; dt != nt; dt++) {
6908 (void) ipf_tune_del(softc, dt);
6909 }
6910 }
6911 }
6912
6913 return (error);
6914 }
6915
6916
6917 /* ------------------------------------------------------------------------ */
6918 /* Function: ipf_tune_array_link */
6919 /* Returns: 0 == success, -1 == failure */
6920 /* Parameters: softc(I) - soft context pointerto work with */
6921 /* array(I) - pointer to an array of tuneables */
6922 /* */
6923 /* Given an array of tunables (array), append them to the current list of */
6924 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the */
6925 /* the array for being appended to the list, initialise all of the next */
6926 /* pointers so we don't need to walk parts of it with ++ and others with */
6927 /* next. The array is expected to have an entry with a NULL name as the */
6928 /* terminator. Trying to add an array with no non-NULL names will return as */
6929 /* a failure. */
6930 /* ------------------------------------------------------------------------ */
6931 int
6932 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array)
6933 {
6934 ipftuneable_t *t, **p;
6935
6936 t = array;
6937 if (t->ipft_name == NULL)
6938 return (-1);
6939
6940 for (; t[1].ipft_name != NULL; t++)
6941 t[0].ipft_next = &t[1];
6942 t->ipft_next = NULL;
6943
6944 /*
6945 * Since a pointer to the last entry isn't kept, we need to find it
6946 * each time we want to add new variables to the list.
6947 */
6948 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
6949 if (t->ipft_name == NULL)
6950 break;
6951 *p = array;
6952
6953 return (0);
6954 }
6955
6956
6957 /* ------------------------------------------------------------------------ */
6958 /* Function: ipf_tune_array_unlink */
6959 /* Returns: 0 == success, -1 == failure */
6960 /* Parameters: softc(I) - soft context pointerto work with */
6961 /* array(I) - pointer to an array of tuneables */
6962 /* */
6963 /* ------------------------------------------------------------------------ */
6964 int
6965 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array)
6966 {
6967 ipftuneable_t *t, **p;
6968
6969 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
6970 if (t == array)
6971 break;
6972 if (t == NULL)
6973 return (-1);
6974
6975 for (; t[1].ipft_name != NULL; t++)
6976 ;
6977
6978 *p = t->ipft_next;
6979
6980 return (0);
6981 }
6982
6983
6984 /* ------------------------------------------------------------------------ */
6985 /* Function: ipf_tune_array_copy */
6986 /* Returns: NULL = failure, else pointer to new array */
6987 /* Parameters: base(I) - pointer to structure base */
6988 /* size(I) - size of the array at template */
6989 /* template(I) - original array to copy */
6990 /* */
6991 /* Allocate memory for a new set of tuneable values and copy everything */
6992 /* from template into the new region of memory. The new region is full of */
6993 /* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */
6994 /* */
6995 /* NOTE: the following assumes that sizeof(long) == sizeof(void *) */
6996 /* In the array template, ipftp_offset is the offset (in bytes) of the */
6997 /* location of the tuneable value inside the structure pointed to by base. */
6998 /* As ipftp_offset is a union over the pointers to the tuneable values, if */
6999 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in */
7000 /* ipftp_void that points to the stored value. */
7001 /* ------------------------------------------------------------------------ */
7002 ipftuneable_t *
7003 ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template)
7004 {
7005 ipftuneable_t *copy;
7006 int i;
7007
7008
7009 KMALLOCS(copy, ipftuneable_t *, size);
7010 if (copy == NULL) {
7011 return (NULL);
7012 }
7013 bcopy(template, copy, size);
7014
7015 for (i = 0; copy[i].ipft_name; i++) {
7016 copy[i].ipft_una.ipftp_offset += (u_long)base;
7017 copy[i].ipft_next = copy + i + 1;
7018 }
7019
7020 return (copy);
7021 }
7022
7023
7024 /* ------------------------------------------------------------------------ */
7025 /* Function: ipf_tune_add */
7026 /* Returns: int - 0 == success, else failure */
7027 /* Parameters: newtune - pointer to new tune entry to add to tuneables */
7028 /* */
7029 /* Appends tune structures from the array passed in (newtune) to the end of */
7030 /* the current list of "dynamic" tuneable parameters. Once added, the */
7031 /* owner of the object is not expected to ever change "ipft_next". */
7032 /* ------------------------------------------------------------------------ */
7033 int
7034 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune)
7035 {
7036 ipftuneable_t *ta, **tap;
7037
7038 ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name);
7039 if (ta != NULL) {
7040 IPFERROR(74);
7041 return (EEXIST);
7042 }
7043
7044 for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next)
7045 ;
7046
7047 newtune->ipft_next = NULL;
7048 *tap = newtune;
7049 return (0);
7050 }
7051
7052
7053 /* ------------------------------------------------------------------------ */
7054 /* Function: ipf_tune_del */
7055 /* Returns: int - 0 == success, else failure */
7056 /* Parameters: oldtune - pointer to tune entry to remove from the list of */
7057 /* current dynamic tuneables */
7058 /* */
7059 /* Search for the tune structure, by pointer, in the list of those that are */
7060 /* dynamically added at run time. If found, adjust the list so that this */
7061 /* structure is no longer part of it. */
7062 /* ------------------------------------------------------------------------ */
7063 int
7064 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune)
7065 {
7066 ipftuneable_t *ta, **tap;
7067 int error = 0;
7068
7069 for (tap = &softc->ipf_tuners; (ta = *tap) != NULL;
7070 tap = &ta->ipft_next) {
7071 if (ta == oldtune) {
7072 *tap = oldtune->ipft_next;
7073 oldtune->ipft_next = NULL;
7074 break;
7075 }
7076 }
7077
7078 if (ta == NULL) {
7079 error = ESRCH;
7080 IPFERROR(75);
7081 }
7082 return (error);
7083 }
7084
7085
7086 /* ------------------------------------------------------------------------ */
7087 /* Function: ipf_tune_del_array */
7088 /* Returns: int - 0 == success, else failure */
7089 /* Parameters: oldtune - pointer to tuneables array */
7090 /* */
7091 /* Remove each tuneable entry in the array from the list of "dynamic" */
7092 /* tunables. If one entry should fail to be found, an error will be */
7093 /* returned and no further ones removed. */
7094 /* An entry with a NULL name is used as the indicator of the last entry in */
7095 /* the array. */
7096 /* ------------------------------------------------------------------------ */
7097 int
7098 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune)
7099 {
7100 ipftuneable_t *ot;
7101 int error = 0;
7102
7103 for (ot = oldtune; ot->ipft_name != NULL; ot++) {
7104 error = ipf_tune_del(softc, ot);
7105 if (error != 0)
7106 break;
7107 }
7108
7109 return (error);
7110
7111 }
7112
7113
7114 /* ------------------------------------------------------------------------ */
7115 /* Function: ipf_tune */
7116 /* Returns: int - 0 == success, else failure */
7117 /* Parameters: cmd(I) - ioctl command number */
7118 /* data(I) - pointer to ioctl data structure */
7119 /* */
7120 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */
7121 /* three ioctls provide the means to access and control global variables */
7122 /* within IPFilter, allowing (for example) timeouts and table sizes to be */
7123 /* changed without rebooting, reloading or recompiling. The initialisation */
7124 /* and 'destruction' routines of the various components of ipfilter are all */
7125 /* each responsible for handling their own values being too big. */
7126 /* ------------------------------------------------------------------------ */
7127 int
7128 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data)
7129 {
7130 ipftuneable_t *ta;
7131 ipftune_t tu;
7132 void *cookie;
7133 int error;
7134
7135 error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE);
7136 if (error != 0)
7137 return (error);
7138
7139 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
7140 cookie = tu.ipft_cookie;
7141 ta = NULL;
7142
7143 switch (cmd)
7144 {
7145 case SIOCIPFGETNEXT :
7146 /*
7147 * If cookie is non-NULL, assume it to be a pointer to the last
7148 * entry we looked at, so find it (if possible) and return a
7149 * pointer to the next one after it. The last entry in the
7150 * the table is a NULL entry, so when we get to it, set cookie
7151 * to NULL and return that, indicating end of list, erstwhile
7152 * if we come in with cookie set to NULL, we are starting anew
7153 * at the front of the list.
7154 */
7155 if (cookie != NULL) {
7156 ta = ipf_tune_findbycookie(&softc->ipf_tuners,
7157 cookie, &tu.ipft_cookie);
7158 } else {
7159 ta = softc->ipf_tuners;
7160 tu.ipft_cookie = ta + 1;
7161 }
7162 if (ta != NULL) {
7163 /*
7164 * Entry found, but does the data pointed to by that
7165 * row fit in what we can return?
7166 */
7167 if (ta->ipft_sz > sizeof(tu.ipft_un)) {
7168 IPFERROR(76);
7169 return (EINVAL);
7170 }
7171
7172 tu.ipft_vlong = 0;
7173 if (ta->ipft_sz == sizeof(u_long))
7174 tu.ipft_vlong = *ta->ipft_plong;
7175 else if (ta->ipft_sz == sizeof(u_int))
7176 tu.ipft_vint = *ta->ipft_pint;
7177 else if (ta->ipft_sz == sizeof(u_short))
7178 tu.ipft_vshort = *ta->ipft_pshort;
7179 else if (ta->ipft_sz == sizeof(u_char))
7180 tu.ipft_vchar = *ta->ipft_pchar;
7181
7182 tu.ipft_sz = ta->ipft_sz;
7183 tu.ipft_min = ta->ipft_min;
7184 tu.ipft_max = ta->ipft_max;
7185 tu.ipft_flags = ta->ipft_flags;
7186 bcopy(ta->ipft_name, tu.ipft_name,
7187 MIN(sizeof(tu.ipft_name),
7188 strlen(ta->ipft_name) + 1));
7189 }
7190 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7191 break;
7192
7193 case SIOCIPFGET :
7194 case SIOCIPFSET :
7195 /*
7196 * Search by name or by cookie value for a particular entry
7197 * in the tuning parameter table.
7198 */
7199 IPFERROR(77);
7200 error = ESRCH;
7201 if (cookie != NULL) {
7202 ta = ipf_tune_findbycookie(&softc->ipf_tuners,
7203 cookie, NULL);
7204 if (ta != NULL)
7205 error = 0;
7206 } else if (tu.ipft_name[0] != '\0') {
7207 ta = ipf_tune_findbyname(softc->ipf_tuners,
7208 tu.ipft_name);
7209 if (ta != NULL)
7210 error = 0;
7211 }
7212 if (error != 0)
7213 break;
7214
7215 if (cmd == (ioctlcmd_t)SIOCIPFGET) {
7216 /*
7217 * Fetch the tuning parameters for a particular value
7218 */
7219 tu.ipft_vlong = 0;
7220 if (ta->ipft_sz == sizeof(u_long))
7221 tu.ipft_vlong = *ta->ipft_plong;
7222 else if (ta->ipft_sz == sizeof(u_int))
7223 tu.ipft_vint = *ta->ipft_pint;
7224 else if (ta->ipft_sz == sizeof(u_short))
7225 tu.ipft_vshort = *ta->ipft_pshort;
7226 else if (ta->ipft_sz == sizeof(u_char))
7227 tu.ipft_vchar = *ta->ipft_pchar;
7228 tu.ipft_cookie = ta;
7229 tu.ipft_sz = ta->ipft_sz;
7230 tu.ipft_min = ta->ipft_min;
7231 tu.ipft_max = ta->ipft_max;
7232 tu.ipft_flags = ta->ipft_flags;
7233 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7234
7235 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
7236 /*
7237 * Set an internal parameter. The hard part here is
7238 * getting the new value safely and correctly out of
7239 * the kernel (given we only know its size, not type.)
7240 */
7241 u_long in;
7242
7243 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
7244 (softc->ipf_running > 0)) {
7245 IPFERROR(78);
7246 error = EBUSY;
7247 break;
7248 }
7249
7250 in = tu.ipft_vlong;
7251 if (in < ta->ipft_min || in > ta->ipft_max) {
7252 IPFERROR(79);
7253 error = EINVAL;
7254 break;
7255 }
7256
7257 if (ta->ipft_func != NULL) {
7258 SPL_INT(s);
7259
7260 SPL_NET(s);
7261 error = (*ta->ipft_func)(softc, ta,
7262 &tu.ipft_un);
7263 SPL_X(s);
7264
7265 } else if (ta->ipft_sz == sizeof(u_long)) {
7266 tu.ipft_vlong = *ta->ipft_plong;
7267 *ta->ipft_plong = in;
7268
7269 } else if (ta->ipft_sz == sizeof(u_int)) {
7270 tu.ipft_vint = *ta->ipft_pint;
7271 *ta->ipft_pint = (u_int)(in & 0xffffffff);
7272
7273 } else if (ta->ipft_sz == sizeof(u_short)) {
7274 tu.ipft_vshort = *ta->ipft_pshort;
7275 *ta->ipft_pshort = (u_short)(in & 0xffff);
7276
7277 } else if (ta->ipft_sz == sizeof(u_char)) {
7278 tu.ipft_vchar = *ta->ipft_pchar;
7279 *ta->ipft_pchar = (u_char)(in & 0xff);
7280 }
7281 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7282 }
7283 break;
7284
7285 default :
7286 IPFERROR(80);
7287 error = EINVAL;
7288 break;
7289 }
7290
7291 return (error);
7292 }
7293
7294
7295 /* ------------------------------------------------------------------------ */
7296 /* Function: ipf_zerostats */
7297 /* Returns: int - 0 = success, else failure */
7298 /* Parameters: data(O) - pointer to pointer for copying data back to */
7299 /* */
7300 /* Copies the current statistics out to userspace and then zero's the */
7301 /* current ones in the kernel. The lock is only held across the bzero() as */
7302 /* the copyout may result in paging (ie network activity.) */
7303 /* ------------------------------------------------------------------------ */
7304 int
7305 ipf_zerostats(ipf_main_softc_t *softc, caddr_t data)
7306 {
7307 friostat_t fio;
7308 ipfobj_t obj;
7309 int error;
7310
7311 error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT);
7312 if (error != 0)
7313 return (error);
7314 ipf_getstat(softc, &fio, obj.ipfo_rev);
7315 error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT);
7316 if (error != 0)
7317 return (error);
7318
7319 WRITE_ENTER(&softc->ipf_mutex);
7320 bzero(&softc->ipf_stats, sizeof(softc->ipf_stats));
7321 RWLOCK_EXIT(&softc->ipf_mutex);
7322
7323 return (0);
7324 }
7325
7326
7327 /* ------------------------------------------------------------------------ */
7328 /* Function: ipf_resolvedest */
7329 /* Returns: Nil */
7330 /* Parameters: softc(I) - pointer to soft context main structure */
7331 /* base(I) - where strings are stored */
7332 /* fdp(IO) - pointer to destination information to resolve */
7333 /* v(I) - IP protocol version to match */
7334 /* */
7335 /* Looks up an interface name in the frdest structure pointed to by fdp and */
7336 /* if a matching name can be found for the particular IP protocol version */
7337 /* then store the interface pointer in the frdest struct. If no match is */
7338 /* found, then set the interface pointer to be -1 as NULL is considered to */
7339 /* indicate there is no information at all in the structure. */
7340 /* ------------------------------------------------------------------------ */
7341 int
7342 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v)
7343 {
7344 int errval = 0;
7345 void *ifp;
7346
7347 ifp = NULL;
7348
7349 if (fdp->fd_name != -1) {
7350 if (fdp->fd_type == FRD_DSTLIST) {
7351 ifp = ipf_lookup_res_name(softc, IPL_LOGIPF,
7352 IPLT_DSTLIST,
7353 base + fdp->fd_name,
7354 NULL);
7355 if (ifp == NULL) {
7356 IPFERROR(144);
7357 errval = ESRCH;
7358 }
7359 } else {
7360 ifp = GETIFP(base + fdp->fd_name, v);
7361 if (ifp == NULL)
7362 ifp = (void *)-1;
7363 }
7364 }
7365 fdp->fd_ptr = ifp;
7366
7367 return (errval);
7368 }
7369
7370
7371 /* ------------------------------------------------------------------------ */
7372 /* Function: ipf_resolvenic */
7373 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */
7374 /* pointer to interface structure for NIC */
7375 /* Parameters: softc(I)- pointer to soft context main structure */
7376 /* name(I) - complete interface name */
7377 /* v(I) - IP protocol version */
7378 /* */
7379 /* Look for a network interface structure that firstly has a matching name */
7380 /* to that passed in and that is also being used for that IP protocol */
7381 /* version (necessary on some platforms where there are separate listings */
7382 /* for both IPv4 and IPv6 on the same physical NIC. */
7383 /* ------------------------------------------------------------------------ */
7384 void *
7385 ipf_resolvenic(ipf_main_softc_t *softc __unused, char *name, int v)
7386 {
7387 void *nic;
7388
7389 if (name[0] == '\0')
7390 return (NULL);
7391
7392 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) {
7393 return (NULL);
7394 }
7395
7396 nic = GETIFP(name, v);
7397 if (nic == NULL)
7398 nic = (void *)-1;
7399 return (nic);
7400 }
7401
7402
7403 /* ------------------------------------------------------------------------ */
7404 /* Function: ipf_token_expire */
7405 /* Returns: None. */
7406 /* Parameters: softc(I) - pointer to soft context main structure */
7407 /* */
7408 /* This function is run every ipf tick to see if there are any tokens that */
7409 /* have been held for too long and need to be freed up. */
7410 /* ------------------------------------------------------------------------ */
7411 void
7412 ipf_token_expire(ipf_main_softc_t *softc)
7413 {
7414 ipftoken_t *it;
7415
7416 WRITE_ENTER(&softc->ipf_tokens);
7417 while ((it = softc->ipf_token_head) != NULL) {
7418 if (it->ipt_die > softc->ipf_ticks)
7419 break;
7420
7421 ipf_token_deref(softc, it);
7422 }
7423 RWLOCK_EXIT(&softc->ipf_tokens);
7424 }
7425
7426
7427 /* ------------------------------------------------------------------------ */
7428 /* Function: ipf_token_flush */
7429 /* Returns: None. */
7430 /* Parameters: softc(I) - pointer to soft context main structure */
7431 /* */
7432 /* Loop through all of the existing tokens and call deref to see if they */
7433 /* can be freed. Normally a function like this might just loop on */
7434 /* ipf_token_head but there is a chance that a token might have a ref count */
7435 /* of greater than one and in that case the reference would drop twice */
7436 /* by code that is only entitled to drop it once. */
7437 /* ------------------------------------------------------------------------ */
7438 static void
7439 ipf_token_flush(ipf_main_softc_t *softc)
7440 {
7441 ipftoken_t *it, *next;
7442
7443 WRITE_ENTER(&softc->ipf_tokens);
7444 for (it = softc->ipf_token_head; it != NULL; it = next) {
7445 next = it->ipt_next;
7446 (void) ipf_token_deref(softc, it);
7447 }
7448 RWLOCK_EXIT(&softc->ipf_tokens);
7449 }
7450
7451
7452 /* ------------------------------------------------------------------------ */
7453 /* Function: ipf_token_del */
7454 /* Returns: int - 0 = success, else error */
7455 /* Parameters: softc(I)- pointer to soft context main structure */
7456 /* type(I) - the token type to match */
7457 /* uid(I) - uid owning the token */
7458 /* ptr(I) - context pointer for the token */
7459 /* */
7460 /* This function looks for a token in the current list that matches up */
7461 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */
7462 /* call ipf_token_dewref() to remove it from the list. In the event that */
7463 /* the token has a reference held elsewhere, setting ipt_complete to 2 */
7464 /* enables debugging to distinguish between the two paths that ultimately */
7465 /* lead to a token to be deleted. */
7466 /* ------------------------------------------------------------------------ */
7467 int
7468 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr)
7469 {
7470 ipftoken_t *it;
7471 int error;
7472
7473 IPFERROR(82);
7474 error = ESRCH;
7475
7476 WRITE_ENTER(&softc->ipf_tokens);
7477 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
7478 if (ptr == it->ipt_ctx && type == it->ipt_type &&
7479 uid == it->ipt_uid) {
7480 it->ipt_complete = 2;
7481 ipf_token_deref(softc, it);
7482 error = 0;
7483 break;
7484 }
7485 }
7486 RWLOCK_EXIT(&softc->ipf_tokens);
7487
7488 return (error);
7489 }
7490
7491
7492 /* ------------------------------------------------------------------------ */
7493 /* Function: ipf_token_mark_complete */
7494 /* Returns: None. */
7495 /* Parameters: token(I) - pointer to token structure */
7496 /* */
7497 /* Mark a token as being ineligable for being found with ipf_token_find. */
7498 /* ------------------------------------------------------------------------ */
7499 void
7500 ipf_token_mark_complete(ipftoken_t *token)
7501 {
7502 if (token->ipt_complete == 0)
7503 token->ipt_complete = 1;
7504 }
7505
7506
7507 /* ------------------------------------------------------------------------ */
7508 /* Function: ipf_token_find */
7509 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */
7510 /* Parameters: softc(I)- pointer to soft context main structure */
7511 /* type(I) - the token type to match */
7512 /* uid(I) - uid owning the token */
7513 /* ptr(I) - context pointer for the token */
7514 /* */
7515 /* This function looks for a live token in the list of current tokens that */
7516 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */
7517 /* allocated. If one is found then it is moved to the top of the list of */
7518 /* currently active tokens. */
7519 /* ------------------------------------------------------------------------ */
7520 ipftoken_t *
7521 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr)
7522 {
7523 ipftoken_t *it, *new;
7524
7525 KMALLOC(new, ipftoken_t *);
7526 if (new != NULL)
7527 bzero((char *)new, sizeof(*new));
7528
7529 WRITE_ENTER(&softc->ipf_tokens);
7530 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
7531 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
7532 (uid == it->ipt_uid) && (it->ipt_complete < 2))
7533 break;
7534 }
7535
7536 if (it == NULL) {
7537 it = new;
7538 new = NULL;
7539 if (it == NULL) {
7540 RWLOCK_EXIT(&softc->ipf_tokens);
7541 return (NULL);
7542 }
7543 it->ipt_ctx = ptr;
7544 it->ipt_uid = uid;
7545 it->ipt_type = type;
7546 it->ipt_ref = 1;
7547 } else {
7548 if (new != NULL) {
7549 KFREE(new);
7550 new = NULL;
7551 }
7552
7553 if (it->ipt_complete > 0)
7554 it = NULL;
7555 else
7556 ipf_token_unlink(softc, it);
7557 }
7558
7559 if (it != NULL) {
7560 it->ipt_pnext = softc->ipf_token_tail;
7561 *softc->ipf_token_tail = it;
7562 softc->ipf_token_tail = &it->ipt_next;
7563 it->ipt_next = NULL;
7564 it->ipt_ref++;
7565
7566 it->ipt_die = softc->ipf_ticks + 20;
7567 }
7568
7569 RWLOCK_EXIT(&softc->ipf_tokens);
7570
7571 return (it);
7572 }
7573
7574
7575 /* ------------------------------------------------------------------------ */
7576 /* Function: ipf_token_unlink */
7577 /* Returns: None. */
7578 /* Parameters: softc(I) - pointer to soft context main structure */
7579 /* token(I) - pointer to token structure */
7580 /* Write Locks: ipf_tokens */
7581 /* */
7582 /* This function unlinks a token structure from the linked list of tokens */
7583 /* that "own" it. The head pointer never needs to be explicitly adjusted */
7584 /* but the tail does due to the linked list implementation. */
7585 /* ------------------------------------------------------------------------ */
7586 static void
7587 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token)
7588 {
7589
7590 if (softc->ipf_token_tail == &token->ipt_next)
7591 softc->ipf_token_tail = token->ipt_pnext;
7592
7593 *token->ipt_pnext = token->ipt_next;
7594 if (token->ipt_next != NULL)
7595 token->ipt_next->ipt_pnext = token->ipt_pnext;
7596 token->ipt_next = NULL;
7597 token->ipt_pnext = NULL;
7598 }
7599
7600
7601 /* ------------------------------------------------------------------------ */
7602 /* Function: ipf_token_deref */
7603 /* Returns: int - 0 == token freed, else reference count */
7604 /* Parameters: softc(I) - pointer to soft context main structure */
7605 /* token(I) - pointer to token structure */
7606 /* Write Locks: ipf_tokens */
7607 /* */
7608 /* Drop the reference count on the token structure and if it drops to zero, */
7609 /* call the dereference function for the token type because it is then */
7610 /* possible to free the token data structure. */
7611 /* ------------------------------------------------------------------------ */
7612 int
7613 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token)
7614 {
7615 void *data, **datap;
7616
7617 ASSERT(token->ipt_ref > 0);
7618 token->ipt_ref--;
7619 if (token->ipt_ref > 0)
7620 return (token->ipt_ref);
7621
7622 data = token->ipt_data;
7623 datap = &data;
7624
7625 if ((data != NULL) && (data != (void *)-1)) {
7626 switch (token->ipt_type)
7627 {
7628 case IPFGENITER_IPF :
7629 (void) ipf_derefrule(softc, (frentry_t **)datap);
7630 break;
7631 case IPFGENITER_IPNAT :
7632 WRITE_ENTER(&softc->ipf_nat);
7633 ipf_nat_rule_deref(softc, (ipnat_t **)datap);
7634 RWLOCK_EXIT(&softc->ipf_nat);
7635 break;
7636 case IPFGENITER_NAT :
7637 ipf_nat_deref(softc, (nat_t **)datap);
7638 break;
7639 case IPFGENITER_STATE :
7640 ipf_state_deref(softc, (ipstate_t **)datap);
7641 break;
7642 case IPFGENITER_FRAG :
7643 ipf_frag_pkt_deref(softc, (ipfr_t **)datap);
7644 break;
7645 case IPFGENITER_NATFRAG :
7646 ipf_frag_nat_deref(softc, (ipfr_t **)datap);
7647 break;
7648 case IPFGENITER_HOSTMAP :
7649 WRITE_ENTER(&softc->ipf_nat);
7650 ipf_nat_hostmapdel(softc, (hostmap_t **)datap);
7651 RWLOCK_EXIT(&softc->ipf_nat);
7652 break;
7653 default :
7654 ipf_lookup_iterderef(softc, token->ipt_type, data);
7655 break;
7656 }
7657 }
7658
7659 ipf_token_unlink(softc, token);
7660 KFREE(token);
7661 return (0);
7662 }
7663
7664
7665 /* ------------------------------------------------------------------------ */
7666 /* Function: ipf_nextrule */
7667 /* Returns: frentry_t * - NULL == no more rules, else pointer to next */
7668 /* Parameters: softc(I) - pointer to soft context main structure */
7669 /* fr(I) - pointer to filter rule */
7670 /* out(I) - 1 == out rules, 0 == input rules */
7671 /* */
7672 /* Starting with "fr", find the next rule to visit. This includes visiting */
7673 /* the list of rule groups if either fr is NULL (empty list) or it is the */
7674 /* last rule in the list. When walking rule lists, it is either input or */
7675 /* output rules that are returned, never both. */
7676 /* ------------------------------------------------------------------------ */
7677 static frentry_t *
7678 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, frentry_t *fr,
7679 int out)
7680 {
7681 frentry_t *next;
7682 frgroup_t *fg;
7683
7684 if (fr != NULL && fr->fr_group != -1) {
7685 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group,
7686 unit, active, NULL);
7687 if (fg != NULL)
7688 fg = fg->fg_next;
7689 } else {
7690 fg = softc->ipf_groups[unit][active];
7691 }
7692
7693 while (fg != NULL) {
7694 next = fg->fg_start;
7695 while (next != NULL) {
7696 if (out) {
7697 if (next->fr_flags & FR_OUTQUE)
7698 return (next);
7699 } else if (next->fr_flags & FR_INQUE) {
7700 return (next);
7701 }
7702 next = next->fr_next;
7703 }
7704 if (next == NULL)
7705 fg = fg->fg_next;
7706 }
7707
7708 return (NULL);
7709 }
7710
7711 /* ------------------------------------------------------------------------ */
7712 /* Function: ipf_getnextrule */
7713 /* Returns: int - 0 = success, else error */
7714 /* Parameters: softc(I)- pointer to soft context main structure */
7715 /* t(I) - pointer to destination information to resolve */
7716 /* ptr(I) - pointer to ipfobj_t to copyin from user space */
7717 /* */
7718 /* This function's first job is to bring in the ipfruleiter_t structure via */
7719 /* the ipfobj_t structure to determine what should be the next rule to */
7720 /* return. Once the ipfruleiter_t has been brought in, it then tries to */
7721 /* find the 'next rule'. This may include searching rule group lists or */
7722 /* just be as simple as looking at the 'next' field in the rule structure. */
7723 /* When we have found the rule to return, increase its reference count and */
7724 /* if we used an existing rule to get here, decrease its reference count. */
7725 /* ------------------------------------------------------------------------ */
7726 int
7727 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr)
7728 {
7729 frentry_t *fr, *next, zero;
7730 ipfruleiter_t it;
7731 int error, out;
7732 frgroup_t *fg;
7733 ipfobj_t obj;
7734 int predict;
7735 char *dst;
7736 int unit;
7737
7738 if (t == NULL || ptr == NULL) {
7739 IPFERROR(84);
7740 return (EFAULT);
7741 }
7742
7743 error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER);
7744 if (error != 0)
7745 return (error);
7746
7747 if ((it.iri_inout < 0) || (it.iri_inout > 3)) {
7748 IPFERROR(85);
7749 return (EINVAL);
7750 }
7751 if ((it.iri_active != 0) && (it.iri_active != 1)) {
7752 IPFERROR(86);
7753 return (EINVAL);
7754 }
7755 if (it.iri_nrules == 0) {
7756 IPFERROR(87);
7757 return (ENOSPC);
7758 }
7759 if (it.iri_rule == NULL) {
7760 IPFERROR(88);
7761 return (EFAULT);
7762 }
7763
7764 fg = NULL;
7765 fr = t->ipt_data;
7766 if ((it.iri_inout & F_OUT) != 0)
7767 out = 1;
7768 else
7769 out = 0;
7770 if ((it.iri_inout & F_ACIN) != 0)
7771 unit = IPL_LOGCOUNT;
7772 else
7773 unit = IPL_LOGIPF;
7774
7775 READ_ENTER(&softc->ipf_mutex);
7776 if (fr == NULL) {
7777 if (*it.iri_group == '\0') {
7778 if (unit == IPL_LOGCOUNT) {
7779 next = softc->ipf_acct[out][it.iri_active];
7780 } else {
7781 next = softc->ipf_rules[out][it.iri_active];
7782 }
7783 if (next == NULL)
7784 next = ipf_nextrule(softc, it.iri_active,
7785 unit, NULL, out);
7786 } else {
7787 fg = ipf_findgroup(softc, it.iri_group, unit,
7788 it.iri_active, NULL);
7789 if (fg != NULL)
7790 next = fg->fg_start;
7791 else
7792 next = NULL;
7793 }
7794 } else {
7795 next = fr->fr_next;
7796 if (next == NULL)
7797 next = ipf_nextrule(softc, it.iri_active, unit,
7798 fr, out);
7799 }
7800
7801 if (next != NULL && next->fr_next != NULL)
7802 predict = 1;
7803 else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL)
7804 predict = 1;
7805 else
7806 predict = 0;
7807
7808 if (fr != NULL)
7809 (void) ipf_derefrule(softc, &fr);
7810
7811 obj.ipfo_type = IPFOBJ_FRENTRY;
7812 dst = (char *)it.iri_rule;
7813
7814 if (next != NULL) {
7815 obj.ipfo_size = next->fr_size;
7816 MUTEX_ENTER(&next->fr_lock);
7817 next->fr_ref++;
7818 MUTEX_EXIT(&next->fr_lock);
7819 t->ipt_data = next;
7820 } else {
7821 obj.ipfo_size = sizeof(frentry_t);
7822 bzero(&zero, sizeof(zero));
7823 next = &zero;
7824 t->ipt_data = NULL;
7825 }
7826 it.iri_rule = predict ? next : NULL;
7827 if (predict == 0)
7828 ipf_token_mark_complete(t);
7829
7830 RWLOCK_EXIT(&softc->ipf_mutex);
7831
7832 obj.ipfo_ptr = dst;
7833 error = ipf_outobjk(softc, &obj, next);
7834 if (error == 0 && t->ipt_data != NULL) {
7835 dst += obj.ipfo_size;
7836 if (next->fr_data != NULL) {
7837 ipfobj_t dobj;
7838
7839 if (next->fr_type == FR_T_IPFEXPR)
7840 dobj.ipfo_type = IPFOBJ_IPFEXPR;
7841 else
7842 dobj.ipfo_type = IPFOBJ_FRIPF;
7843 dobj.ipfo_size = next->fr_dsize;
7844 dobj.ipfo_rev = obj.ipfo_rev;
7845 dobj.ipfo_ptr = dst;
7846 error = ipf_outobjk(softc, &dobj, next->fr_data);
7847 }
7848 }
7849
7850 if ((fr != NULL) && (next == &zero))
7851 (void) ipf_derefrule(softc, &fr);
7852
7853 return (error);
7854 }
7855
7856
7857 /* ------------------------------------------------------------------------ */
7858 /* Function: ipf_frruleiter */
7859 /* Returns: int - 0 = success, else error */
7860 /* Parameters: softc(I)- pointer to soft context main structure */
7861 /* data(I) - the token type to match */
7862 /* uid(I) - uid owning the token */
7863 /* ptr(I) - context pointer for the token */
7864 /* */
7865 /* This function serves as a stepping stone between ipf_ipf_ioctl and */
7866 /* ipf_getnextrule. It's role is to find the right token in the kernel for */
7867 /* the process doing the ioctl and use that to ask for the next rule. */
7868 /* ------------------------------------------------------------------------ */
7869 static int
7870 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
7871 {
7872 ipftoken_t *token;
7873 ipfruleiter_t it;
7874 ipfobj_t obj;
7875 int error;
7876
7877 token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx);
7878 if (token != NULL) {
7879 error = ipf_getnextrule(softc, token, data);
7880 WRITE_ENTER(&softc->ipf_tokens);
7881 ipf_token_deref(softc, token);
7882 RWLOCK_EXIT(&softc->ipf_tokens);
7883 } else {
7884 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER);
7885 if (error != 0)
7886 return (error);
7887 it.iri_rule = NULL;
7888 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER);
7889 }
7890
7891 return (error);
7892 }
7893
7894
7895 /* ------------------------------------------------------------------------ */
7896 /* Function: ipf_geniter */
7897 /* Returns: int - 0 = success, else error */
7898 /* Parameters: softc(I) - pointer to soft context main structure */
7899 /* token(I) - pointer to ipftoken_t structure */
7900 /* itp(I) - pointer to iterator data */
7901 /* */
7902 /* Decide which iterator function to call using information passed through */
7903 /* the ipfgeniter_t structure at itp. */
7904 /* ------------------------------------------------------------------------ */
7905 static int
7906 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp)
7907 {
7908 int error;
7909
7910 switch (itp->igi_type)
7911 {
7912 case IPFGENITER_FRAG :
7913 error = ipf_frag_pkt_next(softc, token, itp);
7914 break;
7915 default :
7916 IPFERROR(92);
7917 error = EINVAL;
7918 break;
7919 }
7920
7921 return (error);
7922 }
7923
7924
7925 /* ------------------------------------------------------------------------ */
7926 /* Function: ipf_genericiter */
7927 /* Returns: int - 0 = success, else error */
7928 /* Parameters: softc(I)- pointer to soft context main structure */
7929 /* data(I) - the token type to match */
7930 /* uid(I) - uid owning the token */
7931 /* ptr(I) - context pointer for the token */
7932 /* */
7933 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */
7934 /* ------------------------------------------------------------------------ */
7935 int
7936 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
7937 {
7938 ipftoken_t *token;
7939 ipfgeniter_t iter;
7940 int error;
7941
7942 error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER);
7943 if (error != 0)
7944 return (error);
7945
7946 token = ipf_token_find(softc, iter.igi_type, uid, ctx);
7947 if (token != NULL) {
7948 token->ipt_subtype = iter.igi_type;
7949 error = ipf_geniter(softc, token, &iter);
7950 WRITE_ENTER(&softc->ipf_tokens);
7951 ipf_token_deref(softc, token);
7952 RWLOCK_EXIT(&softc->ipf_tokens);
7953 } else {
7954 IPFERROR(93);
7955 error = 0;
7956 }
7957
7958 return (error);
7959 }
7960
7961
7962 /* ------------------------------------------------------------------------ */
7963 /* Function: ipf_ipf_ioctl */
7964 /* Returns: int - 0 = success, else error */
7965 /* Parameters: softc(I)- pointer to soft context main structure */
7966 /* data(I) - the token type to match */
7967 /* cmd(I) - the ioctl command number */
7968 /* mode(I) - mode flags for the ioctl */
7969 /* uid(I) - uid owning the token */
7970 /* ptr(I) - context pointer for the token */
7971 /* */
7972 /* This function handles all of the ioctl command that are actually issued */
7973 /* to the /dev/ipl device. */
7974 /* ------------------------------------------------------------------------ */
7975 int
7976 ipf_ipf_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, int mode,
7977 int uid, void *ctx)
7978 {
7979 friostat_t fio;
7980 int error, tmp;
7981 ipfobj_t obj;
7982 SPL_INT(s);
7983
7984 switch (cmd)
7985 {
7986 case SIOCFRENB :
7987 if (!(mode & FWRITE)) {
7988 IPFERROR(94);
7989 error = EPERM;
7990 } else {
7991 error = BCOPYIN(data, &tmp, sizeof(tmp));
7992 if (error != 0) {
7993 IPFERROR(95);
7994 error = EFAULT;
7995 break;
7996 }
7997
7998 WRITE_ENTER(&softc->ipf_global);
7999 if (tmp) {
8000 if (softc->ipf_running > 0)
8001 error = 0;
8002 else
8003 error = ipfattach(softc);
8004 if (error == 0)
8005 softc->ipf_running = 1;
8006 else
8007 (void) ipfdetach(softc);
8008 } else {
8009 if (softc->ipf_running == 1)
8010 error = ipfdetach(softc);
8011 else
8012 error = 0;
8013 if (error == 0)
8014 softc->ipf_running = -1;
8015 }
8016 RWLOCK_EXIT(&softc->ipf_global);
8017 }
8018 break;
8019
8020 case SIOCIPFSET :
8021 if (!(mode & FWRITE)) {
8022 IPFERROR(96);
8023 error = EPERM;
8024 break;
8025 }
8026 /* FALLTHRU */
8027 case SIOCIPFGETNEXT :
8028 case SIOCIPFGET :
8029 error = ipf_ipftune(softc, cmd, (void *)data);
8030 break;
8031
8032 case SIOCSETFF :
8033 if (!(mode & FWRITE)) {
8034 IPFERROR(97);
8035 error = EPERM;
8036 } else {
8037 error = BCOPYIN(data, &softc->ipf_flags,
8038 sizeof(softc->ipf_flags));
8039 if (error != 0) {
8040 IPFERROR(98);
8041 error = EFAULT;
8042 }
8043 }
8044 break;
8045
8046 case SIOCGETFF :
8047 error = BCOPYOUT(&softc->ipf_flags, data,
8048 sizeof(softc->ipf_flags));
8049 if (error != 0) {
8050 IPFERROR(99);
8051 error = EFAULT;
8052 }
8053 break;
8054
8055 case SIOCFUNCL :
8056 error = ipf_resolvefunc(softc, (void *)data);
8057 break;
8058
8059 case SIOCINAFR :
8060 case SIOCRMAFR :
8061 case SIOCADAFR :
8062 case SIOCZRLST :
8063 if (!(mode & FWRITE)) {
8064 IPFERROR(100);
8065 error = EPERM;
8066 } else {
8067 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
8068 softc->ipf_active, 1);
8069 }
8070 break;
8071
8072 case SIOCINIFR :
8073 case SIOCRMIFR :
8074 case SIOCADIFR :
8075 if (!(mode & FWRITE)) {
8076 IPFERROR(101);
8077 error = EPERM;
8078 } else {
8079 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
8080 1 - softc->ipf_active, 1);
8081 }
8082 break;
8083
8084 case SIOCSWAPA :
8085 if (!(mode & FWRITE)) {
8086 IPFERROR(102);
8087 error = EPERM;
8088 } else {
8089 WRITE_ENTER(&softc->ipf_mutex);
8090 error = BCOPYOUT(&softc->ipf_active, data,
8091 sizeof(softc->ipf_active));
8092 if (error != 0) {
8093 IPFERROR(103);
8094 error = EFAULT;
8095 } else {
8096 softc->ipf_active = 1 - softc->ipf_active;
8097 }
8098 RWLOCK_EXIT(&softc->ipf_mutex);
8099 }
8100 break;
8101
8102 case SIOCGETFS :
8103 error = ipf_inobj(softc, (void *)data, &obj, &fio,
8104 IPFOBJ_IPFSTAT);
8105 if (error != 0)
8106 break;
8107 ipf_getstat(softc, &fio, obj.ipfo_rev);
8108 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT);
8109 break;
8110
8111 case SIOCFRZST :
8112 if (!(mode & FWRITE)) {
8113 IPFERROR(104);
8114 error = EPERM;
8115 } else
8116 error = ipf_zerostats(softc, (caddr_t)data);
8117 break;
8118
8119 case SIOCIPFFL :
8120 if (!(mode & FWRITE)) {
8121 IPFERROR(105);
8122 error = EPERM;
8123 } else {
8124 error = BCOPYIN(data, &tmp, sizeof(tmp));
8125 if (!error) {
8126 tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
8127 error = BCOPYOUT(&tmp, data, sizeof(tmp));
8128 if (error != 0) {
8129 IPFERROR(106);
8130 error = EFAULT;
8131 }
8132 } else {
8133 IPFERROR(107);
8134 error = EFAULT;
8135 }
8136 }
8137 break;
8138
8139 #ifdef USE_INET6
8140 case SIOCIPFL6 :
8141 if (!(mode & FWRITE)) {
8142 IPFERROR(108);
8143 error = EPERM;
8144 } else {
8145 error = BCOPYIN(data, &tmp, sizeof(tmp));
8146 if (!error) {
8147 tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
8148 error = BCOPYOUT(&tmp, data, sizeof(tmp));
8149 if (error != 0) {
8150 IPFERROR(109);
8151 error = EFAULT;
8152 }
8153 } else {
8154 IPFERROR(110);
8155 error = EFAULT;
8156 }
8157 }
8158 break;
8159 #endif
8160
8161 case SIOCSTLCK :
8162 if (!(mode & FWRITE)) {
8163 IPFERROR(122);
8164 error = EPERM;
8165 } else {
8166 error = BCOPYIN(data, &tmp, sizeof(tmp));
8167 if (error == 0) {
8168 ipf_state_setlock(softc->ipf_state_soft, tmp);
8169 ipf_nat_setlock(softc->ipf_nat_soft, tmp);
8170 ipf_frag_setlock(softc->ipf_frag_soft, tmp);
8171 ipf_auth_setlock(softc->ipf_auth_soft, tmp);
8172 } else {
8173 IPFERROR(111);
8174 error = EFAULT;
8175 }
8176 }
8177 break;
8178
8179 #ifdef IPFILTER_LOG
8180 case SIOCIPFFB :
8181 if (!(mode & FWRITE)) {
8182 IPFERROR(112);
8183 error = EPERM;
8184 } else {
8185 tmp = ipf_log_clear(softc, IPL_LOGIPF);
8186 error = BCOPYOUT(&tmp, data, sizeof(tmp));
8187 if (error) {
8188 IPFERROR(113);
8189 error = EFAULT;
8190 }
8191 }
8192 break;
8193 #endif /* IPFILTER_LOG */
8194
8195 case SIOCFRSYN :
8196 if (!(mode & FWRITE)) {
8197 IPFERROR(114);
8198 error = EPERM;
8199 } else {
8200 WRITE_ENTER(&softc->ipf_global);
8201 #if (SOLARIS && defined(_KERNEL)) && !defined(INSTANCES)
8202 error = ipfsync();
8203 #else
8204 ipf_sync(softc, NULL);
8205 error = 0;
8206 #endif
8207 RWLOCK_EXIT(&softc->ipf_global);
8208
8209 }
8210 break;
8211
8212 case SIOCGFRST :
8213 error = ipf_outobj(softc, (void *)data,
8214 ipf_frag_stats(softc->ipf_frag_soft),
8215 IPFOBJ_FRAGSTAT);
8216 break;
8217
8218 #ifdef IPFILTER_LOG
8219 case FIONREAD :
8220 tmp = ipf_log_bytesused(softc, IPL_LOGIPF);
8221 error = BCOPYOUT(&tmp, data, sizeof(tmp));
8222 break;
8223 #endif
8224
8225 case SIOCIPFITER :
8226 SPL_SCHED(s);
8227 error = ipf_frruleiter(softc, data, uid, ctx);
8228 SPL_X(s);
8229 break;
8230
8231 case SIOCGENITER :
8232 SPL_SCHED(s);
8233 error = ipf_genericiter(softc, data, uid, ctx);
8234 SPL_X(s);
8235 break;
8236
8237 case SIOCIPFDELTOK :
8238 error = BCOPYIN(data, &tmp, sizeof(tmp));
8239 if (error == 0) {
8240 SPL_SCHED(s);
8241 error = ipf_token_del(softc, tmp, uid, ctx);
8242 SPL_X(s);
8243 }
8244 break;
8245
8246 default :
8247 IPFERROR(115);
8248 error = EINVAL;
8249 break;
8250 }
8251
8252 return (error);
8253 }
8254
8255
8256 /* ------------------------------------------------------------------------ */
8257 /* Function: ipf_decaps */
8258 /* Returns: int - -1 == decapsulation failed, else bit mask of */
8259 /* flags indicating packet filtering decision. */
8260 /* Parameters: fin(I) - pointer to packet information */
8261 /* pass(I) - IP protocol version to match */
8262 /* l5proto(I) - layer 5 protocol to decode UDP data as. */
8263 /* */
8264 /* This function is called for packets that are wrapt up in other packets, */
8265 /* for example, an IP packet that is the entire data segment for another IP */
8266 /* packet. If the basic constraints for this are satisfied, change the */
8267 /* buffer to point to the start of the inner packet and start processing */
8268 /* rules belonging to the head group this rule specifies. */
8269 /* ------------------------------------------------------------------------ */
8270 u_32_t
8271 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto)
8272 {
8273 fr_info_t fin2, *fino = NULL;
8274 int elen, hlen, nh;
8275 grehdr_t gre;
8276 ip_t *ip;
8277 mb_t *m;
8278
8279 if ((fin->fin_flx & FI_COALESCE) == 0)
8280 if (ipf_coalesce(fin) == -1)
8281 goto cantdecaps;
8282
8283 m = fin->fin_m;
8284 hlen = fin->fin_hlen;
8285
8286 switch (fin->fin_p)
8287 {
8288 case IPPROTO_UDP :
8289 /*
8290 * In this case, the specific protocol being decapsulated
8291 * inside UDP frames comes from the rule.
8292 */
8293 nh = fin->fin_fr->fr_icode;
8294 break;
8295
8296 case IPPROTO_GRE : /* 47 */
8297 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre));
8298 hlen += sizeof(grehdr_t);
8299 if (gre.gr_R|gre.gr_s)
8300 goto cantdecaps;
8301 if (gre.gr_C)
8302 hlen += 4;
8303 if (gre.gr_K)
8304 hlen += 4;
8305 if (gre.gr_S)
8306 hlen += 4;
8307
8308 nh = IPPROTO_IP;
8309
8310 /*
8311 * If the routing options flag is set, validate that it is
8312 * there and bounce over it.
8313 */
8314 #if 0
8315 /* This is really heavy weight and lots of room for error, */
8316 /* so for now, put it off and get the simple stuff right. */
8317 if (gre.gr_R) {
8318 u_char off, len, *s;
8319 u_short af;
8320 int end;
8321
8322 end = 0;
8323 s = fin->fin_dp;
8324 s += hlen;
8325 aplen = fin->fin_plen - hlen;
8326 while (aplen > 3) {
8327 af = (s[0] << 8) | s[1];
8328 off = s[2];
8329 len = s[3];
8330 aplen -= 4;
8331 s += 4;
8332 if (af == 0 && len == 0) {
8333 end = 1;
8334 break;
8335 }
8336 if (aplen < len)
8337 break;
8338 s += len;
8339 aplen -= len;
8340 }
8341 if (end != 1)
8342 goto cantdecaps;
8343 hlen = s - (u_char *)fin->fin_dp;
8344 }
8345 #endif
8346 break;
8347
8348 #ifdef IPPROTO_IPIP
8349 case IPPROTO_IPIP : /* 4 */
8350 #endif
8351 nh = IPPROTO_IP;
8352 break;
8353
8354 default : /* Includes ESP, AH is special for IPv4 */
8355 goto cantdecaps;
8356 }
8357
8358 switch (nh)
8359 {
8360 case IPPROTO_IP :
8361 case IPPROTO_IPV6 :
8362 break;
8363 default :
8364 goto cantdecaps;
8365 }
8366
8367 bcopy((char *)fin, (char *)&fin2, sizeof(fin2));
8368 fino = fin;
8369 fin = &fin2;
8370 elen = hlen;
8371 #if SOLARIS && defined(_KERNEL)
8372 m->b_rptr += elen;
8373 #else
8374 m->m_data += elen;
8375 m->m_len -= elen;
8376 #endif
8377 fin->fin_plen -= elen;
8378
8379 ip = (ip_t *)((char *)fin->fin_ip + elen);
8380
8381 /*
8382 * Make sure we have at least enough data for the network layer
8383 * header.
8384 */
8385 if (IP_V(ip) == 4)
8386 hlen = IP_HL(ip) << 2;
8387 #ifdef USE_INET6
8388 else if (IP_V(ip) == 6)
8389 hlen = sizeof(ip6_t);
8390 #endif
8391 else
8392 goto cantdecaps2;
8393
8394 if (fin->fin_plen < hlen)
8395 goto cantdecaps2;
8396
8397 fin->fin_dp = (char *)ip + hlen;
8398
8399 if (IP_V(ip) == 4) {
8400 /*
8401 * Perform IPv4 header checksum validation.
8402 */
8403 if (ipf_cksum((u_short *)ip, hlen))
8404 goto cantdecaps2;
8405 }
8406
8407 if (ipf_makefrip(hlen, ip, fin) == -1) {
8408 cantdecaps2:
8409 if (m != NULL) {
8410 #if SOLARIS && defined(_KERNEL)
8411 m->b_rptr -= elen;
8412 #else
8413 m->m_data -= elen;
8414 m->m_len += elen;
8415 #endif
8416 }
8417 cantdecaps:
8418 DT1(frb_decapfrip, fr_info_t *, fin);
8419 pass &= ~FR_CMDMASK;
8420 pass |= FR_BLOCK|FR_QUICK;
8421 fin->fin_reason = FRB_DECAPFRIP;
8422 return (-1);
8423 }
8424
8425 pass = ipf_scanlist(fin, pass);
8426
8427 /*
8428 * Copy the packet filter "result" fields out of the fr_info_t struct
8429 * that is local to the decapsulation processing and back into the
8430 * one we were called with.
8431 */
8432 fino->fin_flx = fin->fin_flx;
8433 fino->fin_rev = fin->fin_rev;
8434 fino->fin_icode = fin->fin_icode;
8435 fino->fin_rule = fin->fin_rule;
8436 (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN);
8437 fino->fin_fr = fin->fin_fr;
8438 fino->fin_error = fin->fin_error;
8439 fino->fin_mp = fin->fin_mp;
8440 fino->fin_m = fin->fin_m;
8441 m = fin->fin_m;
8442 if (m != NULL) {
8443 #if SOLARIS && defined(_KERNEL)
8444 m->b_rptr -= elen;
8445 #else
8446 m->m_data -= elen;
8447 m->m_len += elen;
8448 #endif
8449 }
8450 return (pass);
8451 }
8452
8453
8454 /* ------------------------------------------------------------------------ */
8455 /* Function: ipf_matcharray_load */
8456 /* Returns: int - 0 = success, else error */
8457 /* Parameters: softc(I) - pointer to soft context main structure */
8458 /* data(I) - pointer to ioctl data */
8459 /* objp(I) - ipfobj_t structure to load data into */
8460 /* arrayptr(I) - pointer to location to store array pointer */
8461 /* */
8462 /* This function loads in a mathing array through the ipfobj_t struct that */
8463 /* describes it. Sanity checking and array size limitations are enforced */
8464 /* in this function to prevent userspace from trying to load in something */
8465 /* that is insanely big. Once the size of the array is known, the memory */
8466 /* required is malloc'd and returned through changing *arrayptr. The */
8467 /* contents of the array are verified before returning. Only in the event */
8468 /* of a successful call is the caller required to free up the malloc area. */
8469 /* ------------------------------------------------------------------------ */
8470 int
8471 ipf_matcharray_load(ipf_main_softc_t *softc, caddr_t data, ipfobj_t *objp,
8472 int **arrayptr)
8473 {
8474 int arraysize, *array, error;
8475
8476 *arrayptr = NULL;
8477
8478 error = BCOPYIN(data, objp, sizeof(*objp));
8479 if (error != 0) {
8480 IPFERROR(116);
8481 return (EFAULT);
8482 }
8483
8484 if (objp->ipfo_type != IPFOBJ_IPFEXPR) {
8485 IPFERROR(117);
8486 return (EINVAL);
8487 }
8488
8489 if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) ||
8490 (objp->ipfo_size > 1024)) {
8491 IPFERROR(118);
8492 return (EINVAL);
8493 }
8494
8495 arraysize = objp->ipfo_size * sizeof(*array);
8496 KMALLOCS(array, int *, arraysize);
8497 if (array == NULL) {
8498 IPFERROR(119);
8499 return (ENOMEM);
8500 }
8501
8502 error = COPYIN(objp->ipfo_ptr, array, arraysize);
8503 if (error != 0) {
8504 KFREES(array, arraysize);
8505 IPFERROR(120);
8506 return (EFAULT);
8507 }
8508
8509 if (ipf_matcharray_verify(array, arraysize) != 0) {
8510 KFREES(array, arraysize);
8511 IPFERROR(121);
8512 return (EINVAL);
8513 }
8514
8515 *arrayptr = array;
8516 return (0);
8517 }
8518
8519
8520 /* ------------------------------------------------------------------------ */
8521 /* Function: ipf_matcharray_verify */
8522 /* Returns: Nil */
8523 /* Parameters: array(I) - pointer to matching array */
8524 /* arraysize(I) - number of elements in the array */
8525 /* */
8526 /* Verify the contents of a matching array by stepping through each element */
8527 /* in it. The actual commands in the array are not verified for */
8528 /* correctness, only that all of the sizes are correctly within limits. */
8529 /* ------------------------------------------------------------------------ */
8530 int
8531 ipf_matcharray_verify(int *array, int arraysize)
8532 {
8533 u_int i, nelem, maxidx;
8534 ipfexp_t *e;
8535
8536 nelem = arraysize / sizeof(*array);
8537
8538 /*
8539 * Currently, it makes no sense to have an array less than 6
8540 * elements long - the initial size at the from, a single operation
8541 * (minimum 4 in length) and a trailer, for a total of 6.
8542 */
8543 if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) {
8544 return (-1);
8545 }
8546
8547 /*
8548 * Verify the size of data pointed to by array with how long
8549 * the array claims to be itself.
8550 */
8551 if (array[0] * sizeof(*array) != arraysize) {
8552 return (-1);
8553 }
8554
8555 maxidx = nelem - 1;
8556 /*
8557 * The last opcode in this array should be an IPF_EXP_END.
8558 */
8559 if (array[maxidx] != IPF_EXP_END) {
8560 return (-1);
8561 }
8562
8563 for (i = 1; i < maxidx; ) {
8564 e = (ipfexp_t *)(array + i);
8565
8566 /*
8567 * The length of the bits to check must be at least 1
8568 * (or else there is nothing to comapre with!) and it
8569 * cannot exceed the length of the data present.
8570 */
8571 if ((e->ipfe_size < 1 ) ||
8572 (e->ipfe_size + i > maxidx)) {
8573 return (-1);
8574 }
8575 i += e->ipfe_size;
8576 }
8577 return (0);
8578 }
8579
8580
8581 /* ------------------------------------------------------------------------ */
8582 /* Function: ipf_fr_matcharray */
8583 /* Returns: int - 0 = match failed, else positive match */
8584 /* Parameters: fin(I) - pointer to packet information */
8585 /* array(I) - pointer to matching array */
8586 /* */
8587 /* This function is used to apply a matching array against a packet and */
8588 /* return an indication of whether or not the packet successfully matches */
8589 /* all of the commands in it. */
8590 /* ------------------------------------------------------------------------ */
8591 static int
8592 ipf_fr_matcharray(fr_info_t *fin, int *array)
8593 {
8594 u_int i, n, *x, rv, p;
8595 ipfexp_t *e;
8596
8597 rv = 0;
8598 n = array[0];
8599 x = array + 1;
8600
8601 for (; n > 0; x += 3 + x[3], rv = 0) {
8602 e = (ipfexp_t *)x;
8603 if (e->ipfe_cmd == IPF_EXP_END)
8604 break;
8605 n -= e->ipfe_size;
8606
8607 /*
8608 * The upper 16 bits currently store the protocol value.
8609 * This is currently used with TCP and UDP port compares and
8610 * allows "tcp.port = 80" without requiring an explicit
8611 " "ip.pr = tcp" first.
8612 */
8613 p = e->ipfe_cmd >> 16;
8614 if ((p != 0) && (p != fin->fin_p))
8615 break;
8616
8617 switch (e->ipfe_cmd)
8618 {
8619 case IPF_EXP_IP_PR :
8620 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8621 rv |= (fin->fin_p == e->ipfe_arg0[i]);
8622 }
8623 break;
8624
8625 case IPF_EXP_IP_SRCADDR :
8626 if (fin->fin_v != 4)
8627 break;
8628 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8629 rv |= ((fin->fin_saddr &
8630 e->ipfe_arg0[i * 2 + 1]) ==
8631 e->ipfe_arg0[i * 2]);
8632 }
8633 break;
8634
8635 case IPF_EXP_IP_DSTADDR :
8636 if (fin->fin_v != 4)
8637 break;
8638 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8639 rv |= ((fin->fin_daddr &
8640 e->ipfe_arg0[i * 2 + 1]) ==
8641 e->ipfe_arg0[i * 2]);
8642 }
8643 break;
8644
8645 case IPF_EXP_IP_ADDR :
8646 if (fin->fin_v != 4)
8647 break;
8648 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8649 rv |= ((fin->fin_saddr &
8650 e->ipfe_arg0[i * 2 + 1]) ==
8651 e->ipfe_arg0[i * 2]) ||
8652 ((fin->fin_daddr &
8653 e->ipfe_arg0[i * 2 + 1]) ==
8654 e->ipfe_arg0[i * 2]);
8655 }
8656 break;
8657
8658 #ifdef USE_INET6
8659 case IPF_EXP_IP6_SRCADDR :
8660 if (fin->fin_v != 6)
8661 break;
8662 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8663 rv |= IP6_MASKEQ(&fin->fin_src6,
8664 &e->ipfe_arg0[i * 8 + 4],
8665 &e->ipfe_arg0[i * 8]);
8666 }
8667 break;
8668
8669 case IPF_EXP_IP6_DSTADDR :
8670 if (fin->fin_v != 6)
8671 break;
8672 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8673 rv |= IP6_MASKEQ(&fin->fin_dst6,
8674 &e->ipfe_arg0[i * 8 + 4],
8675 &e->ipfe_arg0[i * 8]);
8676 }
8677 break;
8678
8679 case IPF_EXP_IP6_ADDR :
8680 if (fin->fin_v != 6)
8681 break;
8682 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8683 rv |= IP6_MASKEQ(&fin->fin_src6,
8684 &e->ipfe_arg0[i * 8 + 4],
8685 &e->ipfe_arg0[i * 8]) ||
8686 IP6_MASKEQ(&fin->fin_dst6,
8687 &e->ipfe_arg0[i * 8 + 4],
8688 &e->ipfe_arg0[i * 8]);
8689 }
8690 break;
8691 #endif
8692
8693 case IPF_EXP_UDP_PORT :
8694 case IPF_EXP_TCP_PORT :
8695 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8696 rv |= (fin->fin_sport == e->ipfe_arg0[i]) ||
8697 (fin->fin_dport == e->ipfe_arg0[i]);
8698 }
8699 break;
8700
8701 case IPF_EXP_UDP_SPORT :
8702 case IPF_EXP_TCP_SPORT :
8703 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8704 rv |= (fin->fin_sport == e->ipfe_arg0[i]);
8705 }
8706 break;
8707
8708 case IPF_EXP_UDP_DPORT :
8709 case IPF_EXP_TCP_DPORT :
8710 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8711 rv |= (fin->fin_dport == e->ipfe_arg0[i]);
8712 }
8713 break;
8714
8715 case IPF_EXP_TCP_FLAGS :
8716 for (i = 0; !rv && i < e->ipfe_narg; i++) {
8717 rv |= ((fin->fin_tcpf &
8718 e->ipfe_arg0[i * 2 + 1]) ==
8719 e->ipfe_arg0[i * 2]);
8720 }
8721 break;
8722 }
8723 rv ^= e->ipfe_not;
8724
8725 if (rv == 0)
8726 break;
8727 }
8728
8729 return (rv);
8730 }
8731
8732
8733 /* ------------------------------------------------------------------------ */
8734 /* Function: ipf_queueflush */
8735 /* Returns: int - number of entries flushed (0 = none) */
8736 /* Parameters: softc(I) - pointer to soft context main structure */
8737 /* deletefn(I) - function to call to delete entry */
8738 /* ipfqs(I) - top of the list of ipf internal queues */
8739 /* userqs(I) - top of the list of user defined timeouts */
8740 /* */
8741 /* This fucntion gets called when the state/NAT hash tables fill up and we */
8742 /* need to try a bit harder to free up some space. The algorithm used here */
8743 /* split into two parts but both halves have the same goal: to reduce the */
8744 /* number of connections considered to be "active" to the low watermark. */
8745 /* There are two steps in doing this: */
8746 /* 1) Remove any TCP connections that are already considered to be "closed" */
8747 /* but have not yet been removed from the state table. The two states */
8748 /* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */
8749 /* candidates for this style of removal. If freeing up entries in */
8750 /* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */
8751 /* we do not go on to step 2. */
8752 /* */
8753 /* 2) Look for the oldest entries on each timeout queue and free them if */
8754 /* they are within the given window we are considering. Where the */
8755 /* window starts and the steps taken to increase its size depend upon */
8756 /* how long ipf has been running (ipf_ticks.) Anything modified in the */
8757 /* last 30 seconds is not touched. */
8758 /* touched */
8759 /* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */
8760 /* | | | | | | */
8761 /* future <--+----------+--------+-----------+-----+-----+-----------> past */
8762 /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */
8763 /* */
8764 /* Points to note: */
8765 /* - tqe_die is the time, in the future, when entries die. */
8766 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */
8767 /* ticks. */
8768 /* - tqe_touched is when the entry was last used by NAT/state */
8769 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */
8770 /* ipf_ticks any given timeout queue and vice versa. */
8771 /* - both tqe_die and tqe_touched increase over time */
8772 /* - timeout queues are sorted with the highest value of tqe_die at the */
8773 /* bottom and therefore the smallest values of each are at the top */
8774 /* - the pointer passed in as ipfqs should point to an array of timeout */
8775 /* queues representing each of the TCP states */
8776 /* */
8777 /* We start by setting up a maximum range to scan for things to move of */
8778 /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */
8779 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */
8780 /* we start again with a new value for "iend" and "istart". This is */
8781 /* continued until we either finish the scan of 30 second intervals or the */
8782 /* low water mark is reached. */
8783 /* ------------------------------------------------------------------------ */
8784 int
8785 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn,
8786 ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low)
8787 {
8788 u_long interval, istart, iend;
8789 ipftq_t *ifq, *ifqnext;
8790 ipftqent_t *tqe, *tqn;
8791 int removed = 0;
8792
8793 for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) {
8794 tqn = tqe->tqe_next;
8795 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8796 removed++;
8797 }
8798 if ((*activep * 100 / size) > low) {
8799 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head;
8800 ((tqe = tqn) != NULL); ) {
8801 tqn = tqe->tqe_next;
8802 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8803 removed++;
8804 }
8805 }
8806
8807 if ((*activep * 100 / size) <= low) {
8808 return (removed);
8809 }
8810
8811 /*
8812 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
8813 * used then the operations are upgraded to floating point
8814 * and kernels don't like floating point...
8815 */
8816 if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
8817 istart = IPF_TTLVAL(86400 * 4);
8818 interval = IPF_TTLVAL(43200);
8819 } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
8820 istart = IPF_TTLVAL(43200);
8821 interval = IPF_TTLVAL(1800);
8822 } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) {
8823 istart = IPF_TTLVAL(1800);
8824 interval = IPF_TTLVAL(30);
8825 } else {
8826 return (0);
8827 }
8828 if (istart > softc->ipf_ticks) {
8829 if (softc->ipf_ticks - interval < interval)
8830 istart = interval;
8831 else
8832 istart = (softc->ipf_ticks / interval) * interval;
8833 }
8834
8835 iend = softc->ipf_ticks - interval;
8836
8837 while ((*activep * 100 / size) > low) {
8838 u_long try;
8839
8840 try = softc->ipf_ticks - istart;
8841
8842 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
8843 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
8844 if (try < tqe->tqe_touched)
8845 break;
8846 tqn = tqe->tqe_next;
8847 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8848 removed++;
8849 }
8850 }
8851
8852 for (ifq = userqs; ifq != NULL; ifq = ifqnext) {
8853 ifqnext = ifq->ifq_next;
8854
8855 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
8856 if (try < tqe->tqe_touched)
8857 break;
8858 tqn = tqe->tqe_next;
8859 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8860 removed++;
8861 }
8862 }
8863
8864 if (try >= iend) {
8865 if (interval == IPF_TTLVAL(43200)) {
8866 interval = IPF_TTLVAL(1800);
8867 } else if (interval == IPF_TTLVAL(1800)) {
8868 interval = IPF_TTLVAL(30);
8869 } else {
8870 break;
8871 }
8872 if (interval >= softc->ipf_ticks)
8873 break;
8874
8875 iend = softc->ipf_ticks - interval;
8876 }
8877 istart -= interval;
8878 }
8879
8880 return (removed);
8881 }
8882
8883
8884 /* ------------------------------------------------------------------------ */
8885 /* Function: ipf_deliverlocal */
8886 /* Returns: int - 1 = local address, 0 = non-local address */
8887 /* Parameters: softc(I) - pointer to soft context main structure */
8888 /* ipversion(I) - IP protocol version (4 or 6) */
8889 /* ifp(I) - network interface pointer */
8890 /* ipaddr(I) - IPv4/6 destination address */
8891 /* */
8892 /* This fucntion is used to determine in the address "ipaddr" belongs to */
8893 /* the network interface represented by ifp. */
8894 /* ------------------------------------------------------------------------ */
8895 int
8896 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp,
8897 i6addr_t *ipaddr)
8898 {
8899 i6addr_t addr;
8900 int islocal = 0;
8901
8902 if (ipversion == 4) {
8903 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) {
8904 if (addr.in4.s_addr == ipaddr->in4.s_addr)
8905 islocal = 1;
8906 }
8907
8908 #ifdef USE_INET6
8909 } else if (ipversion == 6) {
8910 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) {
8911 if (IP6_EQ(&addr, ipaddr))
8912 islocal = 1;
8913 }
8914 #endif
8915 }
8916
8917 return (islocal);
8918 }
8919
8920
8921 /* ------------------------------------------------------------------------ */
8922 /* Function: ipf_settimeout */
8923 /* Returns: int - 0 = success, -1 = failure */
8924 /* Parameters: softc(I) - pointer to soft context main structure */
8925 /* t(I) - pointer to tuneable array entry */
8926 /* p(I) - pointer to values passed in to apply */
8927 /* */
8928 /* This function is called to set the timeout values for each distinct */
8929 /* queue timeout that is available. When called, it calls into both the */
8930 /* state and NAT code, telling them to update their timeout queues. */
8931 /* ------------------------------------------------------------------------ */
8932 static int
8933 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t,
8934 ipftuneval_t *p)
8935 {
8936
8937 /*
8938 * ipf_interror should be set by the functions called here, not
8939 * by this function - it's just a middle man.
8940 */
8941 if (ipf_state_settimeout(softc, t, p) == -1)
8942 return (-1);
8943 if (ipf_nat_settimeout(softc, t, p) == -1)
8944 return (-1);
8945 return (0);
8946 }
8947
8948
8949 /* ------------------------------------------------------------------------ */
8950 /* Function: ipf_apply_timeout */
8951 /* Returns: int - 0 = success, -1 = failure */
8952 /* Parameters: head(I) - pointer to tuneable array entry */
8953 /* seconds(I) - pointer to values passed in to apply */
8954 /* */
8955 /* This function applies a timeout of "seconds" to the timeout queue that */
8956 /* is pointed to by "head". All entries on this list have an expiration */
8957 /* set to be the current tick value of ipf plus the ttl. Given that this */
8958 /* function should only be called when the delta is non-zero, the task is */
8959 /* to walk the entire list and apply the change. The sort order will not */
8960 /* change. The only catch is that this is O(n) across the list, so if the */
8961 /* queue has lots of entries (10s of thousands or 100s of thousands), it */
8962 /* could take a relatively long time to work through them all. */
8963 /* ------------------------------------------------------------------------ */
8964 void
8965 ipf_apply_timeout(ipftq_t *head, u_int seconds)
8966 {
8967 u_int oldtimeout, newtimeout;
8968 ipftqent_t *tqe;
8969 int delta;
8970
8971 MUTEX_ENTER(&head->ifq_lock);
8972 oldtimeout = head->ifq_ttl;
8973 newtimeout = IPF_TTLVAL(seconds);
8974 delta = oldtimeout - newtimeout;
8975
8976 head->ifq_ttl = newtimeout;
8977
8978 for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) {
8979 tqe->tqe_die += delta;
8980 }
8981 MUTEX_EXIT(&head->ifq_lock);
8982 }
8983
8984
8985 /* ------------------------------------------------------------------------ */
8986 /* Function: ipf_settimeout_tcp */
8987 /* Returns: int - 0 = successfully applied, -1 = failed */
8988 /* Parameters: t(I) - pointer to tuneable to change */
8989 /* p(I) - pointer to new timeout information */
8990 /* tab(I) - pointer to table of TCP queues */
8991 /* */
8992 /* This function applies the new timeout (p) to the TCP tunable (t) and */
8993 /* updates all of the entries on the relevant timeout queue by calling */
8994 /* ipf_apply_timeout(). */
8995 /* ------------------------------------------------------------------------ */
8996 int
8997 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab)
8998 {
8999 if (!strcmp(t->ipft_name, "tcp_idle_timeout") ||
9000 !strcmp(t->ipft_name, "tcp_established")) {
9001 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int);
9002 } else if (!strcmp(t->ipft_name, "tcp_close_wait")) {
9003 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int);
9004 } else if (!strcmp(t->ipft_name, "tcp_last_ack")) {
9005 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int);
9006 } else if (!strcmp(t->ipft_name, "tcp_timeout")) {
9007 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
9008 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
9009 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
9010 } else if (!strcmp(t->ipft_name, "tcp_listen")) {
9011 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
9012 } else if (!strcmp(t->ipft_name, "tcp_half_established")) {
9013 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
9014 } else if (!strcmp(t->ipft_name, "tcp_closing")) {
9015 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
9016 } else if (!strcmp(t->ipft_name, "tcp_syn_received")) {
9017 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int);
9018 } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) {
9019 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int);
9020 } else if (!strcmp(t->ipft_name, "tcp_closed")) {
9021 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
9022 } else if (!strcmp(t->ipft_name, "tcp_half_closed")) {
9023 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
9024 } else if (!strcmp(t->ipft_name, "tcp_time_wait")) {
9025 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int);
9026 } else {
9027 /*
9028 * ipf_interror isn't set here because it should be set
9029 * by whatever called this function.
9030 */
9031 return (-1);
9032 }
9033 return (0);
9034 }
9035
9036
9037 /* ------------------------------------------------------------------------ */
9038 /* Function: ipf_main_soft_create */
9039 /* Returns: NULL = failure, else success */
9040 /* Parameters: arg(I) - pointer to soft context structure if already allocd */
9041 /* */
9042 /* Create the foundation soft context structure. In circumstances where it */
9043 /* is not required to dynamically allocate the context, a pointer can be */
9044 /* passed in (rather than NULL) to a structure to be initialised. */
9045 /* The main thing of interest is that a number of locks are initialised */
9046 /* here instead of in the where might be expected - in the relevant create */
9047 /* function elsewhere. This is done because the current locking design has */
9048 /* some areas where these locks are used outside of their module. */
9049 /* Possibly the most important exercise that is done here is setting of all */
9050 /* the timeout values, allowing them to be changed before init(). */
9051 /* ------------------------------------------------------------------------ */
9052 void *
9053 ipf_main_soft_create(void *arg)
9054 {
9055 ipf_main_softc_t *softc;
9056
9057 if (arg == NULL) {
9058 KMALLOC(softc, ipf_main_softc_t *);
9059 if (softc == NULL)
9060 return (NULL);
9061 } else {
9062 softc = arg;
9063 }
9064
9065 bzero((char *)softc, sizeof(*softc));
9066
9067 /*
9068 * This serves as a flag as to whether or not the softc should be
9069 * free'd when _destroy is called.
9070 */
9071 softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0;
9072
9073 softc->ipf_tuners = ipf_tune_array_copy(softc,
9074 sizeof(ipf_main_tuneables),
9075 ipf_main_tuneables);
9076 if (softc->ipf_tuners == NULL) {
9077 ipf_main_soft_destroy(softc);
9078 return (NULL);
9079 }
9080
9081 MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex");
9082 MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock");
9083 RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex");
9084 RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock");
9085 RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock");
9086 RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock");
9087 RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock");
9088 RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock");
9089 RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock");
9090
9091 softc->ipf_token_head = NULL;
9092 softc->ipf_token_tail = &softc->ipf_token_head;
9093
9094 softc->ipf_tcpidletimeout = FIVE_DAYS;
9095 softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL);
9096 softc->ipf_tcplastack = IPF_TTLVAL(30);
9097 softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL);
9098 softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL);
9099 softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL);
9100 softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL);
9101 softc->ipf_tcpclosed = IPF_TTLVAL(30);
9102 softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600);
9103 softc->ipf_udptimeout = IPF_TTLVAL(120);
9104 softc->ipf_udpacktimeout = IPF_TTLVAL(12);
9105 softc->ipf_icmptimeout = IPF_TTLVAL(60);
9106 softc->ipf_icmpacktimeout = IPF_TTLVAL(6);
9107 softc->ipf_iptimeout = IPF_TTLVAL(60);
9108
9109 #if defined(IPFILTER_DEFAULT_BLOCK)
9110 softc->ipf_pass = FR_BLOCK|FR_NOMATCH;
9111 #else
9112 softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
9113 #endif
9114 softc->ipf_minttl = 4;
9115 softc->ipf_icmpminfragmtu = 68;
9116 softc->ipf_max_namelen = 128;
9117 softc->ipf_flags = IPF_LOGGING;
9118 softc->ipf_jail_allowed = 0;
9119
9120 #ifdef LARGE_NAT
9121 softc->ipf_large_nat = 1;
9122 #endif
9123 ipf_fbsd_kenv_get(softc);
9124
9125 return (softc);
9126 }
9127
9128 /* ------------------------------------------------------------------------ */
9129 /* Function: ipf_main_soft_init */
9130 /* Returns: 0 = success, -1 = failure */
9131 /* Parameters: softc(I) - pointer to soft context main structure */
9132 /* */
9133 /* A null-op function that exists as a placeholder so that the flow in */
9134 /* other functions is obvious. */
9135 /* ------------------------------------------------------------------------ */
9136 /*ARGSUSED*/
9137 int
9138 ipf_main_soft_init(ipf_main_softc_t *softc)
9139 {
9140 return (0);
9141 }
9142
9143
9144 /* ------------------------------------------------------------------------ */
9145 /* Function: ipf_main_soft_destroy */
9146 /* Returns: void */
9147 /* Parameters: softc(I) - pointer to soft context main structure */
9148 /* */
9149 /* Undo everything that we did in ipf_main_soft_create. */
9150 /* */
9151 /* The most important check that needs to be made here is whether or not */
9152 /* the structure was allocated by ipf_main_soft_create() by checking what */
9153 /* value is stored in ipf_dynamic_main. */
9154 /* ------------------------------------------------------------------------ */
9155 /*ARGSUSED*/
9156 void
9157 ipf_main_soft_destroy(ipf_main_softc_t *softc)
9158 {
9159
9160 RW_DESTROY(&softc->ipf_frag);
9161 RW_DESTROY(&softc->ipf_poolrw);
9162 RW_DESTROY(&softc->ipf_nat);
9163 RW_DESTROY(&softc->ipf_state);
9164 RW_DESTROY(&softc->ipf_tokens);
9165 RW_DESTROY(&softc->ipf_mutex);
9166 RW_DESTROY(&softc->ipf_global);
9167 MUTEX_DESTROY(&softc->ipf_timeoutlock);
9168 MUTEX_DESTROY(&softc->ipf_rw);
9169
9170 if (softc->ipf_tuners != NULL) {
9171 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables));
9172 }
9173 if (softc->ipf_dynamic_softc == 1) {
9174 KFREE(softc);
9175 }
9176 }
9177
9178
9179 /* ------------------------------------------------------------------------ */
9180 /* Function: ipf_main_soft_fini */
9181 /* Returns: 0 = success, -1 = failure */
9182 /* Parameters: softc(I) - pointer to soft context main structure */
9183 /* */
9184 /* Clean out the rules which have been added since _init was last called, */
9185 /* the only dynamic part of the mainline. */
9186 /* ------------------------------------------------------------------------ */
9187 int
9188 ipf_main_soft_fini(ipf_main_softc_t *softc)
9189 {
9190 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
9191 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
9192 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
9193 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE);
9194
9195 return (0);
9196 }
9197
9198
9199 /* ------------------------------------------------------------------------ */
9200 /* Function: ipf_main_load */
9201 /* Returns: 0 = success, -1 = failure */
9202 /* Parameters: none */
9203 /* */
9204 /* Handle global initialisation that needs to be done for the base part of */
9205 /* IPFilter. At present this just amounts to initialising some ICMP lookup */
9206 /* arrays that get used by the state/NAT code. */
9207 /* ------------------------------------------------------------------------ */
9208 int
9209 ipf_main_load(void)
9210 {
9211 int i;
9212
9213 /* fill icmp reply type table */
9214 for (i = 0; i <= ICMP_MAXTYPE; i++)
9215 icmpreplytype4[i] = -1;
9216 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
9217 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
9218 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
9219 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
9220
9221 #ifdef USE_INET6
9222 /* fill icmp reply type table */
9223 for (i = 0; i <= ICMP6_MAXTYPE; i++)
9224 icmpreplytype6[i] = -1;
9225 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
9226 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
9227 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
9228 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
9229 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
9230 #endif
9231
9232 return (0);
9233 }
9234
9235
9236 /* ------------------------------------------------------------------------ */
9237 /* Function: ipf_main_unload */
9238 /* Returns: 0 = success, -1 = failure */
9239 /* Parameters: none */
9240 /* */
9241 /* A null-op function that exists as a placeholder so that the flow in */
9242 /* other functions is obvious. */
9243 /* ------------------------------------------------------------------------ */
9244 int
9245 ipf_main_unload(void)
9246 {
9247 return (0);
9248 }
9249
9250
9251 /* ------------------------------------------------------------------------ */
9252 /* Function: ipf_load_all */
9253 /* Returns: 0 = success, -1 = failure */
9254 /* Parameters: none */
9255 /* */
9256 /* Work through all of the subsystems inside IPFilter and call the load */
9257 /* function for each in an order that won't lead to a crash :) */
9258 /* ------------------------------------------------------------------------ */
9259 int
9260 ipf_load_all(void)
9261 {
9262 if (ipf_main_load() == -1)
9263 return (-1);
9264
9265 if (ipf_state_main_load() == -1)
9266 return (-1);
9267
9268 if (ipf_nat_main_load() == -1)
9269 return (-1);
9270
9271 if (ipf_frag_main_load() == -1)
9272 return (-1);
9273
9274 if (ipf_auth_main_load() == -1)
9275 return (-1);
9276
9277 if (ipf_proxy_main_load() == -1)
9278 return (-1);
9279
9280 return (0);
9281 }
9282
9283
9284 /* ------------------------------------------------------------------------ */
9285 /* Function: ipf_unload_all */
9286 /* Returns: 0 = success, -1 = failure */
9287 /* Parameters: none */
9288 /* */
9289 /* Work through all of the subsystems inside IPFilter and call the unload */
9290 /* function for each in an order that won't lead to a crash :) */
9291 /* ------------------------------------------------------------------------ */
9292 int
9293 ipf_unload_all(void)
9294 {
9295 if (ipf_proxy_main_unload() == -1)
9296 return (-1);
9297
9298 if (ipf_auth_main_unload() == -1)
9299 return (-1);
9300
9301 if (ipf_frag_main_unload() == -1)
9302 return (-1);
9303
9304 if (ipf_nat_main_unload() == -1)
9305 return (-1);
9306
9307 if (ipf_state_main_unload() == -1)
9308 return (-1);
9309
9310 if (ipf_main_unload() == -1)
9311 return (-1);
9312
9313 return (0);
9314 }
9315
9316
9317 /* ------------------------------------------------------------------------ */
9318 /* Function: ipf_create_all */
9319 /* Returns: NULL = failure, else success */
9320 /* Parameters: arg(I) - pointer to soft context main structure */
9321 /* */
9322 /* Work through all of the subsystems inside IPFilter and call the create */
9323 /* function for each in an order that won't lead to a crash :) */
9324 /* ------------------------------------------------------------------------ */
9325 ipf_main_softc_t *
9326 ipf_create_all(void *arg)
9327 {
9328 ipf_main_softc_t *softc;
9329
9330 softc = ipf_main_soft_create(arg);
9331 if (softc == NULL)
9332 return (NULL);
9333
9334 #ifdef IPFILTER_LOG
9335 softc->ipf_log_soft = ipf_log_soft_create(softc);
9336 if (softc->ipf_log_soft == NULL) {
9337 ipf_destroy_all(softc);
9338 return (NULL);
9339 }
9340 #endif
9341
9342 softc->ipf_lookup_soft = ipf_lookup_soft_create(softc);
9343 if (softc->ipf_lookup_soft == NULL) {
9344 ipf_destroy_all(softc);
9345 return (NULL);
9346 }
9347
9348 softc->ipf_sync_soft = ipf_sync_soft_create(softc);
9349 if (softc->ipf_sync_soft == NULL) {
9350 ipf_destroy_all(softc);
9351 return (NULL);
9352 }
9353
9354 softc->ipf_state_soft = ipf_state_soft_create(softc);
9355 if (softc->ipf_state_soft == NULL) {
9356 ipf_destroy_all(softc);
9357 return (NULL);
9358 }
9359
9360 softc->ipf_nat_soft = ipf_nat_soft_create(softc);
9361 if (softc->ipf_nat_soft == NULL) {
9362 ipf_destroy_all(softc);
9363 return (NULL);
9364 }
9365
9366 softc->ipf_frag_soft = ipf_frag_soft_create(softc);
9367 if (softc->ipf_frag_soft == NULL) {
9368 ipf_destroy_all(softc);
9369 return (NULL);
9370 }
9371
9372 softc->ipf_auth_soft = ipf_auth_soft_create(softc);
9373 if (softc->ipf_auth_soft == NULL) {
9374 ipf_destroy_all(softc);
9375 return (NULL);
9376 }
9377
9378 softc->ipf_proxy_soft = ipf_proxy_soft_create(softc);
9379 if (softc->ipf_proxy_soft == NULL) {
9380 ipf_destroy_all(softc);
9381 return (NULL);
9382 }
9383
9384 return (softc);
9385 }
9386
9387
9388 /* ------------------------------------------------------------------------ */
9389 /* Function: ipf_destroy_all */
9390 /* Returns: void */
9391 /* Parameters: softc(I) - pointer to soft context main structure */
9392 /* */
9393 /* Work through all of the subsystems inside IPFilter and call the destroy */
9394 /* function for each in an order that won't lead to a crash :) */
9395 /* */
9396 /* Every one of these functions is expected to succeed, so there is no */
9397 /* checking of return values. */
9398 /* ------------------------------------------------------------------------ */
9399 void
9400 ipf_destroy_all(ipf_main_softc_t *softc)
9401 {
9402
9403 if (softc->ipf_state_soft != NULL) {
9404 ipf_state_soft_destroy(softc, softc->ipf_state_soft);
9405 softc->ipf_state_soft = NULL;
9406 }
9407
9408 if (softc->ipf_nat_soft != NULL) {
9409 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft);
9410 softc->ipf_nat_soft = NULL;
9411 }
9412
9413 if (softc->ipf_frag_soft != NULL) {
9414 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft);
9415 softc->ipf_frag_soft = NULL;
9416 }
9417
9418 if (softc->ipf_auth_soft != NULL) {
9419 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft);
9420 softc->ipf_auth_soft = NULL;
9421 }
9422
9423 if (softc->ipf_proxy_soft != NULL) {
9424 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft);
9425 softc->ipf_proxy_soft = NULL;
9426 }
9427
9428 if (softc->ipf_sync_soft != NULL) {
9429 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft);
9430 softc->ipf_sync_soft = NULL;
9431 }
9432
9433 if (softc->ipf_lookup_soft != NULL) {
9434 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft);
9435 softc->ipf_lookup_soft = NULL;
9436 }
9437
9438 #ifdef IPFILTER_LOG
9439 if (softc->ipf_log_soft != NULL) {
9440 ipf_log_soft_destroy(softc, softc->ipf_log_soft);
9441 softc->ipf_log_soft = NULL;
9442 }
9443 #endif
9444
9445 ipf_main_soft_destroy(softc);
9446 }
9447
9448
9449 /* ------------------------------------------------------------------------ */
9450 /* Function: ipf_init_all */
9451 /* Returns: 0 = success, -1 = failure */
9452 /* Parameters: softc(I) - pointer to soft context main structure */
9453 /* */
9454 /* Work through all of the subsystems inside IPFilter and call the init */
9455 /* function for each in an order that won't lead to a crash :) */
9456 /* ------------------------------------------------------------------------ */
9457 int
9458 ipf_init_all(ipf_main_softc_t *softc)
9459 {
9460
9461 if (ipf_main_soft_init(softc) == -1)
9462 return (-1);
9463
9464 #ifdef IPFILTER_LOG
9465 if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1)
9466 return (-1);
9467 #endif
9468
9469 if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1)
9470 return (-1);
9471
9472 if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1)
9473 return (-1);
9474
9475 if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1)
9476 return (-1);
9477
9478 if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1)
9479 return (-1);
9480
9481 if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1)
9482 return (-1);
9483
9484 if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1)
9485 return (-1);
9486
9487 if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1)
9488 return (-1);
9489
9490 return (0);
9491 }
9492
9493
9494 /* ------------------------------------------------------------------------ */
9495 /* Function: ipf_fini_all */
9496 /* Returns: 0 = success, -1 = failure */
9497 /* Parameters: softc(I) - pointer to soft context main structure */
9498 /* */
9499 /* Work through all of the subsystems inside IPFilter and call the fini */
9500 /* function for each in an order that won't lead to a crash :) */
9501 /* ------------------------------------------------------------------------ */
9502 int
9503 ipf_fini_all(ipf_main_softc_t *softc)
9504 {
9505
9506 ipf_token_flush(softc);
9507
9508 if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1)
9509 return (-1);
9510
9511 if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1)
9512 return (-1);
9513
9514 if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1)
9515 return (-1);
9516
9517 if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1)
9518 return (-1);
9519
9520 if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1)
9521 return (-1);
9522
9523 if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1)
9524 return (-1);
9525
9526 if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1)
9527 return (-1);
9528
9529 #ifdef IPFILTER_LOG
9530 if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1)
9531 return (-1);
9532 #endif
9533
9534 if (ipf_main_soft_fini(softc) == -1)
9535 return (-1);
9536
9537 return (0);
9538 }
9539
9540
9541 /* ------------------------------------------------------------------------ */
9542 /* Function: ipf_rule_expire */
9543 /* Returns: Nil */
9544 /* Parameters: softc(I) - pointer to soft context main structure */
9545 /* */
9546 /* At present this function exists just to support temporary addition of */
9547 /* firewall rules. Both inactive and active lists are scanned for items to */
9548 /* purge, as by rights, the expiration is computed as soon as the rule is */
9549 /* loaded in. */
9550 /* ------------------------------------------------------------------------ */
9551 void
9552 ipf_rule_expire(ipf_main_softc_t *softc)
9553 {
9554 frentry_t *fr;
9555
9556 if ((softc->ipf_rule_explist[0] == NULL) &&
9557 (softc->ipf_rule_explist[1] == NULL))
9558 return;
9559
9560 WRITE_ENTER(&softc->ipf_mutex);
9561
9562 while ((fr = softc->ipf_rule_explist[0]) != NULL) {
9563 /*
9564 * Because the list is kept sorted on insertion, the fist
9565 * one that dies in the future means no more work to do.
9566 */
9567 if (fr->fr_die > softc->ipf_ticks)
9568 break;
9569 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0);
9570 }
9571
9572 while ((fr = softc->ipf_rule_explist[1]) != NULL) {
9573 /*
9574 * Because the list is kept sorted on insertion, the fist
9575 * one that dies in the future means no more work to do.
9576 */
9577 if (fr->fr_die > softc->ipf_ticks)
9578 break;
9579 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1);
9580 }
9581
9582 RWLOCK_EXIT(&softc->ipf_mutex);
9583 }
9584
9585
9586 static int ipf_ht_node_cmp(struct host_node_s *, struct host_node_s *);
9587 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int,
9588 i6addr_t *);
9589
9590 host_node_t RBI_ZERO(ipf_rb);
9591 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp)
9592
9593
9594 /* ------------------------------------------------------------------------ */
9595 /* Function: ipf_ht_node_cmp */
9596 /* Returns: int - 0 == nodes are the same, .. */
9597 /* Parameters: k1(I) - pointer to first key to compare */
9598 /* k2(I) - pointer to second key to compare */
9599 /* */
9600 /* The "key" for the node is a combination of two fields: the address */
9601 /* family and the address itself. */
9602 /* */
9603 /* Because we're not actually interpreting the address data, it isn't */
9604 /* necessary to convert them to/from network/host byte order. The mask is */
9605 /* just used to remove bits that aren't significant - it doesn't matter */
9606 /* where they are, as long as they're always in the same place. */
9607 /* */
9608 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */
9609 /* this is where individual ones will differ the most - but not true for */
9610 /* for /48's, etc. */
9611 /* ------------------------------------------------------------------------ */
9612 static int
9613 ipf_ht_node_cmp(struct host_node_s *k1, struct host_node_s *k2)
9614 {
9615 int i;
9616
9617 i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family);
9618 if (i != 0)
9619 return (i);
9620
9621 if (k1->hn_addr.adf_family == AF_INET)
9622 return (k2->hn_addr.adf_addr.in4.s_addr -
9623 k1->hn_addr.adf_addr.in4.s_addr);
9624
9625 i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3];
9626 if (i != 0)
9627 return (i);
9628 i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2];
9629 if (i != 0)
9630 return (i);
9631 i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1];
9632 if (i != 0)
9633 return (i);
9634 i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0];
9635 return (i);
9636 }
9637
9638
9639 /* ------------------------------------------------------------------------ */
9640 /* Function: ipf_ht_node_make_key */
9641 /* Returns: Nil */
9642 /* parameters: htp(I) - pointer to address tracking structure */
9643 /* key(I) - where to store masked address for lookup */
9644 /* family(I) - protocol family of address */
9645 /* addr(I) - pointer to network address */
9646 /* */
9647 /* Using the "netmask" (number of bits) stored parent host tracking struct, */
9648 /* copy the address passed in into the key structure whilst masking out the */
9649 /* bits that we don't want. */
9650 /* */
9651 /* Because the parser will set ht_netmask to 128 if there is no protocol */
9652 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we */
9653 /* have to be wary of that and not allow 32-128 to happen. */
9654 /* ------------------------------------------------------------------------ */
9655 static void
9656 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family,
9657 i6addr_t *addr)
9658 {
9659 key->hn_addr.adf_family = family;
9660 if (family == AF_INET) {
9661 u_32_t mask;
9662 int bits;
9663
9664 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4);
9665 bits = htp->ht_netmask;
9666 if (bits >= 32) {
9667 mask = 0xffffffff;
9668 } else {
9669 mask = htonl(0xffffffff << (32 - bits));
9670 }
9671 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask;
9672 #ifdef USE_INET6
9673 } else {
9674 int bits = htp->ht_netmask;
9675
9676 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6);
9677 if (bits > 96) {
9678 key->hn_addr.adf_addr.i6[3] = addr->i6[3] &
9679 htonl(0xffffffff << (128 - bits));
9680 key->hn_addr.adf_addr.i6[2] = addr->i6[2];
9681 key->hn_addr.adf_addr.i6[1] = addr->i6[2];
9682 key->hn_addr.adf_addr.i6[0] = addr->i6[2];
9683 } else if (bits > 64) {
9684 key->hn_addr.adf_addr.i6[3] = 0;
9685 key->hn_addr.adf_addr.i6[2] = addr->i6[2] &
9686 htonl(0xffffffff << (96 - bits));
9687 key->hn_addr.adf_addr.i6[1] = addr->i6[1];
9688 key->hn_addr.adf_addr.i6[0] = addr->i6[0];
9689 } else if (bits > 32) {
9690 key->hn_addr.adf_addr.i6[3] = 0;
9691 key->hn_addr.adf_addr.i6[2] = 0;
9692 key->hn_addr.adf_addr.i6[1] = addr->i6[1] &
9693 htonl(0xffffffff << (64 - bits));
9694 key->hn_addr.adf_addr.i6[0] = addr->i6[0];
9695 } else {
9696 key->hn_addr.adf_addr.i6[3] = 0;
9697 key->hn_addr.adf_addr.i6[2] = 0;
9698 key->hn_addr.adf_addr.i6[1] = 0;
9699 key->hn_addr.adf_addr.i6[0] = addr->i6[0] &
9700 htonl(0xffffffff << (32 - bits));
9701 }
9702 #endif
9703 }
9704 }
9705
9706
9707 /* ------------------------------------------------------------------------ */
9708 /* Function: ipf_ht_node_add */
9709 /* Returns: int - 0 == success, -1 == failure */
9710 /* Parameters: softc(I) - pointer to soft context main structure */
9711 /* htp(I) - pointer to address tracking structure */
9712 /* family(I) - protocol family of address */
9713 /* addr(I) - pointer to network address */
9714 /* */
9715 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */
9716 /* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */
9717 /* */
9718 /* After preparing the key with the address information to find, look in */
9719 /* the red-black tree to see if the address is known. A successful call to */
9720 /* this function can mean one of two things: a new node was added to the */
9721 /* tree or a matching node exists and we're able to bump up its activity. */
9722 /* ------------------------------------------------------------------------ */
9723 int
9724 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family,
9725 i6addr_t *addr)
9726 {
9727 host_node_t *h;
9728 host_node_t k;
9729
9730 ipf_ht_node_make_key(htp, &k, family, addr);
9731
9732 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
9733 if (h == NULL) {
9734 if (htp->ht_cur_nodes >= htp->ht_max_nodes)
9735 return (-1);
9736 KMALLOC(h, host_node_t *);
9737 if (h == NULL) {
9738 DT(ipf_rb_no_mem);
9739 LBUMP(ipf_rb_no_mem);
9740 return (-1);
9741 }
9742
9743 /*
9744 * If there was a macro to initialise the RB node then that
9745 * would get used here, but there isn't...
9746 */
9747 bzero((char *)h, sizeof(*h));
9748 h->hn_addr = k.hn_addr;
9749 h->hn_addr.adf_family = k.hn_addr.adf_family;
9750 RBI_INSERT(ipf_rb, &htp->ht_root, h);
9751 htp->ht_cur_nodes++;
9752 } else {
9753 if ((htp->ht_max_per_node != 0) &&
9754 (h->hn_active >= htp->ht_max_per_node)) {
9755 DT(ipf_rb_node_max);
9756 LBUMP(ipf_rb_node_max);
9757 return (-1);
9758 }
9759 }
9760
9761 h->hn_active++;
9762
9763 return (0);
9764 }
9765
9766
9767 /* ------------------------------------------------------------------------ */
9768 /* Function: ipf_ht_node_del */
9769 /* Returns: int - 0 == success, -1 == failure */
9770 /* parameters: htp(I) - pointer to address tracking structure */
9771 /* family(I) - protocol family of address */
9772 /* addr(I) - pointer to network address */
9773 /* */
9774 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */
9775 /* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */
9776 /* */
9777 /* Try and find the address passed in amongst the leavese on this tree to */
9778 /* be friend. If found then drop the active account for that node drops by */
9779 /* one. If that count reaches 0, it is time to free it all up. */
9780 /* ------------------------------------------------------------------------ */
9781 int
9782 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr)
9783 {
9784 host_node_t *h;
9785 host_node_t k;
9786
9787 ipf_ht_node_make_key(htp, &k, family, addr);
9788
9789 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
9790 if (h == NULL) {
9791 return (-1);
9792 } else {
9793 h->hn_active--;
9794 if (h->hn_active == 0) {
9795 (void) RBI_DELETE(ipf_rb, &htp->ht_root, h);
9796 htp->ht_cur_nodes--;
9797 KFREE(h);
9798 }
9799 }
9800
9801 return (0);
9802 }
9803
9804
9805 /* ------------------------------------------------------------------------ */
9806 /* Function: ipf_rb_ht_init */
9807 /* Returns: Nil */
9808 /* Parameters: head(I) - pointer to host tracking structure */
9809 /* */
9810 /* Initialise the host tracking structure to be ready for use above. */
9811 /* ------------------------------------------------------------------------ */
9812 void
9813 ipf_rb_ht_init(host_track_t *head)
9814 {
9815 RBI_INIT(ipf_rb, &head->ht_root);
9816 }
9817
9818
9819 /* ------------------------------------------------------------------------ */
9820 /* Function: ipf_rb_ht_freenode */
9821 /* Returns: Nil */
9822 /* Parameters: head(I) - pointer to host tracking structure */
9823 /* arg(I) - additional argument from walk caller */
9824 /* */
9825 /* Free an actual host_node_t structure. */
9826 /* ------------------------------------------------------------------------ */
9827 void
9828 ipf_rb_ht_freenode(host_node_t *node, void *arg)
9829 {
9830 KFREE(node);
9831 }
9832
9833
9834 /* ------------------------------------------------------------------------ */
9835 /* Function: ipf_rb_ht_flush */
9836 /* Returns: Nil */
9837 /* Parameters: head(I) - pointer to host tracking structure */
9838 /* */
9839 /* Remove all of the nodes in the tree tracking hosts by calling a walker */
9840 /* and free'ing each one. */
9841 /* ------------------------------------------------------------------------ */
9842 void
9843 ipf_rb_ht_flush(host_track_t *head)
9844 {
9845 RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL);
9846 }
9847
9848
9849 /* ------------------------------------------------------------------------ */
9850 /* Function: ipf_slowtimer */
9851 /* Returns: Nil */
9852 /* Parameters: ptr(I) - pointer to main ipf soft context structure */
9853 /* */
9854 /* Slowly expire held state for fragments. Timeouts are set * in */
9855 /* expectation of this being called twice per second. */
9856 /* ------------------------------------------------------------------------ */
9857 void
9858 ipf_slowtimer(ipf_main_softc_t *softc)
9859 {
9860
9861 ipf_token_expire(softc);
9862 ipf_frag_expire(softc);
9863 ipf_state_expire(softc);
9864 ipf_nat_expire(softc);
9865 ipf_auth_expire(softc);
9866 ipf_lookup_expire(softc);
9867 ipf_rule_expire(softc);
9868 ipf_sync_expire(softc);
9869 softc->ipf_ticks++;
9870 }
9871
9872
9873 /* ------------------------------------------------------------------------ */
9874 /* Function: ipf_inet_mask_add */
9875 /* Returns: Nil */
9876 /* Parameters: bits(I) - pointer to nat context information */
9877 /* mtab(I) - pointer to mask hash table structure */
9878 /* */
9879 /* When called, bits represents the mask of a new NAT rule that has just */
9880 /* been added. This function inserts a bitmask into the array of masks to */
9881 /* search when searching for a matching NAT rule for a packet. */
9882 /* Prevention of duplicate masks is achieved by checking the use count for */
9883 /* a given netmask. */
9884 /* ------------------------------------------------------------------------ */
9885 void
9886 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab)
9887 {
9888 u_32_t mask;
9889 int i, j;
9890
9891 mtab->imt4_masks[bits]++;
9892 if (mtab->imt4_masks[bits] > 1)
9893 return;
9894
9895 if (bits == 0)
9896 mask = 0;
9897 else
9898 mask = 0xffffffff << (32 - bits);
9899
9900 for (i = 0; i < 33; i++) {
9901 if (ntohl(mtab->imt4_active[i]) < mask) {
9902 for (j = 32; j > i; j--)
9903 mtab->imt4_active[j] = mtab->imt4_active[j - 1];
9904 mtab->imt4_active[i] = htonl(mask);
9905 break;
9906 }
9907 }
9908 mtab->imt4_max++;
9909 }
9910
9911
9912 /* ------------------------------------------------------------------------ */
9913 /* Function: ipf_inet_mask_del */
9914 /* Returns: Nil */
9915 /* Parameters: bits(I) - number of bits set in the netmask */
9916 /* mtab(I) - pointer to mask hash table structure */
9917 /* */
9918 /* Remove the 32bit bitmask represented by "bits" from the collection of */
9919 /* netmasks stored inside of mtab. */
9920 /* ------------------------------------------------------------------------ */
9921 void
9922 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab)
9923 {
9924 u_32_t mask;
9925 int i, j;
9926
9927 mtab->imt4_masks[bits]--;
9928 if (mtab->imt4_masks[bits] > 0)
9929 return;
9930
9931 mask = htonl(0xffffffff << (32 - bits));
9932 for (i = 0; i < 33; i++) {
9933 if (mtab->imt4_active[i] == mask) {
9934 for (j = i + 1; j < 33; j++)
9935 mtab->imt4_active[j - 1] = mtab->imt4_active[j];
9936 break;
9937 }
9938 }
9939 mtab->imt4_max--;
9940 ASSERT(mtab->imt4_max >= 0);
9941 }
9942
9943
9944 #ifdef USE_INET6
9945 /* ------------------------------------------------------------------------ */
9946 /* Function: ipf_inet6_mask_add */
9947 /* Returns: Nil */
9948 /* Parameters: bits(I) - number of bits set in mask */
9949 /* mask(I) - pointer to mask to add */
9950 /* mtab(I) - pointer to mask hash table structure */
9951 /* */
9952 /* When called, bitcount represents the mask of a IPv6 NAT map rule that */
9953 /* has just been added. This function inserts a bitmask into the array of */
9954 /* masks to search when searching for a matching NAT rule for a packet. */
9955 /* Prevention of duplicate masks is achieved by checking the use count for */
9956 /* a given netmask. */
9957 /* ------------------------------------------------------------------------ */
9958 void
9959 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab)
9960 {
9961 i6addr_t zero;
9962 int i, j;
9963
9964 mtab->imt6_masks[bits]++;
9965 if (mtab->imt6_masks[bits] > 1)
9966 return;
9967
9968 if (bits == 0) {
9969 mask = &zero;
9970 zero.i6[0] = 0;
9971 zero.i6[1] = 0;
9972 zero.i6[2] = 0;
9973 zero.i6[3] = 0;
9974 }
9975
9976 for (i = 0; i < 129; i++) {
9977 if (IP6_LT(&mtab->imt6_active[i], mask)) {
9978 for (j = 128; j > i; j--)
9979 mtab->imt6_active[j] = mtab->imt6_active[j - 1];
9980 mtab->imt6_active[i] = *mask;
9981 break;
9982 }
9983 }
9984 mtab->imt6_max++;
9985 }
9986
9987
9988 /* ------------------------------------------------------------------------ */
9989 /* Function: ipf_inet6_mask_del */
9990 /* Returns: Nil */
9991 /* Parameters: bits(I) - number of bits set in mask */
9992 /* mask(I) - pointer to mask to remove */
9993 /* mtab(I) - pointer to mask hash table structure */
9994 /* */
9995 /* Remove the 128bit bitmask represented by "bits" from the collection of */
9996 /* netmasks stored inside of mtab. */
9997 /* ------------------------------------------------------------------------ */
9998 void
9999 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab)
10000 {
10001 i6addr_t zero;
10002 int i, j;
10003
10004 mtab->imt6_masks[bits]--;
10005 if (mtab->imt6_masks[bits] > 0)
10006 return;
10007
10008 if (bits == 0)
10009 mask = &zero;
10010 zero.i6[0] = 0;
10011 zero.i6[1] = 0;
10012 zero.i6[2] = 0;
10013 zero.i6[3] = 0;
10014
10015 for (i = 0; i < 129; i++) {
10016 if (IP6_EQ(&mtab->imt6_active[i], mask)) {
10017 for (j = i + 1; j < 129; j++) {
10018 mtab->imt6_active[j - 1] = mtab->imt6_active[j];
10019 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero))
10020 break;
10021 }
10022 break;
10023 }
10024 }
10025 mtab->imt6_max--;
10026 ASSERT(mtab->imt6_max >= 0);
10027 }
10028 #endif
10029
10030 /* ------------------------------------------------------------------------ */
10031 /* Function: ipf_check_names_string */
10032 /* Returns: int - 0 == success */
10033 /* - 1 == negative offset */
10034 /* - 2 == offset exceds namelen */
10035 /* - 3 == string exceeds the names string */
10036 /* Parameters: names - pointer to names string */
10037 /* namelen - total length of names string */
10038 /* offset - offset into names string */
10039 /* */
10040 /* Validate the names string (fr_names for ipfilter, in_names for ipnat). */
10041 /* ------------------------------------------------------------------------ */
10042 int
10043 ipf_check_names_string(char *names, int namelen, int offset)
10044 {
10045 const char *name;
10046 size_t len;
10047
10048 if (offset == -1)
10049 return (0);
10050 if (offset < 0)
10051 return (1);
10052 if (offset > namelen)
10053 return (2);
10054 name = &names[offset];
10055 len = strnlen(name, namelen - offset);
10056 if (len == namelen - offset)
10057 return (3);
10058 return (0);
10059 }
10060