4 * Copyright (C) 1993-2003 by Darren Reed.
6 * See the IPFILTER.LICENCE file for details on licencing.
8 * Copyright 2008 Sun Microsystems, Inc.
10 #if defined(KERNEL) || defined(_KERNEL)
16 #include <sys/errno.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
20 #if defined(__NetBSD__)
21 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
22 # if (__NetBSD_Version__ < 301000000)
23 # include "opt_ipfilter_log.h"
25 # include <sys/cdefs.h>
26 # include "opt_ipfilter.h"
30 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
31 (__FreeBSD_version >= 220000)
32 # if (__FreeBSD_version >= 400000)
33 # if !defined(IPFILTER_LKM)
34 # include "opt_inet6.h"
36 # if (__FreeBSD_version == 400019)
37 # define CSUM_DELAY_DATA
40 # include <sys/filio.h>
42 # include <sys/ioctl.h>
44 #if (defined(__SVR4) || defined(__svr4__)) && defined(sun)
45 # include <sys/filio.h>
48 # include <sys/fcntl.h>
51 # include <sys/systm.h>
52 # include <sys/file.h>
58 # include <sys/file.h>
66 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \
68 # include <sys/mbuf.h>
71 # include <sys/byteorder.h>
73 # if (SOLARIS2 < 5) && defined(sun)
74 # include <sys/dditypes.h>
78 # define _NET_ROUTE_INCLUDED
81 # include <sys/protosw.h>
83 #include <sys/socket.h>
88 #if !defined(_KERNEL) && (defined(__FreeBSD__) || defined(SOLARIS2))
89 # if (__FreeBSD_version >= 504000)
92 # include "radix_ipf.h"
95 # include "radix_ipf.h"
97 # include <net/route.h>
99 #include <netinet/in.h>
100 #include <netinet/in_systm.h>
101 #include <netinet/ip.h>
103 # include <netinet/ip_var.h>
105 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
106 # include <sys/hashing.h>
107 # include <netinet/in_var.h>
109 #include <netinet/tcp.h>
110 #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL)
111 # include <netinet/udp.h>
112 # include <netinet/ip_icmp.h>
115 # undef _NET_ROUTE_INCLUDED
120 #include "netinet/ip_compat.h"
122 # include <netinet/icmp6.h>
123 # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux)
124 # include <netinet6/in6_var.h>
127 #include <netinet/tcpip.h>
128 #include "netinet/ip_fil.h"
129 #include "netinet/ip_nat.h"
130 #include "netinet/ip_frag.h"
131 #include "netinet/ip_state.h"
132 #include "netinet/ip_proxy.h"
133 #include "netinet/ip_auth.h"
135 # include "netinet/ip_scan.h"
138 # include "netinet/ip_sync.h"
140 #include "netinet/ip_pool.h"
141 #include "netinet/ip_htable.h"
142 #ifdef IPFILTER_COMPILED
143 # include "netinet/ip_rules.h"
145 #if defined(IPFILTER_BPF) && defined(_KERNEL)
146 # include <net/bpf.h>
148 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
149 # include <sys/malloc.h>
150 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
151 # include "opt_ipfilter.h"
154 #include "netinet/ipl.h"
155 /* END OF INCLUDES */
158 #if defined(__NetBSD__)
159 #include <sys/cdefs.h>
160 __KERNEL_RCSID(0, "$NetBSD$");
162 static const char sccsid
[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
163 static const char rcsid
[] = "@(#)Id: fil.c,v 2.243.2.147 2009/07/21 22:25:28 darrenr Exp";
170 # include "bpf-ipf.h"
175 fr_info_t frcache
[2][8];
176 struct filterstats frstats
[2] = { { .fr_pass
= 0 }, { .fr_pass
= 0 } };
177 struct frentry
*ipfilter
[2][2] = { { NULL
, NULL
}, { NULL
, NULL
} },
178 *ipfilter6
[2][2] = { { NULL
, NULL
}, { NULL
, NULL
} },
179 *ipacct6
[2][2] = { { NULL
, NULL
}, { NULL
, NULL
} },
180 *ipacct
[2][2] = { { NULL
, NULL
}, { NULL
, NULL
} },
181 *ipnatrules
[2][2] = { { NULL
, NULL
}, { NULL
, NULL
} };
182 struct frgroup
*ipfgroups
[IPL_LOGSIZE
][2];
183 char ipfilter_version
[] = IPL_VERSION
;
187 * 0 == loading, 1 = running, -1 = disabled, -2 = unloading
190 int fr_flags
= IPF_LOGGING
;
192 int fr_control_forwarding
= 0;
193 int fr_update_ipid
= 0;
194 u_short fr_ip_id
= 0;
195 int fr_chksrc
= 0; /* causes a system crash if enabled */
197 int fr_icmpminfragmtu
= 68;
198 u_long fr_frouteok
[2] = {0, 0};
199 u_long fr_userifqs
= 0;
200 u_long fr_badcoalesces
[2] = {0, 0};
201 u_char ipf_iss_secret
[32];
202 #if defined(IPFILTER_DEFAULT_BLOCK)
203 int fr_pass
= FR_BLOCK
|FR_NOMATCH
;
205 int fr_pass
= (IPF_DEFAULT_PASS
)|FR_NOMATCH
;
214 #ifdef IPFILTER_LOOKUP
220 #ifdef IPFILTER_COMPILED
223 #ifdef IPFILTER_CKSUM
237 static INLINE
int fr_ipfcheck
__P((fr_info_t
*, frentry_t
*, int));
238 static int fr_portcheck
__P((frpcmp_t
*, u_short
*));
239 static int frflushlist
__P((int, minor_t
, int *, frentry_t
**));
240 static ipfunc_t fr_findfunc
__P((ipfunc_t
));
241 static frentry_t
*fr_firewall
__P((fr_info_t
*, u_32_t
*));
242 static int fr_funcinit
__P((frentry_t
*fr
));
243 static INLINE
void frpr_ah
__P((fr_info_t
*));
244 static INLINE
void frpr_esp
__P((fr_info_t
*));
245 static INLINE
void frpr_gre
__P((fr_info_t
*));
246 static INLINE
void frpr_udp
__P((fr_info_t
*));
247 static INLINE
void frpr_tcp
__P((fr_info_t
*));
248 static INLINE
void frpr_icmp
__P((fr_info_t
*));
249 static INLINE
void frpr_ipv4hdr
__P((fr_info_t
*));
250 static INLINE
int frpr_pullup
__P((fr_info_t
*, int));
251 static INLINE
void frpr_short
__P((fr_info_t
*, int));
252 static INLINE
int frpr_tcpcommon
__P((fr_info_t
*));
253 static INLINE
int frpr_udpcommon
__P((fr_info_t
*));
254 static int fr_updateipid
__P((fr_info_t
*));
255 #ifdef IPFILTER_LOOKUP
256 static int fr_grpmapinit
__P((frentry_t
*fr
));
257 static INLINE
void *fr_resolvelookup
__P((u_int
, u_int
, i6addr_t
*, lookupfunc_t
*));
259 static void frsynclist
__P((frentry_t
*, void *));
260 static ipftuneable_t
*fr_findtunebyname
__P((const char *));
261 static ipftuneable_t
*fr_findtunebycookie
__P((void *, void **));
262 static int ipf_geniter
__P((ipftoken_t
*, ipfgeniter_t
*));
263 static int ipf_frruleiter
__P((void *, int, void *));
264 static void ipf_unlinktoken
__P((ipftoken_t
*));
268 * bit values for identifying presence of individual IP options
269 * All of these tables should be ordered by increasing key value on the left
270 * hand side to allow for binary searching of the array and include a trailer
271 * with a 0 for the bitmask for linear searches to easily find the end with.
273 const struct optlist ipopts
[20] = {
274 { IPOPT_NOP
, 0x000001 },
275 { IPOPT_RR
, 0x000002 },
276 { IPOPT_ZSU
, 0x000004 },
277 { IPOPT_MTUP
, 0x000008 },
278 { IPOPT_MTUR
, 0x000010 },
279 { IPOPT_ENCODE
, 0x000020 },
280 { IPOPT_TS
, 0x000040 },
281 { IPOPT_TR
, 0x000080 },
282 { IPOPT_SECURITY
, 0x000100 },
283 { IPOPT_LSRR
, 0x000200 },
284 { IPOPT_E_SEC
, 0x000400 },
285 { IPOPT_CIPSO
, 0x000800 },
286 { IPOPT_SATID
, 0x001000 },
287 { IPOPT_SSRR
, 0x002000 },
288 { IPOPT_ADDEXT
, 0x004000 },
289 { IPOPT_VISA
, 0x008000 },
290 { IPOPT_IMITD
, 0x010000 },
291 { IPOPT_EIP
, 0x020000 },
292 { IPOPT_FINN
, 0x040000 },
297 struct optlist ip6exthdr
[] = {
298 { IPPROTO_HOPOPTS
, 0x000001 },
299 { IPPROTO_IPV6
, 0x000002 },
300 { IPPROTO_ROUTING
, 0x000004 },
301 { IPPROTO_FRAGMENT
, 0x000008 },
302 { IPPROTO_ESP
, 0x000010 },
303 { IPPROTO_AH
, 0x000020 },
304 { IPPROTO_NONE
, 0x000040 },
305 { IPPROTO_DSTOPTS
, 0x000080 },
306 { IPPROTO_MOBILITY
, 0x000100 },
311 struct optlist tcpopts
[] = {
312 { TCPOPT_NOP
, 0x000001 },
313 { TCPOPT_MAXSEG
, 0x000002 },
314 { TCPOPT_WINDOW
, 0x000004 },
315 { TCPOPT_SACK_PERMITTED
, 0x000008 },
316 { TCPOPT_SACK
, 0x000010 },
317 { TCPOPT_TIMESTAMP
, 0x000020 },
322 * bit values for identifying presence of individual IP security options
324 const struct optlist secopt
[8] = {
325 { IPSO_CLASS_RES4
, 0x01 },
326 { IPSO_CLASS_TOPS
, 0x02 },
327 { IPSO_CLASS_SECR
, 0x04 },
328 { IPSO_CLASS_RES3
, 0x08 },
329 { IPSO_CLASS_CONF
, 0x10 },
330 { IPSO_CLASS_UNCL
, 0x20 },
331 { IPSO_CLASS_RES2
, 0x40 },
332 { IPSO_CLASS_RES1
, 0x80 }
337 * Table of functions available for use with call rules.
339 static ipfunc_resolve_t fr_availfuncs
[] = {
340 #ifdef IPFILTER_LOOKUP
341 { "fr_srcgrpmap", fr_srcgrpmap
, fr_grpmapinit
},
342 { "fr_dstgrpmap", fr_dstgrpmap
, fr_grpmapinit
},
349 * The next section of code is a a collection of small routines that set
350 * fields in the fr_info_t structure passed based on properties of the
351 * current packet. There are different routines for the same protocol
352 * for each of IPv4 and IPv6. Adding a new protocol, for which there
353 * will "special" inspection for setup, is now more easily done by adding
354 * a new routine and expanding the frpr_ipinit*() function rather than by
355 * adding more code to a growing switch statement.
358 static INLINE
int frpr_ah6
__P((fr_info_t
*));
359 static INLINE
void frpr_esp6
__P((fr_info_t
*));
360 static INLINE
void frpr_gre6
__P((fr_info_t
*));
361 static INLINE
void frpr_udp6
__P((fr_info_t
*));
362 static INLINE
void frpr_tcp6
__P((fr_info_t
*));
363 static INLINE
void frpr_icmp6
__P((fr_info_t
*));
364 static INLINE
void frpr_ipv6hdr
__P((fr_info_t
*));
365 static INLINE
void frpr_short6
__P((fr_info_t
*, int));
366 static INLINE
int frpr_hopopts6
__P((fr_info_t
*));
367 static INLINE
int frpr_mobility6
__P((fr_info_t
*));
368 static INLINE
int frpr_routing6
__P((fr_info_t
*));
369 static INLINE
int frpr_dstopts6
__P((fr_info_t
*));
370 static INLINE
int frpr_fragment6
__P((fr_info_t
*));
371 static INLINE
int frpr_ipv6exthdr
__P((fr_info_t
*, int, int));
374 /* ------------------------------------------------------------------------ */
375 /* Function: frpr_short6 */
377 /* Parameters: fin(I) - pointer to packet information */
380 /* This is function enforces the 'is a packet too short to be legit' rule */
381 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */
382 /* for frpr_short() for more details. */
383 /* ------------------------------------------------------------------------ */
384 static INLINE
void frpr_short6(fin
, xmin
)
389 if (fin
->fin_dlen
< xmin
)
390 fin
->fin_flx
|= FI_SHORT
;
394 /* ------------------------------------------------------------------------ */
395 /* Function: frpr_ipv6hdr */
397 /* Parameters: fin(I) - pointer to packet information */
400 /* Copy values from the IPv6 header into the fr_info_t struct and call the */
401 /* per-protocol analyzer if it exists. In validating the packet, a protocol*/
402 /* analyzer may pullup or free the packet itself so we need to be vigiliant */
403 /* of that possibility arising. */
404 /* ------------------------------------------------------------------------ */
405 static INLINE
void frpr_ipv6hdr(fin
)
408 ip6_t
*ip6
= (ip6_t
*)fin
->fin_ip
;
409 int p
, go
= 1, i
, hdrcount
;
410 fr_ip_t
*fi
= &fin
->fin_fi
;
420 fi
->fi_ttl
= ip6
->ip6_hlim
;
421 fi
->fi_src
.in6
= ip6
->ip6_src
;
422 fi
->fi_dst
.in6
= ip6
->ip6_dst
;
423 fin
->fin_id
= (u_short
)(ip6
->ip6_flow
& 0xffff);
426 while (go
&& !(fin
->fin_flx
& FI_SHORT
)) {
439 case IPPROTO_ICMPV6
:
449 case IPPROTO_HOPOPTS
:
450 p
= frpr_hopopts6(fin
);
453 case IPPROTO_MOBILITY
:
454 p
= frpr_mobility6(fin
);
457 case IPPROTO_DSTOPTS
:
458 p
= frpr_dstopts6(fin
);
461 case IPPROTO_ROUTING
:
462 p
= frpr_routing6(fin
);
475 for (i
= 0; ip6exthdr
[i
].ol_bit
!= 0; i
++)
476 if (ip6exthdr
[i
].ol_val
== p
) {
477 fin
->fin_flx
|= ip6exthdr
[i
].ol_bit
;
487 case IPPROTO_FRAGMENT
:
488 p
= frpr_fragment6(fin
);
489 if (fin
->fin_off
!= 0)
500 * It is important to note that at this point, for the
501 * extension headers (go != 0), the entire header may not have
502 * been pulled up when the code gets to this point. This is
503 * only done for "go != 0" because the other header handlers
504 * will all pullup their complete header. The other indicator
505 * of an incomplete packet is that this was just an extension
508 if ((go
!= 0) && (p
!= IPPROTO_NONE
) &&
509 (frpr_pullup(fin
, 0) == -1)) {
518 /* ------------------------------------------------------------------------ */
519 /* Function: frpr_ipv6exthdr */
520 /* Returns: int - value of the next header or IPPROTO_NONE if error */
521 /* Parameters: fin(I) - pointer to packet information */
522 /* multiple(I) - flag indicating yes/no if multiple occurances */
523 /* of this extension header are allowed. */
524 /* proto(I) - protocol number for this extension header */
527 /* This function expects to find an IPv6 extension header at fin_dp. */
528 /* There must be at least 8 bytes of data at fin_dp for there to be a valid */
529 /* extension header present. If a good one is found, fin_dp is advanced to */
530 /* point at the first piece of data after the extension header, fin_exthdr */
531 /* points to the start of the extension header and the "protocol" of the */
532 /* *NEXT* header is returned. */
533 /* ------------------------------------------------------------------------ */
534 static INLINE
int frpr_ipv6exthdr(fin
, multiple
, proto
)
542 fin
->fin_flx
|= FI_V6EXTHDR
;
544 /* 8 is default length of extension hdr */
545 if ((fin
->fin_dlen
- 8) < 0) {
546 fin
->fin_flx
|= FI_SHORT
;
550 if (frpr_pullup(fin
, 8) == -1)
556 case IPPROTO_FRAGMENT
:
560 shift
= 8 + (hdr
->ip6e_len
<< 3);
564 if (shift
> fin
->fin_dlen
) { /* Nasty extension header length? */
565 fin
->fin_flx
|= FI_BAD
;
569 for (i
= 0; ip6exthdr
[i
].ol_bit
!= 0; i
++)
570 if (ip6exthdr
[i
].ol_val
== proto
) {
572 * Most IPv6 extension headers are only allowed once.
574 if ((multiple
== 0) &&
575 ((fin
->fin_optmsk
& ip6exthdr
[i
].ol_bit
) != 0))
576 fin
->fin_flx
|= FI_BAD
;
578 fin
->fin_optmsk
|= ip6exthdr
[i
].ol_bit
;
582 fin
->fin_exthdr
= fin
->fin_dp
;
583 fin
->fin_dp
= (char *)fin
->fin_dp
+ shift
;
584 fin
->fin_dlen
-= shift
;
586 return hdr
->ip6e_nxt
;
590 /* ------------------------------------------------------------------------ */
591 /* Function: frpr_hopopts6 */
592 /* Returns: int - value of the next header or IPPROTO_NONE if error */
593 /* Parameters: fin(I) - pointer to packet information */
596 /* This is function checks pending hop by hop options extension header */
597 /* ------------------------------------------------------------------------ */
598 static INLINE
int frpr_hopopts6(fin
)
601 return frpr_ipv6exthdr(fin
, 0, IPPROTO_HOPOPTS
);
605 /* ------------------------------------------------------------------------ */
606 /* Function: frpr_mobility6 */
607 /* Returns: int - value of the next header or IPPROTO_NONE if error */
608 /* Parameters: fin(I) - pointer to packet information */
611 /* This is function checks the IPv6 mobility extension header */
612 /* ------------------------------------------------------------------------ */
613 static INLINE
int frpr_mobility6(fin
)
616 return frpr_ipv6exthdr(fin
, 0, IPPROTO_MOBILITY
);
620 /* ------------------------------------------------------------------------ */
621 /* Function: frpr_routing6 */
622 /* Returns: int - value of the next header or IPPROTO_NONE if error */
623 /* Parameters: fin(I) - pointer to packet information */
626 /* This is function checks pending routing extension header */
627 /* ------------------------------------------------------------------------ */
628 static INLINE
int frpr_routing6(fin
)
633 if (frpr_ipv6exthdr(fin
, 0, IPPROTO_ROUTING
) == IPPROTO_NONE
)
635 hdr
= fin
->fin_exthdr
;
637 if ((hdr
->ip6e_len
& 1) != 0) {
639 * The routing header data is made up of 128 bit IPv6 addresses
640 * which means it must be a multiple of 2 lots of 8 in length.
642 fin
->fin_flx
|= FI_BAD
;
645 return hdr
->ip6e_nxt
;
649 /* ------------------------------------------------------------------------ */
650 /* Function: frpr_fragment6 */
651 /* Returns: int - value of the next header or IPPROTO_NONE if error */
652 /* Parameters: fin(I) - pointer to packet information */
655 /* Examine the IPv6 fragment header and extract fragment offset information.*/
657 /* We don't know where the transport layer header (or whatever is next is), */
658 /* as it could be behind destination options (amongst others). Because */
659 /* there is no fragment cache, there is no knowledge about whether or not an*/
660 /* upper layer header has been seen (or where it ends) and thus we are not */
661 /* able to continue processing beyond this header with any confidence. */
662 /* ------------------------------------------------------------------------ */
663 static INLINE
int frpr_fragment6(fin
)
666 struct ip6_frag
*frag
;
668 fin
->fin_flx
|= FI_FRAG
;
671 * A fragmented IPv6 packet implies that there must be something
672 * else after the fragment.
674 if (frpr_ipv6exthdr(fin
, 0, IPPROTO_FRAGMENT
) == IPPROTO_NONE
)
677 frag
= fin
->fin_exthdr
;
680 * If this fragment isn't the last then the packet length must
681 * be a multiple of 8.
683 if ((frag
->ip6f_offlg
& IP6F_MORE_FRAG
) != 0) {
684 fin
->fin_flx
|= FI_MOREFRAG
;
686 if ((fin
->fin_plen
& 0x7) != 0)
687 fin
->fin_flx
|= FI_BAD
;
690 fin
->fin_off
= ntohs(frag
->ip6f_offlg
& IP6F_OFF_MASK
);
691 if (fin
->fin_off
!= 0)
692 fin
->fin_flx
|= FI_FRAGBODY
;
695 * Jumbograms aren't handled, so the max. length is 64k
697 if ((fin
->fin_off
<< 3) + fin
->fin_dlen
> 65535)
698 fin
->fin_flx
|= FI_BAD
;
700 return frag
->ip6f_nxt
;
704 /* ------------------------------------------------------------------------ */
705 /* Function: frpr_dstopts6 */
706 /* Returns: int - value of the next header or IPPROTO_NONE if error */
707 /* Parameters: fin(I) - pointer to packet information */
708 /* nextheader(I) - stores next header value */
711 /* This is function checks pending destination options extension header */
712 /* ------------------------------------------------------------------------ */
713 static INLINE
int frpr_dstopts6(fin
)
716 return frpr_ipv6exthdr(fin
, 1, IPPROTO_DSTOPTS
);
720 /* ------------------------------------------------------------------------ */
721 /* Function: frpr_icmp6 */
723 /* Parameters: fin(I) - pointer to packet information */
726 /* This routine is mainly concerned with determining the minimum valid size */
727 /* for an ICMPv6 packet. */
728 /* ------------------------------------------------------------------------ */
729 static INLINE
void frpr_icmp6(fin
)
732 int minicmpsz
= sizeof(struct icmp6_hdr
);
733 struct icmp6_hdr
*icmp6
;
735 if (frpr_pullup(fin
, ICMP6ERR_MINPKTLEN
- sizeof(ip6_t
)) == -1)
738 if (fin
->fin_dlen
> 1) {
743 fin
->fin_data
[0] = *(u_short
*)icmp6
;
745 switch (icmp6
->icmp6_type
)
747 case ICMP6_ECHO_REPLY
:
748 case ICMP6_ECHO_REQUEST
:
749 minicmpsz
= ICMP6ERR_MINPKTLEN
- sizeof(ip6_t
);
751 case ICMP6_DST_UNREACH
:
752 case ICMP6_PACKET_TOO_BIG
:
753 case ICMP6_TIME_EXCEEDED
:
754 case ICMP6_PARAM_PROB
:
755 fin
->fin_flx
|= FI_ICMPERR
;
756 minicmpsz
= ICMP6ERR_IPICMPHLEN
- sizeof(ip6_t
);
757 if (fin
->fin_plen
< ICMP6ERR_IPICMPHLEN
)
760 if (M_LEN(fin
->fin_m
) < fin
->fin_plen
) {
761 if (fr_coalesce(fin
) != 1)
766 * If the destination of this packet doesn't match the
767 * source of the original packet then this packet is
771 ip6
= (ip6_t
*)((char *)icmp6
+ ICMPERR_ICMPHLEN
);
772 if (IP6_NEQ(&fin
->fin_fi
.fi_dst
,
774 fin
->fin_flx
|= FI_BAD
;
782 frpr_short6(fin
, minicmpsz
);
786 /* ------------------------------------------------------------------------ */
787 /* Function: frpr_udp6 */
789 /* Parameters: fin(I) - pointer to packet information */
792 /* Analyse the packet for IPv6/UDP properties. */
793 /* Is not expected to be called for fragmented packets. */
794 /* ------------------------------------------------------------------------ */
795 static INLINE
void frpr_udp6(fin
)
799 frpr_short6(fin
, sizeof(struct udphdr
));
801 if (frpr_udpcommon(fin
) == 0) {
802 u_char p
= fin
->fin_p
;
804 fin
->fin_p
= IPPROTO_UDP
;
811 /* ------------------------------------------------------------------------ */
812 /* Function: frpr_tcp6 */
814 /* Parameters: fin(I) - pointer to packet information */
817 /* Analyse the packet for IPv6/TCP properties. */
818 /* Is not expected to be called for fragmented packets. */
819 /* ------------------------------------------------------------------------ */
820 static INLINE
void frpr_tcp6(fin
)
824 frpr_short6(fin
, sizeof(struct tcphdr
));
826 if (frpr_tcpcommon(fin
) == 0) {
827 u_char p
= fin
->fin_p
;
829 fin
->fin_p
= IPPROTO_TCP
;
836 /* ------------------------------------------------------------------------ */
837 /* Function: frpr_esp6 */
839 /* Parameters: fin(I) - pointer to packet information */
842 /* Analyse the packet for ESP properties. */
843 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */
844 /* even though the newer ESP packets must also have a sequence number that */
845 /* is 32bits as well, it is not possible(?) to determine the version from a */
846 /* simple packet header. */
847 /* ------------------------------------------------------------------------ */
848 static INLINE
void frpr_esp6(fin
)
852 frpr_short6(fin
, sizeof(grehdr_t
));
854 (void) frpr_pullup(fin
, 8);
858 /* ------------------------------------------------------------------------ */
859 /* Function: frpr_ah6 */
861 /* Parameters: fin(I) - pointer to packet information */
864 /* Analyse the packet for AH properties. */
865 /* The minimum length is taken to be the combination of all fields in the */
866 /* header being present and no authentication data (null algorithm used.) */
867 /* ------------------------------------------------------------------------ */
868 static INLINE
int frpr_ah6(fin
)
873 frpr_short6(fin
, 12);
875 if (frpr_pullup(fin
, sizeof(*ah
)) == -1)
878 ah
= (authhdr_t
*)fin
->fin_dp
;
883 /* ------------------------------------------------------------------------ */
884 /* Function: frpr_gre6 */
886 /* Parameters: fin(I) - pointer to packet information */
888 /* Analyse the packet for GRE properties. */
889 /* ------------------------------------------------------------------------ */
890 static INLINE
void frpr_gre6(fin
)
895 frpr_short6(fin
, sizeof(grehdr_t
));
897 if (frpr_pullup(fin
, sizeof(grehdr_t
)) == -1)
901 if (GRE_REV(gre
->gr_flags
) == 1)
902 fin
->fin_data
[0] = gre
->gr_call
;
904 #endif /* USE_INET6 */
907 /* ------------------------------------------------------------------------ */
908 /* Function: frpr_pullup */
909 /* Returns: int - 0 == pullup succeeded, -1 == failure */
910 /* Parameters: fin(I) - pointer to packet information */
911 /* plen(I) - length (excluding L3 header) to pullup */
913 /* Short inline function to cut down on code duplication to perform a call */
914 /* to fr_pullup to ensure there is the required amount of data, */
915 /* consecutively in the packet buffer. */
917 /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */
918 /* points to the first byte after the complete layer 3 header, which will */
919 /* include all of the known extension headers for IPv6 or options for IPv4. */
921 /* Since fr_pullup() expects the total length of bytes to be pulled up, it */
922 /* is necessary to add those we can already assume to be pulled up (fin_dp */
923 /* - fin_ip) to what is passed through. */
924 /* ------------------------------------------------------------------------ */
925 static INLINE
int frpr_pullup(fin
, plen
)
929 if (fin
->fin_m
!= NULL
) {
930 if (fin
->fin_dp
!= NULL
)
931 plen
+= (char *)fin
->fin_dp
-
932 ((char *)fin
->fin_ip
+ fin
->fin_hlen
);
933 plen
+= fin
->fin_hlen
;
934 if (M_LEN(fin
->fin_m
) < plen
) {
936 if (fr_pullup(fin
->fin_m
, fin
, plen
) == NULL
)
940 * Fake fr_pullup failing
953 /* ------------------------------------------------------------------------ */
954 /* Function: frpr_short */
956 /* Parameters: fin(I) - pointer to packet information */
957 /* xmin(I) - minimum header size */
959 /* Check if a packet is "short" as defined by xmin. The rule we are */
960 /* applying here is that the packet must not be fragmented within the layer */
961 /* 4 header. That is, it must not be a fragment that has its offset set to */
962 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */
963 /* entire layer 4 header must be present (min). */
964 /* ------------------------------------------------------------------------ */
965 static INLINE
void frpr_short(fin
, xmin
)
970 if (fin
->fin_off
== 0) {
971 if (fin
->fin_dlen
< xmin
)
972 fin
->fin_flx
|= FI_SHORT
;
973 } else if (fin
->fin_off
< xmin
) {
974 fin
->fin_flx
|= FI_SHORT
;
979 /* ------------------------------------------------------------------------ */
980 /* Function: frpr_icmp */
982 /* Parameters: fin(I) - pointer to packet information */
985 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */
986 /* except extrememly bad packets, both type and code will be present. */
987 /* The expected minimum size of an ICMP packet is very much dependent on */
988 /* the type of it. */
990 /* XXX - other ICMP sanity checks? */
991 /* ------------------------------------------------------------------------ */
992 static INLINE
void frpr_icmp(fin
)
995 int minicmpsz
= sizeof(struct icmp
);
999 if (fin
->fin_off
!= 0) {
1000 frpr_short(fin
, ICMPERR_ICMPHLEN
);
1004 if (frpr_pullup(fin
, ICMPERR_ICMPHLEN
) == -1)
1009 fin
->fin_data
[0] = *(u_short
*)icmp
;
1010 fin
->fin_data
[1] = icmp
->icmp_id
;
1012 switch (icmp
->icmp_type
)
1014 case ICMP_ECHOREPLY
:
1016 /* Router discovery messaes - RFC 1256 */
1017 case ICMP_ROUTERADVERT
:
1018 case ICMP_ROUTERSOLICIT
:
1019 minicmpsz
= ICMP_MINLEN
;
1022 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1023 * 3 * timestamp(3 * 4)
1026 case ICMP_TSTAMPREPLY
:
1030 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1034 case ICMP_MASKREPLY
:
1038 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
1042 if (icmp
->icmp_code
== ICMP_UNREACH_NEEDFRAG
) {
1043 if (icmp
->icmp_nextmtu
< fr_icmpminfragmtu
)
1044 fin
->fin_flx
|= FI_BAD
;
1047 case ICMP_SOURCEQUENCH
:
1048 case ICMP_REDIRECT
:
1049 case ICMP_TIMXCEED
:
1050 case ICMP_PARAMPROB
:
1051 fin
->fin_flx
|= FI_ICMPERR
;
1052 if (fr_coalesce(fin
) != 1)
1055 * ICMP error packets should not be generated for IP
1056 * packets that are a fragment that isn't the first
1059 oip
= (ip_t
*)((char *)fin
->fin_dp
+ ICMPERR_ICMPHLEN
);
1060 if ((ntohs(oip
->ip_off
) & IP_OFFMASK
) != 0)
1061 fin
->fin_flx
|= FI_BAD
;
1064 * If the destination of this packet doesn't match the
1065 * source of the original packet then this packet is
1068 if (oip
->ip_src
.s_addr
!= fin
->fin_daddr
)
1069 fin
->fin_flx
|= FI_BAD
;
1072 * If the destination of this packet doesn't match the
1073 * source of the original packet then this packet is
1076 if (oip
->ip_src
.s_addr
!= fin
->fin_daddr
)
1077 fin
->fin_flx
|= FI_BAD
;
1083 frpr_short(fin
, minicmpsz
);
1085 if ((fin
->fin_flx
& FI_FRAG
) == 0)
1090 /* ------------------------------------------------------------------------ */
1091 /* Function: frpr_tcpcommon */
1092 /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */
1093 /* Parameters: fin(I) - pointer to packet information */
1095 /* TCP header sanity checking. Look for bad combinations of TCP flags, */
1096 /* and make some checks with how they interact with other fields. */
1097 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */
1098 /* valid and mark the packet as bad if not. */
1099 /* ------------------------------------------------------------------------ */
1100 static INLINE
int frpr_tcpcommon(fin
)
1106 fin
->fin_flx
|= FI_TCPUDP
;
1107 if (fin
->fin_off
!= 0)
1110 if (frpr_pullup(fin
, sizeof(*tcp
)) == -1)
1114 if (fin
->fin_dlen
> 3) {
1115 fin
->fin_sport
= ntohs(tcp
->th_sport
);
1116 fin
->fin_dport
= ntohs(tcp
->th_dport
);
1119 if ((fin
->fin_flx
& FI_SHORT
) != 0)
1123 * Use of the TCP data offset *must* result in a value that is at
1124 * least the same size as the TCP header.
1126 tlen
= TCP_OFF(tcp
) << 2;
1127 if (tlen
< sizeof(tcphdr_t
)) {
1128 fin
->fin_flx
|= FI_BAD
;
1132 flags
= tcp
->th_flags
;
1133 fin
->fin_tcpf
= tcp
->th_flags
;
1136 * If the urgent flag is set, then the urgent pointer must
1137 * also be set and vice versa. Good TCP packets do not have
1138 * just one of these set.
1140 if ((flags
& TH_URG
) != 0 && (tcp
->th_urp
== 0)) {
1141 fin
->fin_flx
|= FI_BAD
;
1143 } else if ((flags
& TH_URG
) == 0 && (tcp
->th_urp
!= 0)) {
1145 * Ignore this case (#if 0) as it shows up in "real"
1146 * traffic with bogus values in the urgent pointer field.
1148 fin
->fin_flx
|= FI_BAD
;
1150 } else if (((flags
& (TH_SYN
|TH_FIN
)) != 0) &&
1151 ((flags
& (TH_RST
|TH_ACK
)) == TH_RST
)) {
1152 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
1153 fin
->fin_flx
|= FI_BAD
;
1155 } else if (((flags
& TH_SYN
) != 0) &&
1156 ((flags
& (TH_URG
|TH_PUSH
)) != 0)) {
1158 * SYN with URG and PUSH set is not for normal TCP but it is
1159 * possible(?) with T/TCP...but who uses T/TCP?
1161 fin
->fin_flx
|= FI_BAD
;
1163 } else if (!(flags
& TH_ACK
)) {
1165 * If the ack bit isn't set, then either the SYN or
1166 * RST bit must be set. If the SYN bit is set, then
1167 * we expect the ACK field to be 0. If the ACK is
1168 * not set and if URG, PSH or FIN are set, consdier
1169 * that to indicate a bad TCP packet.
1171 if ((flags
== TH_SYN
) && (tcp
->th_ack
!= 0)) {
1173 * Cisco PIX sets the ACK field to a random value.
1174 * In light of this, do not set FI_BAD until a patch
1175 * is available from Cisco to ensure that
1176 * interoperability between existing systems is
1179 /*fin->fin_flx |= FI_BAD*/;
1180 } else if (!(flags
& (TH_RST
|TH_SYN
))) {
1181 fin
->fin_flx
|= FI_BAD
;
1182 } else if ((flags
& (TH_URG
|TH_PUSH
|TH_FIN
)) != 0) {
1183 fin
->fin_flx
|= FI_BAD
;
1188 * At this point, it's not exactly clear what is to be gained by
1189 * marking up which TCP options are and are not present. The one we
1190 * are most interested in is the TCP window scale. This is only in
1191 * a SYN packet [RFC1323] so we don't need this here...?
1192 * Now if we were to analyse the header for passive fingerprinting,
1193 * then that might add some weight to adding this...
1195 if (tlen
== sizeof(tcphdr_t
))
1198 if (frpr_pullup(fin
, tlen
) == -1)
1204 s
= (u_char
*)(tcp
+ 1);
1205 off
= IP_HL(ip
) << 2;
1207 if (fin
->fin_mp
!= NULL
) {
1208 mb_t
*m
= *fin
->fin_mp
;
1210 if (off
+ tlen
> M_LEN(m
))
1214 for (tlen
-= (int)sizeof(*tcp
); tlen
> 0; ) {
1218 else if (opt
== TCPOPT_NOP
)
1224 if (ol
< 2 || ol
> tlen
)
1228 for (i
= 9, mv
= 4; mv
>= 0; ) {
1230 if (opt
== (u_char
)op
->ol_val
) {
1231 optmsk
|= op
->ol_bit
;
1245 /* ------------------------------------------------------------------------ */
1246 /* Function: frpr_udpcommon */
1247 /* Returns: int - 0 = header ok, 1 = bad packet */
1248 /* Parameters: fin(I) - pointer to packet information */
1250 /* Extract the UDP source and destination ports, if present. If compiled */
1251 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */
1252 /* ------------------------------------------------------------------------ */
1253 static INLINE
int frpr_udpcommon(fin
)
1258 fin
->fin_flx
|= FI_TCPUDP
;
1260 if (!fin
->fin_off
&& (fin
->fin_dlen
> 3)) {
1261 if (frpr_pullup(fin
, sizeof(*udp
)) == -1) {
1262 fin
->fin_flx
|= FI_SHORT
;
1268 fin
->fin_sport
= ntohs(udp
->uh_sport
);
1269 fin
->fin_dport
= ntohs(udp
->uh_dport
);
1276 /* ------------------------------------------------------------------------ */
1277 /* Function: frpr_tcp */
1279 /* Parameters: fin(I) - pointer to packet information */
1282 /* Analyse the packet for IPv4/TCP properties. */
1283 /* ------------------------------------------------------------------------ */
1284 static INLINE
void frpr_tcp(fin
)
1288 frpr_short(fin
, sizeof(tcphdr_t
));
1290 if (frpr_tcpcommon(fin
) == 0) {
1291 if ((fin
->fin_flx
& FI_FRAG
) == 0)
1297 /* ------------------------------------------------------------------------ */
1298 /* Function: frpr_udp */
1300 /* Parameters: fin(I) - pointer to packet information */
1303 /* Analyse the packet for IPv4/UDP properties. */
1304 /* ------------------------------------------------------------------------ */
1305 static INLINE
void frpr_udp(fin
)
1309 frpr_short(fin
, sizeof(udphdr_t
));
1311 if (frpr_udpcommon(fin
) == 0) {
1312 if ((fin
->fin_flx
& FI_FRAG
) == 0)
1318 /* ------------------------------------------------------------------------ */
1319 /* Function: frpr_esp */
1321 /* Parameters: fin(I) - pointer to packet information */
1323 /* Analyse the packet for ESP properties. */
1324 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */
1325 /* even though the newer ESP packets must also have a sequence number that */
1326 /* is 32bits as well, it is not possible(?) to determine the version from a */
1327 /* simple packet header. */
1328 /* ------------------------------------------------------------------------ */
1329 static INLINE
void frpr_esp(fin
)
1333 if (fin
->fin_off
== 0) {
1335 (void) frpr_pullup(fin
, 8);
1341 /* ------------------------------------------------------------------------ */
1342 /* Function: frpr_ah */
1344 /* Parameters: fin(I) - pointer to packet information */
1346 /* Analyse the packet for AH properties. */
1347 /* The minimum length is taken to be the combination of all fields in the */
1348 /* header being present and no authentication data (null algorithm used.) */
1349 /* ------------------------------------------------------------------------ */
1350 static INLINE
void frpr_ah(fin
)
1356 frpr_short(fin
, sizeof(*ah
));
1358 if (((fin
->fin_flx
& FI_SHORT
) != 0) || (fin
->fin_off
!= 0))
1361 if (frpr_pullup(fin
, sizeof(*ah
)) == -1)
1364 ah
= (authhdr_t
*)fin
->fin_dp
;
1366 len
= (ah
->ah_plen
+ 2) << 2;
1367 frpr_short(fin
, len
);
1371 /* ------------------------------------------------------------------------ */
1372 /* Function: frpr_gre */
1374 /* Parameters: fin(I) - pointer to packet information */
1376 /* Analyse the packet for GRE properties. */
1377 /* ------------------------------------------------------------------------ */
1378 static INLINE
void frpr_gre(fin
)
1383 frpr_short(fin
, sizeof(*gre
));
1385 if (fin
->fin_off
!= 0)
1388 if (frpr_pullup(fin
, sizeof(*gre
)) == -1)
1391 if (fin
->fin_off
== 0) {
1393 if (GRE_REV(gre
->gr_flags
) == 1)
1394 fin
->fin_data
[0] = gre
->gr_call
;
1399 /* ------------------------------------------------------------------------ */
1400 /* Function: frpr_ipv4hdr */
1402 /* Parameters: fin(I) - pointer to packet information */
1405 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */
1406 /* Check all options present and flag their presence if any exist. */
1407 /* ------------------------------------------------------------------------ */
1408 static INLINE
void frpr_ipv4hdr(fin
)
1411 u_short optmsk
= 0, secmsk
= 0, auth
= 0;
1412 int hlen
, ol
, mv
, p
, i
;
1413 const struct optlist
*op
;
1420 hlen
= fin
->fin_hlen
;
1425 fi
->fi_tos
= ip
->ip_tos
;
1426 fin
->fin_id
= ip
->ip_id
;
1429 /* Get both TTL and protocol */
1430 fi
->fi_p
= ip
->ip_p
;
1431 fi
->fi_ttl
= ip
->ip_ttl
;
1433 (*(((u_short
*)fi
) + 1)) = (*(((u_short
*)ip
) + 4));
1436 /* Zero out bits not used in IPv6 address */
1437 fi
->fi_src
.i6
[1] = 0;
1438 fi
->fi_src
.i6
[2] = 0;
1439 fi
->fi_src
.i6
[3] = 0;
1440 fi
->fi_dst
.i6
[1] = 0;
1441 fi
->fi_dst
.i6
[2] = 0;
1442 fi
->fi_dst
.i6
[3] = 0;
1444 fi
->fi_saddr
= ip
->ip_src
.s_addr
;
1445 fi
->fi_daddr
= ip
->ip_dst
.s_addr
;
1448 * set packet attribute flags based on the offset and
1449 * calculate the byte offset that it represents.
1451 off
&= IP_MF
|IP_OFFMASK
;
1453 int morefrag
= off
& IP_MF
;
1455 fi
->fi_flx
|= FI_FRAG
;
1457 fi
->fi_flx
|= FI_MOREFRAG
;
1460 fin
->fin_flx
|= FI_FRAGBODY
;
1462 if ((off
+ fin
->fin_dlen
> 65535) ||
1463 (fin
->fin_dlen
== 0) ||
1464 ((morefrag
!= 0) && ((fin
->fin_dlen
& 7) != 0))) {
1466 * The length of the packet, starting at its
1467 * offset cannot exceed 65535 (0xffff) as the
1468 * length of an IP packet is only 16 bits.
1470 * Any fragment that isn't the last fragment
1471 * must have a length greater than 0 and it
1472 * must be an even multiple of 8.
1474 fi
->fi_flx
|= FI_BAD
;
1481 * Call per-protocol setup and checking
1510 * If it is a standard IP header (no options), set the flag fields
1511 * which relate to options to 0.
1513 if (hlen
== sizeof(*ip
)) {
1521 * So the IP header has some IP options attached. Walk the entire
1522 * list of options present with this packet and set flags to indicate
1523 * which ones are here and which ones are not. For the somewhat out
1524 * of date and obscure security classification options, set a flag to
1525 * represent which classification is present.
1527 fi
->fi_flx
|= FI_OPTIONS
;
1529 for (s
= (u_char
*)(ip
+ 1), hlen
-= (int)sizeof(*ip
); hlen
> 0; ) {
1533 else if (opt
== IPOPT_NOP
)
1539 if (ol
< 2 || ol
> hlen
)
1542 for (i
= 9, mv
= 4; mv
>= 0; ) {
1544 if ((opt
== (u_char
)op
->ol_val
) && (ol
> 4)) {
1545 optmsk
|= op
->ol_bit
;
1546 if (opt
== IPOPT_SECURITY
) {
1547 const struct optlist
*sp
;
1551 sec
= *(s
+ 2); /* classification */
1552 for (j
= 3, m
= 2; m
>= 0; ) {
1554 if (sec
== sp
->ol_val
) {
1555 secmsk
|= sp
->ol_bit
;
1561 if (sec
< sp
->ol_val
)
1570 if (opt
< op
->ol_val
)
1583 if (auth
&& !(auth
& 0x0100))
1585 fi
->fi_optmsk
= optmsk
;
1586 fi
->fi_secmsk
= secmsk
;
1591 /* ------------------------------------------------------------------------ */
1592 /* Function: fr_makefrip */
1594 /* Parameters: hlen(I) - length of IP packet header */
1595 /* ip(I) - pointer to the IP header */
1596 /* fin(IO) - pointer to packet information */
1598 /* Compact the IP header into a structure which contains just the info. */
1599 /* which is useful for comparing IP headers with and store this information */
1600 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */
1601 /* this function will be called with either an IPv4 or IPv6 packet. */
1602 /* ------------------------------------------------------------------------ */
1603 int fr_makefrip(hlen
, ip
, fin
)
1611 fin
->fin_hlen
= (u_short
)hlen
;
1613 fin
->fin_rule
= 0xffffffff;
1614 fin
->fin_group
[0] = -1;
1615 fin
->fin_group
[1] = '\0';
1616 fin
->fin_dp
= (char *)ip
+ hlen
;
1620 fin
->fin_plen
= ip
->ip_len
;
1621 fin
->fin_dlen
= fin
->fin_plen
- hlen
;
1625 } else if (v
== 6) {
1626 fin
->fin_plen
= ntohs(((ip6_t
*)ip
)->ip6_plen
);
1627 fin
->fin_dlen
= fin
->fin_plen
;
1628 fin
->fin_plen
+= hlen
;
1633 if (fin
->fin_ip
== NULL
)
1639 /* ------------------------------------------------------------------------ */
1640 /* Function: fr_portcheck */
1641 /* Returns: int - 1 == port matched, 0 == port match failed */
1642 /* Parameters: frp(I) - pointer to port check `expression' */
1643 /* pop(I) - pointer to port number to evaluate */
1645 /* Perform a comparison of a port number against some other(s), using a */
1646 /* structure with compare information stored in it. */
1647 /* ------------------------------------------------------------------------ */
1648 static INLINE
int fr_portcheck(frp
, pop
)
1659 * Do opposite test to that required and continue if that succeeds.
1661 switch (frp
->frp_cmp
)
1664 if (tup
!= po
) /* EQUAL */
1668 if (tup
== po
) /* NOTEQUAL */
1672 if (tup
>= po
) /* LESSTHAN */
1676 if (tup
<= po
) /* GREATERTHAN */
1680 if (tup
> po
) /* LT or EQ */
1684 if (tup
< po
) /* GT or EQ */
1688 if (tup
>= po
&& tup
<= frp
->frp_top
) /* Out of range */
1692 if (tup
<= po
|| tup
>= frp
->frp_top
) /* In range */
1696 if (tup
< po
|| tup
> frp
->frp_top
) /* Inclusive range */
1706 /* ------------------------------------------------------------------------ */
1707 /* Function: fr_tcpudpchk */
1708 /* Returns: int - 1 == protocol matched, 0 == check failed */
1709 /* Parameters: fin(I) - pointer to packet information */
1710 /* ft(I) - pointer to structure with comparison data */
1712 /* Compares the current pcket (assuming it is TCP/UDP) information with a */
1713 /* structure containing information that we want to match against. */
1714 /* ------------------------------------------------------------------------ */
1715 int fr_tcpudpchk(fin
, ft
)
1722 * Both ports should *always* be in the first fragment.
1723 * So far, I cannot find any cases where they can not be.
1725 * compare destination ports
1728 err
= fr_portcheck(&ft
->ftu_dst
, &fin
->fin_dport
);
1731 * compare source ports
1733 if (err
&& ft
->ftu_scmp
)
1734 err
= fr_portcheck(&ft
->ftu_src
, &fin
->fin_sport
);
1737 * If we don't have all the TCP/UDP header, then how can we
1738 * expect to do any sort of match on it ? If we were looking for
1739 * TCP flags, then NO match. If not, then match (which should
1740 * satisfy the "short" class too).
1742 if (err
&& (fin
->fin_p
== IPPROTO_TCP
)) {
1743 if (fin
->fin_flx
& FI_SHORT
)
1744 return !(ft
->ftu_tcpf
| ft
->ftu_tcpfm
);
1746 * Match the flags ? If not, abort this match.
1748 if (ft
->ftu_tcpfm
&&
1749 ft
->ftu_tcpf
!= (fin
->fin_tcpf
& ft
->ftu_tcpfm
)) {
1750 FR_DEBUG(("f. %#x & %#x != %#x\n", fin
->fin_tcpf
,
1751 ft
->ftu_tcpfm
, ft
->ftu_tcpf
));
1760 /* ------------------------------------------------------------------------ */
1761 /* Function: fr_ipfcheck */
1762 /* Returns: int - 0 == match, 1 == no match */
1763 /* Parameters: fin(I) - pointer to packet information */
1764 /* fr(I) - pointer to filter rule */
1765 /* portcmp(I) - flag indicating whether to attempt matching on */
1766 /* TCP/UDP port data. */
1768 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */
1769 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
1770 /* this function. */
1771 /* ------------------------------------------------------------------------ */
1772 static INLINE
int fr_ipfcheck(fin
, fr
, portcmp
)
1777 u_32_t
*ld
, *lm
, *lip
;
1785 lm
= (u_32_t
*)&fri
->fri_mip
;
1786 ld
= (u_32_t
*)&fri
->fri_ip
;
1789 * first 32 bits to check coversion:
1790 * IP version, TOS, TTL, protocol
1792 i
= ((*lip
& *lm
) != *ld
);
1793 FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
1794 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1799 * Next 32 bits is a constructed bitmask indicating which IP options
1800 * are present (if any) in this packet.
1803 i
|= ((*lip
& *lm
) != *ld
);
1804 FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
1805 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1811 * Unrolled loops (4 each, for 32 bits) for address checks.
1814 * Check the source address.
1816 #ifdef IPFILTER_LOOKUP
1817 if (fr
->fr_satype
== FRI_LOOKUP
) {
1818 i
= (*fr
->fr_srcfunc
)(fr
->fr_srcptr
, fi
->fi_v
, lip
);
1826 i
= ((*lip
& *lm
) != *ld
);
1827 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
1828 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1829 if (fi
->fi_v
== 6) {
1831 i
|= ((*lip
& *lm
) != *ld
);
1832 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
1833 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1835 i
|= ((*lip
& *lm
) != *ld
);
1836 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
1837 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1839 i
|= ((*lip
& *lm
) != *ld
);
1840 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
1841 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1847 #ifdef IPFILTER_LOOKUP
1850 i
^= (fr
->fr_flags
& FR_NOTSRCIP
) >> 6;
1855 * Check the destination address.
1858 #ifdef IPFILTER_LOOKUP
1859 if (fr
->fr_datype
== FRI_LOOKUP
) {
1860 i
= (*fr
->fr_dstfunc
)(fr
->fr_dstptr
, fi
->fi_v
, lip
);
1868 i
= ((*lip
& *lm
) != *ld
);
1869 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
1870 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1871 if (fi
->fi_v
== 6) {
1873 i
|= ((*lip
& *lm
) != *ld
);
1874 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
1875 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1877 i
|= ((*lip
& *lm
) != *ld
);
1878 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
1879 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1881 i
|= ((*lip
& *lm
) != *ld
);
1882 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
1883 ntohl(*lip
), ntohl(*lm
), ntohl(*ld
)));
1889 #ifdef IPFILTER_LOOKUP
1892 i
^= (fr
->fr_flags
& FR_NOTDSTIP
) >> 7;
1896 * IP addresses matched. The next 32bits contains:
1897 * mast of old IP header security & authentication bits.
1900 i
|= ((*lip
& *lm
) != *ld
);
1901 FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
1905 * Next we have 32 bits of packet flags.
1908 i
|= ((*lip
& *lm
) != *ld
);
1909 FR_DEBUG(("5. %#08x & %#08x != %#08x\n",
1914 * If a fragment, then only the first has what we're
1915 * looking for here...
1918 if (!fr_tcpudpchk(fin
, &fr
->fr_tuc
))
1921 if (fr
->fr_dcmp
|| fr
->fr_scmp
||
1922 fr
->fr_tcpf
|| fr
->fr_tcpfm
)
1924 if (fr
->fr_icmpm
|| fr
->fr_icmp
) {
1925 if (((fi
->fi_p
!= IPPROTO_ICMP
) &&
1926 (fi
->fi_p
!= IPPROTO_ICMPV6
)) ||
1927 fin
->fin_off
|| (fin
->fin_dlen
< 2))
1929 else if ((fin
->fin_data
[0] & fr
->fr_icmpm
) !=
1931 FR_DEBUG(("i. %#x & %#x != %#x\n",
1933 fr
->fr_icmpm
, fr
->fr_icmp
));
1943 /* ------------------------------------------------------------------------ */
1944 /* Function: fr_scanlist */
1945 /* Returns: int - result flags of scanning filter list */
1946 /* Parameters: fin(I) - pointer to packet information */
1947 /* pass(I) - default result to return for filtering */
1949 /* Check the input/output list of rules for a match to the current packet. */
1950 /* If a match is found, the value of fr_flags from the rule becomes the */
1951 /* return value and fin->fin_fr points to the matched rule. */
1953 /* This function may be called recusively upto 16 times (limit inbuilt.) */
1954 /* When unwinding, it should finish up with fin_depth as 0. */
1956 /* Could be per interface, but this gets real nasty when you don't have, */
1957 /* or can't easily change, the kernel source code to . */
1958 /* ------------------------------------------------------------------------ */
1959 int fr_scanlist(fin
, pass
)
1963 int rulen
, portcmp
, off
, skip
;
1964 struct frentry
*fr
, *fnext
;
1965 u_32_t passt
, passo
;
1968 * Do not allow nesting deeper than 16 levels.
1970 if (fin
->fin_depth
>= 16)
1976 * If there are no rules in this list, return now.
1987 if ((fin
->fin_flx
& FI_TCPUDP
) && (fin
->fin_dlen
> 3) && !off
)
1990 for (rulen
= 0; fr
; fr
= fnext
, rulen
++) {
1991 fnext
= fr
->fr_next
;
1993 FR_VERBOSE(("%d (%#x)\n", skip
, fr
->fr_flags
));
1999 * In all checks below, a null (zero) value in the
2000 * filter struture is taken to mean a wildcard.
2002 * check that we are working for the right interface
2005 if (fr
->fr_ifa
&& fr
->fr_ifa
!= fin
->fin_ifp
)
2008 if (opts
& (OPT_VERBOSE
|OPT_DEBUG
))
2010 FR_VERBOSE(("%c", FR_ISSKIP(pass
) ? 's' :
2011 FR_ISPASS(pass
) ? 'p' :
2012 FR_ISACCOUNT(pass
) ? 'A' :
2013 FR_ISAUTH(pass
) ? 'a' :
2014 (pass
& FR_NOMATCH
) ? 'n' :'b'));
2015 if (fr
->fr_ifa
&& fr
->fr_ifa
!= fin
->fin_ifp
)
2020 switch (fr
->fr_type
)
2023 case FR_T_IPF
|FR_T_BUILTIN
:
2024 if (fr_ipfcheck(fin
, fr
, portcmp
))
2027 #if defined(IPFILTER_BPF)
2029 case FR_T_BPFOPC
|FR_T_BUILTIN
:
2033 if (*fin
->fin_mp
== NULL
)
2035 if (fin
->fin_v
!= fr
->fr_v
)
2037 mc
= (u_char
*)fin
->fin_m
;
2038 if (!bpf_filter(fr
->fr_data
, mc
, fin
->fin_plen
, 0))
2043 case FR_T_CALLFUNC
|FR_T_BUILTIN
:
2047 f
= (*fr
->fr_func
)(fin
, &pass
);
2058 if ((fin
->fin_out
== 0) && (fr
->fr_nattag
.ipt_num
[0] != 0)) {
2059 if (fin
->fin_nattag
== NULL
)
2061 if (fr_matchtag(&fr
->fr_nattag
, fin
->fin_nattag
) == 0)
2064 FR_VERBOSE(("=%s.%d *", fr
->fr_group
, rulen
));
2066 passt
= fr
->fr_flags
;
2069 * Allowing a rule with the "keep state" flag set to match
2070 * packets that have been tagged "out of window" by the TCP
2071 * state tracking is foolish as the attempt to add a new
2072 * state entry to the table will fail.
2074 if ((passt
& FR_KEEPSTATE
) && (fin
->fin_flx
& FI_OOW
))
2078 * If the rule is a "call now" rule, then call the function
2079 * in the rule, if it exists and use the results from that.
2080 * If the function pointer is bad, just make like we ignore
2081 * it, except for increasing the hit counter.
2083 if ((passt
& FR_CALLNOW
) != 0) {
2086 ATOMIC_INC64(fr
->fr_hits
);
2087 if ((fr
->fr_func
!= NULL
) &&
2088 (fr
->fr_func
== (ipfunc_t
)-1))
2093 fr
= (*fr
->fr_func
)(fin
, &passt
);
2098 passt
= fr
->fr_flags
;
2104 * Just log this packet...
2106 if ((passt
& FR_LOGMASK
) == FR_LOG
) {
2107 if (ipflog(fin
, passt
) == -1) {
2108 if (passt
& FR_LOGORBLOCK
) {
2109 passt
&= ~FR_CMDMASK
;
2110 passt
|= FR_BLOCK
|FR_QUICK
;
2112 ATOMIC_INCL(frstats
[fin
->fin_out
].fr_skip
);
2114 ATOMIC_INCL(frstats
[fin
->fin_out
].fr_pkl
);
2115 fin
->fin_flx
|= FI_DONTCACHE
;
2117 #endif /* IPFILTER_LOG */
2118 fr
->fr_bytes
+= (U_QUAD_T
)fin
->fin_plen
;
2120 if (FR_ISSKIP(passt
))
2122 else if ((passt
& FR_LOGMASK
) != FR_LOG
)
2124 if (passt
& (FR_RETICMP
|FR_FAKEICMP
))
2125 fin
->fin_icode
= fr
->fr_icode
;
2126 FR_DEBUG(("pass %#x\n", pass
));
2127 ATOMIC_INC64(fr
->fr_hits
);
2128 fin
->fin_rule
= rulen
;
2129 (void) strncpy(fin
->fin_group
, fr
->fr_group
, FR_GROUPLEN
);
2130 if (fr
->fr_grp
!= NULL
) {
2131 fin
->fin_fr
= *fr
->fr_grp
;
2132 passt
= fr_scanlist(fin
, pass
);
2133 if (fin
->fin_fr
== NULL
) {
2134 fin
->fin_rule
= rulen
;
2135 (void) strncpy(fin
->fin_group
, fr
->fr_group
,
2143 if (passt
& FR_QUICK
) {
2145 * Finally, if we've asked to track state for this
2146 * packet, set it up. Add state for "quick" rules
2147 * here so that if the action fails we can consider
2148 * the rule to "not match" and keep on processing
2151 if ((pass
& FR_KEEPSTATE
) && !FR_ISAUTH(pass
) &&
2152 !(fin
->fin_flx
& FI_STATE
)) {
2153 int out
= fin
->fin_out
;
2156 if (fr_addstate(fin
, NULL
, 0) != NULL
) {
2157 ATOMIC_INCL(frstats
[out
].fr_ads
);
2159 ATOMIC_INCL(frstats
[out
].fr_bads
);
2172 /* ------------------------------------------------------------------------ */
2173 /* Function: fr_acctpkt */
2174 /* Returns: frentry_t* - always returns NULL */
2175 /* Parameters: fin(I) - pointer to packet information */
2176 /* passp(IO) - pointer to current/new filter decision (unused) */
2178 /* Checks a packet against accounting rules, if there are any for the given */
2179 /* IP protocol version. */
2181 /* N.B.: this function returns NULL to match the prototype used by other */
2182 /* functions called from the IPFilter "mainline" in fr_check(). */
2183 /* ------------------------------------------------------------------------ */
2184 frentry_t
*fr_acctpkt(fin
, passp
)
2188 char group
[FR_GROUPLEN
];
2189 frentry_t
*fr
, *frsave
;
2194 if (fin
->fin_v
== 6)
2195 fr
= ipacct6
[fin
->fin_out
][fr_active
];
2198 fr
= ipacct
[fin
->fin_out
][fr_active
];
2201 frsave
= fin
->fin_fr
;
2202 bcopy(fin
->fin_group
, group
, FR_GROUPLEN
);
2203 rulen
= fin
->fin_rule
;
2205 pass
= fr_scanlist(fin
, FR_NOMATCH
);
2206 if (FR_ISACCOUNT(pass
)) {
2207 ATOMIC_INCL(frstats
[0].fr_acct
);
2209 fin
->fin_fr
= frsave
;
2210 bcopy(group
, fin
->fin_group
, FR_GROUPLEN
);
2211 fin
->fin_rule
= rulen
;
2217 /* ------------------------------------------------------------------------ */
2218 /* Function: fr_firewall */
2219 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */
2220 /* were found, returns NULL. */
2221 /* Parameters: fin(I) - pointer to packet information */
2222 /* passp(IO) - pointer to current/new filter decision (unused) */
2224 /* Applies an appropriate set of firewall rules to the packet, to see if */
2225 /* there are any matches. The first check is to see if a match can be seen */
2226 /* in the cache. If not, then search an appropriate list of rules. Once a */
2227 /* matching rule is found, take any appropriate actions as defined by the */
2228 /* rule - except logging. */
2229 /* ------------------------------------------------------------------------ */
2230 static frentry_t
*fr_firewall(fin
, passp
)
2243 * If a packet is found in the auth table, then skip checking
2244 * the access lists for permission but we do need to consider
2245 * the result as if it were from the ACL's.
2247 fc
= &frcache
[out
][CACHE_HASH(fin
)];
2248 READ_ENTER(&ipf_frcache
);
2249 if (!bcmp((char *)fin
, (char *)fc
, FI_CSIZE
)) {
2251 * copy cached data so we can unlock the mutexes earlier.
2253 bcopy((char *)fc
, (char *)fin
, FI_COPYSIZE
);
2254 RWLOCK_EXIT(&ipf_frcache
);
2255 ATOMIC_INCL(frstats
[out
].fr_chit
);
2257 if ((fr
= fin
->fin_fr
) != NULL
) {
2258 ATOMIC_INC64(fr
->fr_hits
);
2259 pass
= fr
->fr_flags
;
2262 RWLOCK_EXIT(&ipf_frcache
);
2265 if (fin
->fin_v
== 6)
2266 fin
->fin_fr
= ipfilter6
[out
][fr_active
];
2269 fin
->fin_fr
= ipfilter
[out
][fr_active
];
2270 if (fin
->fin_fr
!= NULL
)
2271 pass
= fr_scanlist(fin
, fr_pass
);
2273 if (((pass
& FR_KEEPSTATE
) == 0) &&
2274 ((fin
->fin_flx
& FI_DONTCACHE
) == 0)) {
2275 WRITE_ENTER(&ipf_frcache
);
2276 bcopy((char *)fin
, (char *)fc
, FI_COPYSIZE
);
2277 RWLOCK_EXIT(&ipf_frcache
);
2279 if ((pass
& FR_NOMATCH
)) {
2280 ATOMIC_INCL(frstats
[out
].fr_nom
);
2286 * Apply packets per second rate-limiting to a rule as required.
2288 if ((fr
!= NULL
) && (fr
->fr_pps
!= 0) &&
2289 !ppsratecheck(&fr
->fr_lastpkt
, &fr
->fr_curpps
, fr
->fr_pps
)) {
2290 pass
&= ~(FR_CMDMASK
|FR_DUP
|FR_RETICMP
|FR_RETRST
);
2292 ATOMIC_INCL(frstats
[out
].fr_ppshit
);
2296 * If we fail to add a packet to the authorization queue, then we
2297 * drop the packet later. However, if it was added then pretend
2298 * we've dropped it already.
2300 if (FR_ISAUTH(pass
)) {
2301 if (fr_newauth(fin
->fin_m
, fin
) != 0) {
2303 fin
->fin_m
= *fin
->fin_mp
= NULL
;
2309 fin
->fin_error
= ENOSPC
;
2312 if ((fr
!= NULL
) && (fr
->fr_func
!= NULL
) &&
2313 (fr
->fr_func
!= (ipfunc_t
)-1) && !(pass
& FR_CALLNOW
))
2314 (void) (*fr
->fr_func
)(fin
, &pass
);
2317 * If a rule is a pre-auth rule, check again in the list of rules
2318 * loaded for authenticated use. It does not particulary matter
2319 * if this search fails because a "preauth" result, from a rule,
2320 * is treated as "not a pass", hence the packet is blocked.
2322 if (FR_ISPREAUTH(pass
)) {
2323 if ((fin
->fin_fr
= ipauth
) != NULL
)
2324 pass
= fr_scanlist(fin
, fr_pass
);
2328 * If the rule has "keep frag" and the packet is actually a fragment,
2329 * then create a fragment state entry.
2331 if ((pass
& (FR_KEEPFRAG
|FR_KEEPSTATE
)) == FR_KEEPFRAG
) {
2332 if (fin
->fin_flx
& FI_FRAG
) {
2333 if (fr_newfrag(fin
, pass
) == -1) {
2334 ATOMIC_INCL(frstats
[out
].fr_bnfr
);
2336 ATOMIC_INCL(frstats
[out
].fr_nfr
);
2339 ATOMIC_INCL(frstats
[out
].fr_cfr
);
2352 /* ------------------------------------------------------------------------ */
2353 /* Function: fr_check */
2354 /* Returns: int - 0 == packet allowed through, */
2356 /* -1 == packet blocked */
2357 /* 1 == packet not matched */
2358 /* -2 == requires authentication */
2360 /* > 0 == filter error # for packet */
2361 /* Parameters: ip(I) - pointer to start of IPv4/6 packet */
2362 /* hlen(I) - length of header */
2363 /* ifp(I) - pointer to interface this packet is on */
2364 /* out(I) - 0 == packet going in, 1 == packet going out */
2365 /* mp(IO) - pointer to caller's buffer pointer that holds this */
2367 /* Solaris & HP-UX ONLY : */
2368 /* qpi(I) - pointer to STREAMS queue information for this */
2369 /* interface & direction. */
2371 /* fr_check() is the master function for all IPFilter packet processing. */
2372 /* It orchestrates: Network Address Translation (NAT), checking for packet */
2373 /* authorisation (or pre-authorisation), presence of related state info., */
2374 /* generating log entries, IP packet accounting, routing of packets as */
2375 /* directed by firewall rules and of course whether or not to allow the */
2376 /* packet to be further processed by the kernel. */
2378 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */
2379 /* freed. Packets passed may be returned with the pointer pointed to by */
2380 /* by "mp" changed to a new buffer. */
2381 /* ------------------------------------------------------------------------ */
2382 int fr_check(ip
, hlen
, ifp
, out
2383 #if defined(_KERNEL) && defined(MENTAT)
2396 * The above really sucks, but short of writing a diff
2399 fr_info_t
*fin
= &frinfo
;
2400 u_32_t pass
= fr_pass
;
2401 frentry_t
*fr
= NULL
;
2406 * The first part of fr_check() deals with making sure that what goes
2407 * into the filtering engine makes some sense. Information about the
2408 * the packet is distilled, collected into a fr_info_t structure and
2409 * the an attempt to ensure the buffer the packet is in is big enough
2410 * to hold all the required packet headers.
2414 qpktinfo_t
*qpi
= qif
;
2416 # if !defined(_INET_IP_STACK_H)
2417 if ((u_int
)ip
& 0x3)
2424 if (fr_running
<= 0) {
2428 bzero((char *)fin
, sizeof(*fin
));
2431 if (qpi
->qpi_flags
& QF_GROUP
)
2432 fin
->fin_flx
|= FI_MBCAST
;
2440 # if defined(M_MCAST)
2441 if ((m
->m_flags
& M_MCAST
) != 0)
2442 fin
->fin_flx
|= FI_MBCAST
|FI_MULTICAST
;
2444 # if defined(M_MLOOP)
2445 if ((m
->m_flags
& M_MLOOP
) != 0)
2446 fin
->fin_flx
|= FI_MBCAST
|FI_MULTICAST
;
2448 # if defined(M_BCAST)
2449 if ((m
->m_flags
& M_BCAST
) != 0)
2450 fin
->fin_flx
|= FI_MBCAST
|FI_BROADCAST
;
2452 # ifdef M_CANFASTFWD
2454 * XXX For now, IP Filter and fast-forwarding of cached flows
2455 * XXX are mutually exclusive. Eventually, IP Filter should
2456 * XXX get a "can-fast-forward" filter rule.
2458 m
->m_flags
&= ~M_CANFASTFWD
;
2459 # endif /* M_CANFASTFWD */
2460 # ifdef CSUM_DELAY_DATA
2462 * disable delayed checksums.
2464 if (m
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) {
2465 in_delayed_cksum(m
);
2466 m
->m_pkthdr
.csum_flags
&= ~CSUM_DELAY_DATA
;
2468 # endif /* CSUM_DELAY_DATA */
2469 # endif /* MENTAT */
2471 bzero((char *)fin
, sizeof(*fin
));
2473 #endif /* _KERNEL */
2481 fin
->fin_error
= ENETUNREACH
;
2482 fin
->fin_hlen
= (u_short
)hlen
;
2483 fin
->fin_dp
= (char *)ip
+ hlen
;
2485 fin
->fin_ipoff
= (char *)ip
- MTOD(m
, char *);
2491 ATOMIC_INCL(frstats
[out
].fr_ipv6
);
2493 * Jumbo grams are quite likely too big for internal buffer
2494 * structures to handle comfortably, for now, so just drop
2497 if (((ip6_t
*)ip
)->ip6_plen
== 0) {
2498 pass
= FR_BLOCK
|FR_NOMATCH
;
2504 #if (defined(OpenBSD) && (OpenBSD >= 200311)) && defined(_KERNEL)
2505 ip
->ip_len
= ntohs(ip
->ip_len
);
2506 ip
->ip_off
= ntohs(ip
->ip_off
);
2510 if (fr_makefrip(hlen
, ip
, fin
) == -1) {
2511 pass
= FR_BLOCK
|FR_NOMATCH
;
2516 * For at least IPv6 packets, if a m_pullup() fails then this pointer
2517 * becomes NULL and so we have no packet to free.
2519 if (*fin
->fin_mp
== NULL
)
2525 if (fr_chksrc
&& !fr_verifysrc(fin
)) {
2526 ATOMIC_INCL(frstats
[0].fr_badsrc
);
2527 fin
->fin_flx
|= FI_BADSRC
;
2530 if (fin
->fin_ip
->ip_ttl
< fr_minttl
) {
2531 ATOMIC_INCL(frstats
[0].fr_badttl
);
2532 fin
->fin_flx
|= FI_LOWTTL
;
2537 if (((ip6_t
*)ip
)->ip6_hlim
< fr_minttl
) {
2538 ATOMIC_INCL(frstats
[0].fr_badttl
);
2539 fin
->fin_flx
|= FI_LOWTTL
;
2545 if (fin
->fin_flx
& FI_SHORT
) {
2546 ATOMIC_INCL(frstats
[out
].fr_short
);
2549 READ_ENTER(&ipf_mutex
);
2552 if (fr_checknatin(fin
, &pass
) == -1) {
2558 * Check auth now. This, combined with the check below to see if apass
2559 * is 0 is to ensure that we don't count the packet twice, which can
2560 * otherwise occur when we reprocess it. As it is, we only count it
2561 * after it has no auth. table matchup.
2563 * If a packet is found in the auth table, then skip checking
2564 * the access lists for permission but we do need to consider
2565 * the result as if it were from the ACL's. In addition, being
2566 * found in the auth table means it has been seen before, so do
2567 * not pass it through accounting (again), lest it be counted twice.
2569 fr
= fr_checkauth(fin
, &pass
);
2570 if (!out
&& (fr
== NULL
))
2571 (void) fr_acctpkt(fin
, NULL
);
2574 if ((fin
->fin_flx
& (FI_FRAG
|FI_BAD
)) == FI_FRAG
) {
2575 fr
= fr_knownfrag(fin
, &pass
);
2577 * Reset the keep state flag here so that we don't
2578 * try and add a new state entry because of it, leading
2579 * to a blocked packet because the add will fail.
2582 pass
&= ~FR_KEEPSTATE
;
2585 fr
= fr_checkstate(fin
, &pass
);
2588 if ((pass
& FR_NOMATCH
) || (fr
== NULL
))
2589 fr
= fr_firewall(fin
, &pass
);
2592 * If we've asked to track state for this packet, set it up.
2593 * Here rather than fr_firewall because fr_checkauth may decide
2594 * to return a packet for "keep state"
2596 if ((pass
& FR_KEEPSTATE
) && (fin
->fin_m
!= NULL
) &&
2597 !(fin
->fin_flx
& FI_STATE
)) {
2598 if (fr_addstate(fin
, NULL
, 0) != NULL
) {
2599 ATOMIC_INCL(frstats
[out
].fr_ads
);
2601 ATOMIC_INCL(frstats
[out
].fr_bads
);
2602 if (FR_ISPASS(pass
)) {
2603 pass
&= ~FR_CMDMASK
;
2612 * Only count/translate packets which will be passed on, out the
2615 if (out
&& FR_ISPASS(pass
)) {
2616 (void) fr_acctpkt(fin
, NULL
);
2618 if (fr_checknatout(fin
, &pass
) == -1) {
2620 } else if ((fr_update_ipid
!= 0) && (v
== 4)) {
2621 if (fr_updateipid(fin
) == -1) {
2622 ATOMIC_INCL(frstats
[1].fr_ipud
);
2623 pass
&= ~FR_CMDMASK
;
2626 ATOMIC_INCL(frstats
[0].fr_ipud
);
2633 if ((fr_flags
& FF_LOGGING
) || (pass
& FR_LOGMASK
)) {
2634 (void) fr_dolog(fin
, &pass
);
2639 * The FI_STATE flag is cleared here so that calling fr_checkstate
2640 * will work when called from inside of fr_fastroute. Although
2641 * there is a similar flag, FI_NATED, for NAT, it does have the same
2642 * impact on code execution.
2644 fin
->fin_flx
&= ~FI_STATE
;
2646 #if defined(FASTROUTE_RECURSION)
2648 * Up the reference on fr_lock and exit ipf_mutex. fr_fastroute
2649 * only frees up the lock on ipf_global and the generation of a
2650 * packet below could cause a recursive call into IPFilter.
2651 * Hang onto the filter rule just in case someone decides to remove
2652 * or flush it in the meantime.
2655 MUTEX_ENTER(&fr
->fr_lock
);
2657 MUTEX_EXIT(&fr
->fr_lock
);
2660 RWLOCK_EXIT(&ipf_mutex
);
2663 if ((pass
& FR_RETMASK
) != 0) {
2665 * Should we return an ICMP packet to indicate error
2666 * status passing through the packet filter ?
2667 * WARNING: ICMP error packets AND TCP RST packets should
2668 * ONLY be sent in repsonse to incoming packets. Sending them
2669 * in response to outbound packets can result in a panic on
2670 * some operating systems.
2673 if (pass
& FR_RETICMP
) {
2676 if ((pass
& FR_RETMASK
) == FR_FAKEICMP
)
2680 (void) fr_send_icmp_err(ICMP_UNREACH
, fin
, dst
);
2681 ATOMIC_INCL(frstats
[0].fr_ret
);
2682 } else if (((pass
& FR_RETMASK
) == FR_RETRST
) &&
2683 !(fin
->fin_flx
& FI_SHORT
)) {
2684 if (((fin
->fin_flx
& FI_OOW
) != 0) ||
2685 (fr_send_reset(fin
) == 0)) {
2686 ATOMIC_INCL(frstats
[1].fr_ret
);
2691 * When using return-* with auth rules, the auth code
2692 * takes over disposing of this packet.
2694 if (FR_ISAUTH(pass
) && (fin
->fin_m
!= NULL
)) {
2695 fin
->fin_m
= *fin
->fin_mp
= NULL
;
2699 if (pass
& FR_RETRST
)
2700 fin
->fin_error
= ECONNRESET
;
2704 if (FR_ISBLOCK(pass
) && (fin
->fin_flx
& FI_NEWNAT
))
2708 * If we didn't drop off the bottom of the list of rules (and thus
2709 * the 'current' rule fr is not NULL), then we may have some extra
2710 * instructions about what to do with a packet.
2711 * Once we're finished return to our caller, freeing the packet if
2712 * we are dropping it (* BSD ONLY *).
2718 * Generate a duplicated packet first because ipf_fastroute
2719 * can lead to fin_m being free'd... not good.
2721 if ((pass
& FR_DUP
) != 0) {
2722 mc
= M_DUPLICATE(fin
->fin_m
);
2724 (void) fr_fastroute(mc
, &mc
, fin
, &fr
->fr_dif
);
2727 fdp
= &fr
->fr_tifs
[fin
->fin_rev
];
2729 if (!out
&& (pass
& FR_FASTROUTE
)) {
2731 * For fastroute rule, no destioation interface defined
2732 * so pass NULL as the frdest_t parameter
2734 (void) fr_fastroute(fin
->fin_m
, mp
, fin
, NULL
);
2736 } else if ((fdp
->fd_ifp
!= NULL
) &&
2737 (fdp
->fd_ifp
!= (struct ifnet
*)-1)) {
2738 /* this is for to rules: */
2739 (void) fr_fastroute(fin
->fin_m
, mp
, fin
, fdp
);
2743 #if defined(FASTROUTE_RECURSION)
2744 (void) fr_derefrule(&fr
);
2747 #if !defined(FASTROUTE_RECURSION)
2748 RWLOCK_EXIT(&ipf_mutex
);
2752 if (!FR_ISPASS(pass
)) {
2753 ATOMIC_INCL(frstats
[out
].fr_block
);
2759 ATOMIC_INCL(frstats
[out
].fr_pass
);
2760 #if defined(_KERNEL) && defined(__sgi)
2761 if ((fin
->fin_hbuf
!= NULL
) &&
2762 (mtod(fin
->fin_m
, struct ip
*) != fin
->fin_ip
)) {
2763 COPYBACK(fin
->fin_m
, 0, fin
->fin_plen
, fin
->fin_hbuf
);
2771 # if (defined(OpenBSD) && (OpenBSD >= 200311))
2772 if (FR_ISPASS(pass
) && (v
== 4)) {
2774 ip
->ip_len
= ntohs(ip
->ip_len
);
2775 ip
->ip_off
= ntohs(ip
->ip_off
);
2778 return (FR_ISPASS(pass
)) ? 0 : fin
->fin_error
;
2780 FR_VERBOSE(("fin_flx %#x pass %#x ", fin
->fin_flx
, pass
));
2781 if ((pass
& FR_NOMATCH
) != 0)
2784 if ((pass
& FR_RETMASK
) != 0)
2785 switch (pass
& FR_RETMASK
)
2795 switch (pass
& FR_CMDMASK
)
2809 #endif /* _KERNEL */
2814 /* ------------------------------------------------------------------------ */
2815 /* Function: fr_dolog */
2816 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */
2817 /* Parameters: fin(I) - pointer to packet information */
2818 /* passp(IO) - pointer to current/new filter decision (unused) */
2820 /* Checks flags set to see how a packet should be logged, if it is to be */
2821 /* logged. Adjust statistics based on its success or not. */
2822 /* ------------------------------------------------------------------------ */
2823 frentry_t
*fr_dolog(fin
, passp
)
2833 if ((fr_flags
& FF_LOGNOMATCH
) && (pass
& FR_NOMATCH
)) {
2834 pass
|= FF_LOGNOMATCH
;
2835 ATOMIC_INCL(frstats
[out
].fr_npkl
);
2837 } else if (((pass
& FR_LOGMASK
) == FR_LOGP
) ||
2838 (FR_ISPASS(pass
) && (fr_flags
& FF_LOGPASS
))) {
2839 if ((pass
& FR_LOGMASK
) != FR_LOGP
)
2841 ATOMIC_INCL(frstats
[out
].fr_ppkl
);
2843 } else if (((pass
& FR_LOGMASK
) == FR_LOGB
) ||
2844 (FR_ISBLOCK(pass
) && (fr_flags
& FF_LOGBLOCK
))) {
2845 if ((pass
& FR_LOGMASK
) != FR_LOGB
)
2846 pass
|= FF_LOGBLOCK
;
2847 ATOMIC_INCL(frstats
[out
].fr_bpkl
);
2849 if (ipflog(fin
, pass
) == -1) {
2850 ATOMIC_INCL(frstats
[out
].fr_skip
);
2853 * If the "or-block" option has been used then
2854 * block the packet if we failed to log it.
2856 if ((pass
& FR_LOGORBLOCK
) &&
2858 pass
&= ~FR_CMDMASK
;
2867 #endif /* IPFILTER_LOG */
2870 /* ------------------------------------------------------------------------ */
2871 /* Function: ipf_cksum */
2872 /* Returns: u_short - IP header checksum */
2873 /* Parameters: addr(I) - pointer to start of buffer to checksum */
2874 /* len(I) - length of buffer in bytes */
2876 /* Calculate the two's complement 16 bit checksum of the buffer passed. */
2878 /* N.B.: addr should be 16bit aligned. */
2879 /* ------------------------------------------------------------------------ */
2880 u_short
ipf_cksum(addr
, len
)
2886 for (sum
= 0; len
> 1; len
-= 2)
2889 /* mop up an odd byte, if necessary */
2891 sum
+= *(u_char
*)addr
;
2894 * add back carry outs from top 16 bits to low 16 bits
2896 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
2897 sum
+= (sum
>> 16); /* add carry */
2898 return (u_short
)(~sum
);
2902 /* ------------------------------------------------------------------------ */
2903 /* Function: fr_cksum */
2904 /* Returns: u_short - layer 4 checksum */
2905 /* Parameters: m(I ) - pointer to buffer holding packet */
2906 /* ip(I) - pointer to IP header */
2907 /* l4proto(I) - protocol to caclulate checksum for */
2908 /* l4hdr(I) - pointer to layer 4 header */
2909 /* l3len(I) - length of layer 4 data plus layer 3 header */
2911 /* Calculates the TCP checksum for the packet held in "m", using the data */
2912 /* in the IP header "ip" to seed it. */
2914 /* NB: This function assumes we've pullup'd enough for all of the IP header */
2915 /* and the TCP header. We also assume that data blocks aren't allocated in */
2918 /* For IPv6, l3len excludes extension header size. */
2920 /* Expects ip_len to be in host byte order when called. */
2921 /* ------------------------------------------------------------------------ */
2923 u_short
fr_cksum(m
, ip
, l4proto
, l4hdr
, l3len
)
2929 u_short
*sp
, slen
, sumsave
, l4hlen
, *csump
;
2945 * Add up IP Header portion
2948 if (IP_V(ip
) == 4) {
2950 hlen
= IP_HL(ip
) << 2;
2951 slen
= l3len
- hlen
;
2952 sum
= htons((u_short
)l4proto
);
2954 sp
= (u_short
*)&ip
->ip_src
;
2955 sum
+= *sp
++; /* ip_src */
2957 sum
+= *sp
++; /* ip_dst */
2960 } else if (IP_V(ip
) == 6) {
2962 hlen
= sizeof(*ip6
);
2963 slen
= l3len
- hlen
;
2964 sum
= htons((u_short
)l4proto
);
2966 sp
= (u_short
*)&ip6
->ip6_src
;
2967 sum
+= *sp
++; /* ip6_src */
2975 sum
+= *sp
++; /* ip6_dst */
2989 csump
= &((udphdr_t
*)l4hdr
)->uh_sum
;
2990 l4hlen
= sizeof(udphdr_t
);
2994 csump
= &((tcphdr_t
*)l4hdr
)->th_sum
;
2995 l4hlen
= sizeof(tcphdr_t
);
2998 csump
= &((icmphdr_t
*)l4hdr
)->icmp_cksum
;
3006 if (csump
!= NULL
) {
3011 l4hlen
= l4hlen
; /* LINT */
3016 void *rp
= m
->b_rptr
;
3018 if ((unsigned char *)ip
> m
->b_rptr
&& (unsigned char *)ip
< m
->b_wptr
)
3019 m
->b_rptr
= (u_char
*)ip
;
3020 sum2
= ip_cksum(m
, hlen
, sum
); /* hlen == offset */
3022 sum2
= (u_short
)(~sum2
& 0xffff);
3025 # if defined(BSD) || defined(sun)
3026 # if defined(BSD) && (BSD >= 199103)
3032 sum2
= in_cksum(m
, slen
);
3040 * Both sum and sum2 are partial sums, so combine them together.
3042 sum
+= ~sum2
& 0xffff;
3043 while (sum
> 0xffff)
3044 sum
= (sum
& 0xffff) + (sum
>> 16);
3045 sum2
= ~sum
& 0xffff;
3046 # else /* defined(BSD) || defined(sun) */
3052 u_short len
= ip
->ip_len
;
3058 * Add up IP Header portion
3060 if (sp
!= (u_short
*)l4hdr
)
3061 sp
= (u_short
*)l4hdr
;
3066 sum
+= *sp
++; /* sport */
3067 sum
+= *sp
++; /* dport */
3068 sum
+= *sp
++; /* udp length */
3069 sum
+= *sp
++; /* checksum */
3073 sum
+= *sp
++; /* sport */
3074 sum
+= *sp
++; /* dport */
3075 sum
+= *sp
++; /* seq */
3077 sum
+= *sp
++; /* ack */
3079 sum
+= *sp
++; /* off */
3080 sum
+= *sp
++; /* win */
3081 sum
+= *sp
++; /* checksum */
3082 sum
+= *sp
++; /* urp */
3085 sum
= *sp
++; /* type/code */
3086 sum
+= *sp
++; /* checksum */
3092 * In case we had to copy the IP & TCP header out of mbufs,
3093 * skip over the mbuf bits which are the header
3095 if ((void *)ip
!= mtod(m
, void *)) {
3096 hlen
= (void *)sp
- (void *)ip
;
3098 add
= MIN(hlen
, m
->m_len
);
3099 sp
= (u_short
*)(mtod(m
, void *) + add
);
3101 if (add
== m
->m_len
) {
3106 sp
= mtod(m
, u_short
*);
3108 PANIC((!m
),("fr_cksum(1): not enough data"));
3114 len
-= (l4hlen
+ hlen
);
3119 if (((void *)sp
- mtod(m
, void *)) >= m
->m_len
) {
3121 PANIC((!m
),("fr_cksum(2): not enough data"));
3122 sp
= mtod(m
, u_short
*);
3124 if (((void *)(sp
+ 1) - mtod(m
, void *)) > m
->m_len
) {
3125 bytes
.c
[0] = *(u_char
*)sp
;
3127 PANIC((!m
),("fr_cksum(3): not enough data"));
3128 sp
= mtod(m
, u_short
*);
3129 bytes
.c
[1] = *(u_char
*)sp
;
3131 sp
= (u_short
*)((u_char
*)sp
+ 1);
3133 if ((u_long
)sp
& 1) {
3134 bcopy((char *)sp
++, (char *)&bytes
.s
, sizeof(bytes
.s
));
3142 sum
+= ntohs(*(u_char
*)sp
<< 8);
3144 while (sum
> 0xffff)
3145 sum
= (sum
& 0xffff) + (sum
>> 16);
3146 sum2
= (u_short
)(~sum
& 0xffff);
3148 # endif /* defined(BSD) || defined(sun) */
3149 # endif /* MENTAT */
3152 * Add up IP Header portion
3154 if (sp
!= (u_short
*)l4hdr
)
3155 sp
= (u_short
*)l4hdr
;
3157 for (; slen
> 1; slen
-= 2)
3160 sum
+= ntohs(*(u_char
*)sp
<< 8);
3161 while (sum
> 0xffff)
3162 sum
= (sum
& 0xffff) + (sum
>> 16);
3163 sum2
= (u_short
)(~sum
& 0xffff);
3164 #endif /* _KERNEL */
3172 #if defined(_KERNEL) && ( ((defined(BSD) && (BSD < 199103)) && \
3173 !defined(MENTAT)) || defined(__sgi) ) && \
3174 !defined(linux) && !defined(_AIX51)
3176 * Copyright (c) 1982, 1986, 1988, 1991, 1993
3177 * The Regents of the University of California. All rights reserved.
3179 * Redistribution and use in source and binary forms, with or without
3180 * modification, are permitted provided that the following conditions
3182 * 1. Redistributions of source code must retain the above copyright
3183 * notice, this list of conditions and the following disclaimer.
3184 * 2. Redistributions in binary form must reproduce the above copyright
3185 * notice, this list of conditions and the following disclaimer in the
3186 * documentation and/or other materials provided with the distribution.
3187 * 3. Neither the name of the University nor the names of its contributors
3188 * may be used to endorse or promote products derived from this software
3189 * without specific prior written permission.
3191 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3192 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3193 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3194 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3195 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3196 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3197 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3198 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3199 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3200 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3203 * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
3204 * Id: fil.c,v 2.243.2.147 2009/07/21 22:25:28 darrenr Exp
3207 * Copy data from an mbuf chain starting "off" bytes from the beginning,
3208 * continuing for "len" bytes, into the indicated buffer.
3211 m_copydata(m
, off
, len
, cp
)
3219 if (off
< 0 || len
< 0)
3220 panic("m_copydata");
3223 panic("m_copydata");
3231 panic("m_copydata");
3232 count
= MIN(m
->m_len
- off
, len
);
3233 bcopy(mtod(m
, void *) + off
, cp
, count
);
3243 * Copy data from a buffer back into the indicated mbuf chain,
3244 * starting "off" bytes from the beginning, extending the mbuf
3245 * chain if necessary.
3248 m_copyback(m0
, off
, len
, cp
)
3255 struct mbuf
*m
= m0
, *n
;
3260 while (off
> (mlen
= m
->m_len
)) {
3263 if (m
->m_next
== 0) {
3264 n
= m_getclr(M_DONTWAIT
, m
->m_type
);
3267 n
->m_len
= min(MLEN
, len
+ off
);
3273 mlen
= min(m
->m_len
- off
, len
);
3274 bcopy(cp
, off
+ mtod(m
, void *), (unsigned)mlen
);
3282 if (m
->m_next
== 0) {
3283 n
= m_get(M_DONTWAIT
, m
->m_type
);
3286 n
->m_len
= min(MLEN
, len
);
3293 if (((m
= m0
)->m_flags
& M_PKTHDR
) && (m
->m_pkthdr
.len
< totlen
))
3294 m
->m_pkthdr
.len
= totlen
;
3298 #endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */
3301 /* ------------------------------------------------------------------------ */
3302 /* Function: fr_findgroup */
3303 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */
3304 /* Parameters: group(I) - group name to search for */
3305 /* unit(I) - device to which this group belongs */
3306 /* set(I) - which set of rules (inactive/inactive) this is */
3307 /* fgpp(O) - pointer to place to store pointer to the pointer */
3308 /* to where to add the next (last) group or where */
3309 /* to delete group from. */
3311 /* Search amongst the defined groups for a particular group number. */
3312 /* ------------------------------------------------------------------------ */
3313 frgroup_t
*fr_findgroup(group
, unit
, set
, fgpp
)
3319 frgroup_t
*fg
, **fgp
;
3322 * Which list of groups to search in is dependent on which list of
3323 * rules are being operated on.
3325 fgp
= &ipfgroups
[unit
][set
];
3327 while ((fg
= *fgp
) != NULL
) {
3328 if (strncmp(group
, fg
->fg_name
, FR_GROUPLEN
) == 0)
3339 /* ------------------------------------------------------------------------ */
3340 /* Function: fr_addgroup */
3341 /* Returns: frgroup_t * - NULL == did not create group, */
3342 /* != NULL == pointer to the group */
3343 /* Parameters: num(I) - group number to add */
3344 /* head(I) - rule pointer that is using this as the head */
3345 /* flags(I) - rule flags which describe the type of rule it is */
3346 /* unit(I) - device to which this group will belong to */
3347 /* set(I) - which set of rules (inactive/inactive) this is */
3348 /* Write Locks: ipf_mutex */
3350 /* Add a new group head, or if it already exists, increase the reference */
3352 /* ------------------------------------------------------------------------ */
3353 frgroup_t
*fr_addgroup(group
, head
, flags
, unit
, set
)
3360 frgroup_t
*fg
, **fgp
;
3366 if (unit
== IPL_LOGIPF
&& *group
== '\0')
3370 gflags
= flags
& FR_INOUT
;
3372 fg
= fr_findgroup(group
, unit
, set
, &fgp
);
3374 if (fg
->fg_flags
== 0)
3375 fg
->fg_flags
= gflags
;
3376 else if (gflags
!= fg
->fg_flags
)
3381 KMALLOC(fg
, frgroup_t
*);
3384 fg
->fg_start
= NULL
;
3386 bcopy(group
, fg
->fg_name
, FR_GROUPLEN
);
3387 fg
->fg_flags
= gflags
;
3395 /* ------------------------------------------------------------------------ */
3396 /* Function: fr_delgroup */
3398 /* Parameters: group(I) - group name to delete */
3399 /* unit(I) - device to which this group belongs */
3400 /* set(I) - which set of rules (inactive/inactive) this is */
3401 /* Write Locks: ipf_mutex */
3403 /* Attempt to delete a group head. */
3404 /* Only do this when its reference count reaches 0. */
3405 /* ------------------------------------------------------------------------ */
3406 void fr_delgroup(group
, unit
, set
)
3411 frgroup_t
*fg
, **fgp
;
3413 fg
= fr_findgroup(group
, unit
, set
, &fgp
);
3418 if (fg
->fg_ref
== 0) {
3425 /* ------------------------------------------------------------------------ */
3426 /* Function: fr_getrulen */
3427 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */
3428 /* Parameters: unit(I) - device for which to count the rule's number */
3429 /* flags(I) - which set of rules to find the rule in */
3430 /* group(I) - group name */
3431 /* n(I) - rule number to find */
3433 /* Find rule # n in group # g and return a pointer to it. Return NULl if */
3434 /* group # g doesn't exist or there are less than n rules in the group. */
3435 /* ------------------------------------------------------------------------ */
3436 frentry_t
*fr_getrulen(unit
, group
, n
)
3444 fg
= fr_findgroup(group
, unit
, fr_active
, NULL
);
3447 for (fr
= fg
->fg_start
; fr
&& n
; fr
= fr
->fr_next
, n
--)
3455 /* ------------------------------------------------------------------------ */
3456 /* Function: frflushlist */
3457 /* Returns: int - >= 0 - number of flushed rules */
3458 /* Parameters: set(I) - which set of rules (inactive/inactive) this is */
3459 /* unit(I) - device for which to flush rules */
3460 /* flags(I) - which set of rules to flush */
3461 /* nfreedp(O) - pointer to int where flush count is stored */
3462 /* listp(I) - pointer to list to flush pointer */
3463 /* Write Locks: ipf_mutex */
3465 /* Recursively flush rules from the list, descending groups as they are */
3466 /* encountered. if a rule is the head of a group and it has lost all its */
3467 /* group members, then also delete the group reference. nfreedp is needed */
3468 /* to store the accumulating count of rules removed, whereas the returned */
3469 /* value is just the number removed from the current list. The latter is */
3470 /* needed to correctly adjust reference counts on rules that define groups. */
3472 /* NOTE: Rules not loaded from user space cannot be flushed. */
3473 /* ------------------------------------------------------------------------ */
3474 static int frflushlist(set
, unit
, nfreedp
, listp
)
3483 while ((fp
= *listp
) != NULL
) {
3484 if ((fp
->fr_type
& FR_T_BUILTIN
) ||
3485 !(fp
->fr_flags
& FR_COPIED
)) {
3486 listp
= &fp
->fr_next
;
3489 *listp
= fp
->fr_next
;
3490 if (fp
->fr_grp
!= NULL
) {
3491 (void) frflushlist(set
, unit
, nfreedp
, fp
->fr_grp
);
3494 if (fp
->fr_grhead
!= NULL
) {
3495 fr_delgroup(fp
->fr_grhead
, unit
, set
);
3496 *fp
->fr_grhead
= '\0';
3499 ASSERT(fp
->fr_ref
> 0);
3501 if (fr_derefrule(&fp
) == 0)
3509 /* ------------------------------------------------------------------------ */
3510 /* Function: frflush */
3511 /* Returns: int - >= 0 - number of flushed rules */
3512 /* Parameters: unit(I) - device for which to flush rules */
3513 /* flags(I) - which set of rules to flush */
3515 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
3516 /* and IPv6) as defined by the value of flags. */
3517 /* ------------------------------------------------------------------------ */
3518 int frflush(unit
, proto
, flags
)
3522 int flushed
= 0, set
;
3524 WRITE_ENTER(&ipf_mutex
);
3525 bzero((char *)frcache
, sizeof(frcache
));
3528 if ((flags
& FR_INACTIVE
) == FR_INACTIVE
)
3531 if (flags
& FR_OUTQUE
) {
3532 if (proto
== 0 || proto
== 6) {
3533 (void) frflushlist(set
, unit
,
3534 &flushed
, &ipfilter6
[1][set
]);
3535 (void) frflushlist(set
, unit
,
3536 &flushed
, &ipacct6
[1][set
]);
3538 if (proto
== 0 || proto
== 4) {
3539 (void) frflushlist(set
, unit
,
3540 &flushed
, &ipfilter
[1][set
]);
3541 (void) frflushlist(set
, unit
,
3542 &flushed
, &ipacct
[1][set
]);
3545 if (flags
& FR_INQUE
) {
3546 if (proto
== 0 || proto
== 6) {
3547 (void) frflushlist(set
, unit
,
3548 &flushed
, &ipfilter6
[0][set
]);
3549 (void) frflushlist(set
, unit
,
3550 &flushed
, &ipacct6
[0][set
]);
3552 if (proto
== 0 || proto
== 4) {
3553 (void) frflushlist(set
, unit
,
3554 &flushed
, &ipfilter
[0][set
]);
3555 (void) frflushlist(set
, unit
,
3556 &flushed
, &ipacct
[0][set
]);
3559 RWLOCK_EXIT(&ipf_mutex
);
3561 if (unit
== IPL_LOGIPF
) {
3564 tmp
= frflush(IPL_LOGCOUNT
, proto
, flags
);
3572 /* ------------------------------------------------------------------------ */
3573 /* Function: memstr */
3574 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */
3575 /* Parameters: src(I) - pointer to byte sequence to match */
3576 /* dst(I) - pointer to byte sequence to search */
3577 /* slen(I) - match length */
3578 /* dlen(I) - length available to search in */
3580 /* Search dst for a sequence of bytes matching those at src and extend for */
3582 /* ------------------------------------------------------------------------ */
3583 char *memstr(src
, dst
, slen
, dlen
)
3590 while (dlen
>= slen
) {
3591 if (memcmp(src
, dst
, slen
) == 0) {
3600 /* ------------------------------------------------------------------------ */
3601 /* Function: fr_fixskip */
3603 /* Parameters: listp(IO) - pointer to start of list with skip rule */
3604 /* rp(I) - rule added/removed with skip in it. */
3605 /* addremove(I) - adjustment (-1/+1) to make to skip count, */
3606 /* depending on whether a rule was just added */
3609 /* Adjust all the rules in a list which would have skip'd past the position */
3610 /* where we are inserting to skip to the right place given the change. */
3611 /* ------------------------------------------------------------------------ */
3612 void fr_fixskip(listp
, rp
, addremove
)
3613 frentry_t
**listp
, *rp
;
3620 for (fp
= *listp
; (fp
!= NULL
) && (fp
!= rp
); fp
= fp
->fr_next
)
3626 for (rn
= 0, fp
= *listp
; fp
&& (fp
!= rp
); fp
= fp
->fr_next
, rn
++)
3627 if (FR_ISSKIP(fp
->fr_flags
) && (rn
+ fp
->fr_arg
>= rules
))
3628 fp
->fr_arg
+= addremove
;
3633 /* ------------------------------------------------------------------------ */
3634 /* Function: count4bits */
3635 /* Returns: int - >= 0 - number of consecutive bits in input */
3636 /* Parameters: ip(I) - 32bit IP address */
3639 /* count consecutive 1's in bit mask. If the mask generated by counting */
3640 /* consecutive 1's is different to that passed, return -1, else return # */
3642 /* ------------------------------------------------------------------------ */
3649 ip
= ipn
= ntohl(ip
);
3650 for (i
= 32; i
; i
--, ipn
*= 2)
3651 if (ipn
& 0x80000000)
3656 for (i
= 32, j
= cnt
; i
; i
--, j
--) {
3668 /* ------------------------------------------------------------------------ */
3669 /* Function: count6bits */
3670 /* Returns: int - >= 0 - number of consecutive bits in input */
3671 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */
3674 /* count consecutive 1's in bit mask. */
3675 /* ------------------------------------------------------------------------ */
3682 for (k
= 3; k
>= 0; k
--)
3683 if (msk
[k
] == 0xffffffff)
3686 for (j
= msk
[k
]; j
; j
<<= 1)
3693 #endif /* _KERNEL */
3696 /* ------------------------------------------------------------------------ */
3697 /* Function: frsynclist */
3699 /* Parameters: fr(I) - start of filter list to sync interface names for */
3700 /* ifp(I) - interface pointer for limiting sync lookups */
3701 /* Write Locks: ipf_mutex */
3703 /* Walk through a list of filter rules and resolve any interface names into */
3704 /* pointers. Where dynamic addresses are used, also update the IP address */
3705 /* used in the rule. The interface pointer is used to limit the lookups to */
3706 /* a specific set of matching names if it is non-NULL. */
3707 /* ------------------------------------------------------------------------ */
3708 static void frsynclist(fr
, ifp
)
3715 for (; fr
; fr
= fr
->fr_next
) {
3719 * Lookup all the interface names that are part of the rule.
3721 for (i
= 0; i
< 4; i
++) {
3722 if ((ifp
!= NULL
) && (fr
->fr_ifas
[i
] != ifp
))
3724 fr
->fr_ifas
[i
] = fr_resolvenic(fr
->fr_ifnames
[i
], v
);
3727 if (fr
->fr_type
== FR_T_IPF
) {
3728 if (fr
->fr_satype
!= FRI_NORMAL
&&
3729 fr
->fr_satype
!= FRI_LOOKUP
) {
3730 (void)fr_ifpaddr(v
, fr
->fr_satype
,
3731 fr
->fr_ifas
[fr
->fr_sifpidx
],
3732 &fr
->fr_src
, &fr
->fr_smsk
);
3734 if (fr
->fr_datype
!= FRI_NORMAL
&&
3735 fr
->fr_datype
!= FRI_LOOKUP
) {
3736 (void)fr_ifpaddr(v
, fr
->fr_datype
,
3737 fr
->fr_ifas
[fr
->fr_difpidx
],
3738 &fr
->fr_dst
, &fr
->fr_dmsk
);
3742 fdp
= &fr
->fr_tifs
[0];
3743 if ((ifp
== NULL
) || (fdp
->fd_ifp
== ifp
))
3744 fr_resolvedest(fdp
, v
);
3746 fdp
= &fr
->fr_tifs
[1];
3747 if ((ifp
== NULL
) || (fdp
->fd_ifp
== ifp
))
3748 fr_resolvedest(fdp
, v
);
3751 if ((ifp
== NULL
) || (fdp
->fd_ifp
== ifp
)) {
3752 fr_resolvedest(fdp
, v
);
3754 fr
->fr_flags
&= ~FR_DUP
;
3755 if ((fdp
->fd_ifp
!= (void *)-1) &&
3756 (fdp
->fd_ifp
!= NULL
))
3757 fr
->fr_flags
|= FR_DUP
;
3760 #ifdef IPFILTER_LOOKUP
3761 if (fr
->fr_type
== FR_T_IPF
&& fr
->fr_satype
== FRI_LOOKUP
&&
3762 fr
->fr_srcptr
== NULL
) {
3763 fr
->fr_srcptr
= fr_resolvelookup(fr
->fr_srctype
,
3768 if (fr
->fr_type
== FR_T_IPF
&& fr
->fr_datype
== FRI_LOOKUP
&&
3769 fr
->fr_dstptr
== NULL
) {
3770 fr
->fr_dstptr
= fr_resolvelookup(fr
->fr_dsttype
,
3781 /* ------------------------------------------------------------------------ */
3782 /* Function: frsync */
3784 /* Parameters: Nil */
3786 /* frsync() is called when we suspect that the interface list or */
3787 /* information about interfaces (like IP#) has changed. Go through all */
3788 /* filter rules, NAT entries and the state table and check if anything */
3789 /* needs to be changed/updated. */
3790 /* ------------------------------------------------------------------------ */
3801 WRITE_ENTER(&ipf_mutex
);
3802 frsynclist(ipacct
[0][fr_active
], ifp
);
3803 frsynclist(ipacct
[1][fr_active
], ifp
);
3804 frsynclist(ipfilter
[0][fr_active
], ifp
);
3805 frsynclist(ipfilter
[1][fr_active
], ifp
);
3806 frsynclist(ipacct6
[0][fr_active
], ifp
);
3807 frsynclist(ipacct6
[1][fr_active
], ifp
);
3808 frsynclist(ipfilter6
[0][fr_active
], ifp
);
3809 frsynclist(ipfilter6
[1][fr_active
], ifp
);
3811 for (i
= 0; i
< IPL_LOGSIZE
; i
++) {
3814 for (g
= ipfgroups
[i
][0]; g
!= NULL
; g
= g
->fg_next
)
3815 frsynclist(g
->fg_start
, ifp
);
3816 for (g
= ipfgroups
[i
][1]; g
!= NULL
; g
= g
->fg_next
)
3817 frsynclist(g
->fg_start
, ifp
);
3819 RWLOCK_EXIT(&ipf_mutex
);
3824 * In the functions below, bcopy() is called because the pointer being
3825 * copied _from_ in this instance is a pointer to a char buf (which could
3826 * end up being unaligned) and on the kernel's local stack.
3828 /* ------------------------------------------------------------------------ */
3829 /* Function: copyinptr */
3830 /* Returns: int - 0 = success, else failure */
3831 /* Parameters: src(I) - pointer to the source address */
3832 /* dst(I) - destination address */
3833 /* size(I) - number of bytes to copy */
3835 /* Copy a block of data in from user space, given a pointer to the pointer */
3836 /* to start copying from (src) and a pointer to where to store it (dst). */
3837 /* NB: src - pointer to user space pointer, dst - kernel space pointer */
3838 /* ------------------------------------------------------------------------ */
3839 int copyinptr(src
, dst
, size
)
3847 error
= COPYIN(src
, &ca
, sizeof(ca
));
3851 bcopy(src
, (void *)&ca
, sizeof(ca
));
3853 error
= COPYIN(ca
, dst
, size
);
3860 /* ------------------------------------------------------------------------ */
3861 /* Function: copyoutptr */
3862 /* Returns: int - 0 = success, else failure */
3863 /* Parameters: src(I) - pointer to the source address */
3864 /* dst(I) - destination address */
3865 /* size(I) - number of bytes to copy */
3867 /* Copy a block of data out to user space, given a pointer to the pointer */
3868 /* to start copying from (src) and a pointer to where to store it (dst). */
3869 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */
3870 /* ------------------------------------------------------------------------ */
3871 int copyoutptr(src
, dst
, size
)
3878 bcopy(dst
, &ca
, sizeof(ca
));
3879 error
= COPYOUT(src
, ca
, size
);
3887 /* ------------------------------------------------------------------------ */
3888 /* Function: fr_lock */
3889 /* Returns: int - 0 = success, else error */
3890 /* Parameters: data(I) - pointer to lock value to set */
3891 /* lockp(O) - pointer to location to store old lock value */
3893 /* Get the new value for the lock integer, set it and return the old value */
3895 /* ------------------------------------------------------------------------ */
3896 int fr_lock(data
, lockp
)
3902 err
= BCOPYIN(data
, &arg
, sizeof(arg
));
3905 err
= BCOPYOUT(lockp
, data
, sizeof(*lockp
));
3913 /* ------------------------------------------------------------------------ */
3914 /* Function: fr_getstat */
3916 /* Parameters: fiop(I) - pointer to ipfilter stats structure */
3918 /* Stores a copy of current pointers, counters, etc, in the friostat */
3920 /* ------------------------------------------------------------------------ */
3921 void fr_getstat(fiop
)
3926 bcopy((char *)frstats
, (char *)fiop
->f_st
, sizeof(filterstats_t
) * 2);
3927 fiop
->f_locks
[IPL_LOGSTATE
] = fr_state_lock
;
3928 fiop
->f_locks
[IPL_LOGNAT
] = fr_nat_lock
;
3929 fiop
->f_locks
[IPL_LOGIPF
] = fr_frag_lock
;
3930 fiop
->f_locks
[IPL_LOGAUTH
] = fr_auth_lock
;
3932 for (i
= 0; i
< 2; i
++)
3933 for (j
= 0; j
< 2; j
++) {
3934 fiop
->f_ipf
[i
][j
] = ipfilter
[i
][j
];
3935 fiop
->f_acct
[i
][j
] = ipacct
[i
][j
];
3936 fiop
->f_ipf6
[i
][j
] = ipfilter6
[i
][j
];
3937 fiop
->f_acct6
[i
][j
] = ipacct6
[i
][j
];
3940 fiop
->f_ticks
= fr_ticks
;
3941 fiop
->f_active
= fr_active
;
3942 fiop
->f_froute
[0] = fr_frouteok
[0];
3943 fiop
->f_froute
[1] = fr_frouteok
[1];
3945 fiop
->f_running
= fr_running
;
3946 for (i
= 0; i
< IPL_LOGSIZE
; i
++) {
3947 fiop
->f_groups
[i
][0] = ipfgroups
[i
][0];
3948 fiop
->f_groups
[i
][1] = ipfgroups
[i
][1];
3951 fiop
->f_logging
= 1;
3953 fiop
->f_logging
= 0;
3955 fiop
->f_defpass
= fr_pass
;
3956 fiop
->f_features
= fr_features
;
3957 (void) strncpy(fiop
->f_version
, ipfilter_version
,
3958 sizeof(fiop
->f_version
));
3963 int icmptoicmp6types
[ICMP_MAXTYPE
+1] = {
3964 ICMP6_ECHO_REPLY
, /* 0: ICMP_ECHOREPLY */
3967 ICMP6_DST_UNREACH
, /* 3: ICMP_UNREACH */
3968 -1, /* 4: ICMP_SOURCEQUENCH */
3969 ND_REDIRECT
, /* 5: ICMP_REDIRECT */
3972 ICMP6_ECHO_REQUEST
, /* 8: ICMP_ECHO */
3974 -1, /* 10: UNUSED */
3975 ICMP6_TIME_EXCEEDED
, /* 11: ICMP_TIMXCEED */
3976 ICMP6_PARAM_PROB
, /* 12: ICMP_PARAMPROB */
3977 -1, /* 13: ICMP_TSTAMP */
3978 -1, /* 14: ICMP_TSTAMPREPLY */
3979 -1, /* 15: ICMP_IREQ */
3980 -1, /* 16: ICMP_IREQREPLY */
3981 -1, /* 17: ICMP_MASKREQ */
3982 -1, /* 18: ICMP_MASKREPLY */
3986 int icmptoicmp6unreach
[ICMP_MAX_UNREACH
] = {
3987 ICMP6_DST_UNREACH_ADDR
, /* 0: ICMP_UNREACH_NET */
3988 ICMP6_DST_UNREACH_ADDR
, /* 1: ICMP_UNREACH_HOST */
3989 -1, /* 2: ICMP_UNREACH_PROTOCOL */
3990 ICMP6_DST_UNREACH_NOPORT
, /* 3: ICMP_UNREACH_PORT */
3991 -1, /* 4: ICMP_UNREACH_NEEDFRAG */
3992 ICMP6_DST_UNREACH_NOTNEIGHBOR
, /* 5: ICMP_UNREACH_SRCFAIL */
3993 ICMP6_DST_UNREACH_ADDR
, /* 6: ICMP_UNREACH_NET_UNKNOWN */
3994 ICMP6_DST_UNREACH_ADDR
, /* 7: ICMP_UNREACH_HOST_UNKNOWN */
3995 -1, /* 8: ICMP_UNREACH_ISOLATED */
3996 ICMP6_DST_UNREACH_ADMIN
, /* 9: ICMP_UNREACH_NET_PROHIB */
3997 ICMP6_DST_UNREACH_ADMIN
, /* 10: ICMP_UNREACH_HOST_PROHIB */
3998 -1, /* 11: ICMP_UNREACH_TOSNET */
3999 -1, /* 12: ICMP_UNREACH_TOSHOST */
4000 ICMP6_DST_UNREACH_ADMIN
, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
4002 int icmpreplytype6
[ICMP6_MAXTYPE
+ 1];
4005 int icmpreplytype4
[ICMP_MAXTYPE
+ 1];
4008 /* ------------------------------------------------------------------------ */
4009 /* Function: fr_matchicmpqueryreply */
4010 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */
4011 /* Parameters: v(I) - IP protocol version (4 or 6) */
4012 /* ic(I) - ICMP information */
4013 /* icmp(I) - ICMP packet header */
4014 /* rev(I) - direction (0 = forward/1 = reverse) of packet */
4016 /* Check if the ICMP packet defined by the header pointed to by icmp is a */
4017 /* reply to one as described by what's in ic. If it is a match, return 1, */
4018 /* else return 0 for no match. */
4019 /* ------------------------------------------------------------------------ */
4020 int fr_matchicmpqueryreply(v
, ic
, icmp
, rev
)
4028 ictype
= ic
->ici_type
;
4032 * If we matched its type on the way in, then when going out
4033 * it will still be the same type.
4035 if ((!rev
&& (icmp
->icmp_type
== ictype
)) ||
4036 (rev
&& (icmpreplytype4
[ictype
] == icmp
->icmp_type
))) {
4037 if (icmp
->icmp_type
!= ICMP_ECHOREPLY
)
4039 if (icmp
->icmp_id
== ic
->ici_id
)
4045 if ((!rev
&& (icmp
->icmp_type
== ictype
)) ||
4046 (rev
&& (icmpreplytype6
[ictype
] == icmp
->icmp_type
))) {
4047 if (icmp
->icmp_type
!= ICMP6_ECHO_REPLY
)
4049 if (icmp
->icmp_id
== ic
->ici_id
)
4058 #ifdef IPFILTER_LOOKUP
4059 /* ------------------------------------------------------------------------ */
4060 /* Function: fr_resolvelookup */
4061 /* Returns: void * - NULL = failure, else success. */
4062 /* Parameters: type(I) - type of lookup these parameters are for. */
4063 /* subtype(I) - whether the info below contains number/name */
4064 /* info(I) - pointer to name/number of the lookup data */
4065 /* funcptr(IO) - pointer to pointer for storing IP address */
4066 /* searching function. */
4068 /* Search for the "table" number passed in amongst those configured for */
4069 /* that particular type. If the type is recognised then the function to */
4070 /* call to do the IP address search will be change, regardless of whether */
4071 /* or not the "table" number exists. */
4072 /* ------------------------------------------------------------------------ */
4073 static void *fr_resolvelookup(type
, subtype
, info
, funcptr
)
4074 u_int type
, subtype
;
4076 lookupfunc_t
*funcptr
;
4078 char label
[FR_GROUPLEN
], *name
;
4084 #if defined(SNPRINTF) && defined(_KERNEL)
4085 SNPRINTF(label
, sizeof(label
), "%u", info
->iplookupnum
);
4087 (void) sprintf(label
, "%u", info
->iplookupnum
);
4090 } else if (subtype
== 1) {
4092 * Because iplookupname is currently only a 12 character
4093 * string and FR_GROUPLEN is 16, copy all of it into the
4094 * label buffer and add on a NULL at the end.
4096 strncpy(label
, info
->iplookupname
, sizeof(info
->iplookupname
));
4097 label
[sizeof(info
->iplookupname
)] = '\0';
4103 READ_ENTER(&ip_poolrw
);
4108 # if (defined(__osf__) && defined(_KERNEL))
4112 ipo
= ip_pool_find(IPL_LOGIPF
, name
);
4115 ATOMIC_INC32(ipo
->ipo_ref
);
4117 *funcptr
= ip_pool_search
;
4121 iph
= fr_findhtable(IPL_LOGIPF
, name
);
4124 ATOMIC_INC32(iph
->iph_ref
);
4126 *funcptr
= fr_iphmfindip
;
4133 RWLOCK_EXIT(&ip_poolrw
);
4140 /* ------------------------------------------------------------------------ */
4141 /* Function: frrequest */
4142 /* Returns: int - 0 == success, > 0 == errno value */
4143 /* Parameters: unit(I) - device for which this is for */
4144 /* req(I) - ioctl command (SIOC*) */
4145 /* data(I) - pointr to ioctl data */
4146 /* set(I) - 1 or 0 (filter set) */
4147 /* makecopy(I) - flag indicating whether data points to a rule */
4148 /* in kernel space & hence doesn't need copying. */
4150 /* This function handles all the requests which operate on the list of */
4151 /* filter rules. This includes adding, deleting, insertion. It is also */
4152 /* responsible for creating groups when a "head" rule is loaded. Interface */
4153 /* names are resolved here and other sanity checks are made on the content */
4154 /* of the rule structure being loaded. If a rule has user defined timeouts */
4155 /* then make sure they are created and initialised before exiting. */
4156 /* ------------------------------------------------------------------------ */
4157 int frrequest(unit
, req
, data
, set
, makecopy
)
4163 frentry_t frd
, *fp
, *f
, **fprev
, **ftail
;
4164 int error
= 0, in
, v
;
4172 if (makecopy
!= 0) {
4173 error
= fr_inobj(data
, fp
, IPFOBJ_FRENTRY
);
4176 if ((fp
->fr_flags
& FR_T_BUILTIN
) != 0)
4179 fp
->fr_flags
|= FR_COPIED
;
4181 fp
= (frentry_t
*)data
;
4182 if ((fp
->fr_type
& FR_T_BUILTIN
) == 0)
4184 fp
->fr_flags
&= ~FR_COPIED
;
4187 if (((fp
->fr_dsize
== 0) && (fp
->fr_data
!= NULL
)) ||
4188 ((fp
->fr_dsize
!= 0) && (fp
->fr_data
== NULL
)))
4195 * Only filter rules for IPv4 or IPv6 are accepted.
4208 * If the rule is being loaded from user space, i.e. we had to copy it
4209 * into kernel space, then do not trust the function pointer in the
4212 if ((makecopy
== 1) && (fp
->fr_func
!= NULL
)) {
4213 if (fr_findfunc(fp
->fr_func
) == NULL
)
4215 error
= fr_funcinit(fp
);
4222 * Check that the group number does exist and that its use (in/out)
4223 * matches what the rule is.
4225 if (!strncmp(fp
->fr_grhead
, "0", FR_GROUPLEN
))
4226 *fp
->fr_grhead
= '\0';
4227 group
= fp
->fr_group
;
4228 if (!strncmp(group
, "0", FR_GROUPLEN
))
4231 if (FR_ISACCOUNT(fp
->fr_flags
))
4232 unit
= IPL_LOGCOUNT
;
4234 if ((req
!= (int)SIOCZRLST
) && (*group
!= '\0')) {
4235 fg
= fr_findgroup(group
, unit
, set
, NULL
);
4238 if (fg
->fg_flags
== 0)
4239 fg
->fg_flags
= fp
->fr_flags
& FR_INOUT
;
4240 else if (fg
->fg_flags
!= (fp
->fr_flags
& FR_INOUT
))
4244 in
= (fp
->fr_flags
& FR_INQUE
) ? 0 : 1;
4247 * Work out which rule list this change is being applied to.
4251 if (unit
== IPL_LOGAUTH
)
4254 if (FR_ISACCOUNT(fp
->fr_flags
))
4255 fprev
= &ipacct
[in
][set
];
4256 else if ((fp
->fr_flags
& (FR_OUTQUE
|FR_INQUE
)) != 0)
4257 fprev
= &ipfilter
[in
][set
];
4258 } else if (v
== 6) {
4259 if (FR_ISACCOUNT(fp
->fr_flags
))
4260 fprev
= &ipacct6
[in
][set
];
4261 else if ((fp
->fr_flags
& (FR_OUTQUE
|FR_INQUE
)) != 0)
4262 fprev
= &ipfilter6
[in
][set
];
4267 if (*group
!= '\0') {
4268 if (!fg
&& !(fg
= fr_findgroup(group
, unit
, set
, NULL
)))
4270 fprev
= &fg
->fg_start
;
4274 * Copy in extra data for the rule.
4276 if (fp
->fr_dsize
!= 0) {
4277 if (makecopy
!= 0) {
4278 KMALLOCS(ptr
, void *, fp
->fr_dsize
);
4281 error
= COPYIN(uptr
, ptr
, fp
->fr_dsize
);
4289 KFREES(ptr
, fp
->fr_dsize
);
4297 * Perform per-rule type sanity checks of their members.
4299 switch (fp
->fr_type
& ~FR_T_BUILTIN
)
4301 #if defined(IPFILTER_BPF)
4303 if (fp
->fr_dsize
== 0)
4305 if (!bpf_validate(ptr
, fp
->fr_dsize
/sizeof(struct bpf_insn
))) {
4306 if (makecopy
&& fp
->fr_data
!= NULL
) {
4307 KFREES(fp
->fr_data
, fp
->fr_dsize
);
4314 if (fp
->fr_dsize
!= sizeof(fripf_t
))
4318 * Allowing a rule with both "keep state" and "with oow" is
4319 * pointless because adding a state entry to the table will
4320 * fail with the out of window (oow) flag set.
4322 if ((fp
->fr_flags
& FR_KEEPSTATE
) && (fp
->fr_flx
& FI_OOW
))
4325 switch (fp
->fr_satype
)
4327 case FRI_BROADCAST
:
4330 case FRI_NETMASKED
:
4332 if (fp
->fr_sifpidx
< 0 || fp
->fr_sifpidx
> 3) {
4333 if (makecopy
&& fp
->fr_data
!= NULL
) {
4334 KFREES(fp
->fr_data
, fp
->fr_dsize
);
4339 #ifdef IPFILTER_LOOKUP
4341 fp
->fr_srcptr
= fr_resolvelookup(fp
->fr_srctype
,
4345 if (fp
->fr_srcptr
== NULL
)
4353 switch (fp
->fr_datype
)
4355 case FRI_BROADCAST
:
4358 case FRI_NETMASKED
:
4360 if (fp
->fr_difpidx
< 0 || fp
->fr_difpidx
> 3) {
4361 if (makecopy
&& fp
->fr_data
!= NULL
) {
4362 KFREES(fp
->fr_data
, fp
->fr_dsize
);
4367 #ifdef IPFILTER_LOOKUP
4369 fp
->fr_dstptr
= fr_resolvelookup(fp
->fr_dsttype
,
4373 if (fp
->fr_dstptr
== NULL
)
4383 case FR_T_CALLFUNC
:
4388 if (makecopy
&& fp
->fr_data
!= NULL
) {
4389 KFREES(fp
->fr_data
, fp
->fr_dsize
);
4395 * Lookup all the interface names that are part of the rule.
4397 frsynclist(fp
, NULL
);
4398 fp
->fr_statecnt
= 0;
4401 * Look for an existing matching filter rule, but don't include the
4402 * next or interface pointer in the comparison (fr_next, fr_ifa).
4403 * This elminates rules which are indentical being loaded. Checksum
4404 * the constant part of the filter rule to make comparisons quicker
4405 * (this meaning no pointers are included).
4407 for (fp
->fr_cksum
= 0, p
= (u_int
*)&fp
->fr_func
, pp
= &fp
->fr_cksum
;
4410 pp
= (u_int
*)((char *)fp
->fr_caddr
+ fp
->fr_dsize
);
4411 for (p
= (u_int
*)fp
->fr_data
; p
< pp
; p
++)
4414 WRITE_ENTER(&ipf_mutex
);
4417 * Now that the filter rule lists are locked, we can walk the
4418 * chain of them without fear.
4421 for (f
= *ftail
; (f
= *ftail
) != NULL
; ftail
= &f
->fr_next
) {
4422 if (fp
->fr_collect
<= f
->fr_collect
) {
4429 bzero((char *)frcache
, sizeof(frcache
));
4431 for (; (f
= *ftail
) != NULL
; ftail
= &f
->fr_next
) {
4432 if ((fp
->fr_cksum
!= f
->fr_cksum
) ||
4433 (f
->fr_dsize
!= fp
->fr_dsize
))
4435 if (bcmp((char *)&f
->fr_func
, (char *)&fp
->fr_func
, FR_CMPSIZ
))
4437 if ((!ptr
&& !f
->fr_data
) ||
4438 (ptr
&& f
->fr_data
&&
4439 !bcmp((char *)ptr
, (char *)f
->fr_data
, f
->fr_dsize
)))
4444 * If zero'ing statistics, copy current to caller and zero.
4446 if (req
== (ioctlcmd_t
)SIOCZRLST
) {
4451 * Copy and reduce lock because of impending copyout.
4452 * Well we should, but if we do then the atomicity of
4453 * this call and the correctness of fr_hits and
4454 * fr_bytes cannot be guaranteed. As it is, this code
4455 * only resets them to 0 if they are successfully
4456 * copied out into user space.
4458 bcopy((char *)f
, (char *)fp
, sizeof(*f
));
4459 /* MUTEX_DOWNGRADE(&ipf_mutex); */
4462 * When we copy this rule back out, set the data
4463 * pointer to be what it was in user space.
4466 error
= fr_outobj(data
, fp
, IPFOBJ_FRENTRY
);
4469 if ((f
->fr_dsize
!= 0) && (uptr
!= NULL
))
4470 error
= COPYOUT(f
->fr_data
, uptr
,
4481 if ((ptr
!= NULL
) && (makecopy
!= 0)) {
4482 KFREES(ptr
, fp
->fr_dsize
);
4484 RWLOCK_EXIT(&ipf_mutex
);
4490 * At the end of this, ftail must point to the place where the
4491 * new rule is to be saved/inserted/added.
4492 * For SIOCAD*FR, this should be the last rule in the group of
4493 * rules that have equal fr_collect fields.
4494 * For SIOCIN*FR, ...
4496 if (req
== (ioctlcmd_t
)SIOCADAFR
||
4497 req
== (ioctlcmd_t
)SIOCADIFR
) {
4499 for (ftail
= fprev
; (f
= *ftail
) != NULL
; ) {
4500 if (f
->fr_collect
> fp
->fr_collect
)
4502 ftail
= &f
->fr_next
;
4507 } else if (req
== (ioctlcmd_t
)SIOCINAFR
||
4508 req
== (ioctlcmd_t
)SIOCINIFR
) {
4509 while ((f
= *fprev
) != NULL
) {
4510 if (f
->fr_collect
>= fp
->fr_collect
)
4512 fprev
= &f
->fr_next
;
4515 if (fp
->fr_hits
!= 0) {
4516 while (fp
->fr_hits
&& (f
= *ftail
)) {
4517 if (f
->fr_collect
!= fp
->fr_collect
)
4520 ftail
= &f
->fr_next
;
4531 * Request to remove a rule.
4533 if (req
== (ioctlcmd_t
)SIOCRMAFR
|| req
== (ioctlcmd_t
)SIOCRMIFR
) {
4538 * Do not allow activity from user space to interfere
4539 * with rules not loaded that way.
4541 if ((makecopy
== 1) && !(f
->fr_flags
& FR_COPIED
)) {
4547 * Return EBUSY if the rule is being reference by
4548 * something else (eg state information.)
4550 if (f
->fr_ref
> 1) {
4554 #ifdef IPFILTER_SCAN
4555 if (f
->fr_isctag
[0] != '\0' &&
4556 (f
->fr_isc
!= (struct ipscan
*)-1))
4559 if (unit
== IPL_LOGAUTH
) {
4560 error
= fr_preauthcmd(req
, f
, ftail
);
4563 if (*f
->fr_grhead
!= '\0')
4564 fr_delgroup(f
->fr_grhead
, unit
, set
);
4565 fr_fixskip(ftail
, f
, -1);
4566 *ftail
= f
->fr_next
;
4568 (void) fr_derefrule(&f
);
4572 * Not removing, so we must be adding/inserting a rule.
4577 if (unit
== IPL_LOGAUTH
) {
4578 error
= fr_preauthcmd(req
, fp
, ftail
);
4582 KMALLOC(f
, frentry_t
*);
4587 bcopy((char *)fp
, (char *)f
,
4589 MUTEX_NUKE(&f
->fr_lock
);
4590 MUTEX_INIT(&f
->fr_lock
, "filter rule lock");
4591 #ifdef IPFILTER_SCAN
4592 if (f
->fr_isctag
[0] != '\0' &&
4594 f
->fr_isc
= (struct ipscan
*)-1;
4599 f
->fr_next
= *ftail
;
4601 if (req
== (ioctlcmd_t
)SIOCINIFR
||
4602 req
== (ioctlcmd_t
)SIOCINAFR
)
4603 fr_fixskip(ftail
, f
, 1);
4605 group
= f
->fr_grhead
;
4606 if (*group
!= '\0') {
4607 fg
= fr_addgroup(group
, f
, f
->fr_flags
,
4610 f
->fr_grp
= &fg
->fg_start
;
4617 RWLOCK_EXIT(&ipf_mutex
);
4618 if ((ptr
!= NULL
) && (error
!= 0) && (makecopy
!= 0)) {
4619 KFREES(ptr
, fp
->fr_dsize
);
4625 /* ------------------------------------------------------------------------ */
4626 /* Function: fr_funcinit */
4627 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */
4628 /* Parameters: fr(I) - pointer to filter rule */
4630 /* If a rule is a call rule, then check if the function it points to needs */
4631 /* an init function to be called now the rule has been loaded. */
4632 /* ------------------------------------------------------------------------ */
4633 static int fr_funcinit(fr
)
4636 ipfunc_resolve_t
*ft
;
4641 for (ft
= fr_availfuncs
; ft
->ipfu_addr
!= NULL
; ft
++)
4642 if (ft
->ipfu_addr
== fr
->fr_func
) {
4644 if (ft
->ipfu_init
!= NULL
)
4645 err
= (*ft
->ipfu_init
)(fr
);
4652 /* ------------------------------------------------------------------------ */
4653 /* Function: fr_findfunc */
4654 /* Returns: ipfunc_t - pointer to function if found, else NULL */
4655 /* Parameters: funcptr(I) - function pointer to lookup */
4657 /* Look for a function in the table of known functions. */
4658 /* ------------------------------------------------------------------------ */
4659 static ipfunc_t
fr_findfunc(funcptr
)
4662 ipfunc_resolve_t
*ft
;
4664 for (ft
= fr_availfuncs
; ft
->ipfu_addr
!= NULL
; ft
++)
4665 if (ft
->ipfu_addr
== funcptr
)
4671 /* ------------------------------------------------------------------------ */
4672 /* Function: fr_resolvefunc */
4673 /* Returns: int - 0 == success, else error */
4674 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */
4676 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */
4677 /* This will either be the function name (if the pointer is set) or the */
4678 /* function pointer if the name is set. When found, fill in the other one */
4679 /* so that the entire, complete, structure can be copied back to user space.*/
4680 /* ------------------------------------------------------------------------ */
4681 int fr_resolvefunc(data
)
4684 ipfunc_resolve_t res
, *ft
;
4687 err
= BCOPYIN(data
, &res
, sizeof(res
));
4691 if (res
.ipfu_addr
== NULL
&& res
.ipfu_name
[0] != '\0') {
4692 for (ft
= fr_availfuncs
; ft
->ipfu_addr
!= NULL
; ft
++)
4693 if (strncmp(res
.ipfu_name
, ft
->ipfu_name
,
4694 sizeof(res
.ipfu_name
)) == 0) {
4695 res
.ipfu_addr
= ft
->ipfu_addr
;
4696 res
.ipfu_init
= ft
->ipfu_init
;
4697 if (COPYOUT(&res
, data
, sizeof(res
)) != 0)
4702 if (res
.ipfu_addr
!= NULL
&& res
.ipfu_name
[0] == '\0') {
4703 for (ft
= fr_availfuncs
; ft
->ipfu_addr
!= NULL
; ft
++)
4704 if (ft
->ipfu_addr
== res
.ipfu_addr
) {
4705 (void) strncpy(res
.ipfu_name
, ft
->ipfu_name
,
4706 sizeof(res
.ipfu_name
));
4707 res
.ipfu_init
= ft
->ipfu_init
;
4708 if (COPYOUT(&res
, data
, sizeof(res
)) != 0)
4717 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \
4718 (defined(__FreeBSD__) && (__FreeBSD_version < 501000)) || \
4719 (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \
4720 (defined(__OpenBSD__) && (OpenBSD < 200006))
4723 * ppsratecheck(): packets (or events) per second limitation.
4726 ppsratecheck(lasttime
, curpps
, maxpps
)
4727 struct timeval
*lasttime
;
4729 int maxpps
; /* maximum pps allowed */
4731 struct timeval tv
, delta
;
4736 delta
.tv_sec
= tv
.tv_sec
- lasttime
->tv_sec
;
4737 delta
.tv_usec
= tv
.tv_usec
- lasttime
->tv_usec
;
4738 if (delta
.tv_usec
< 0) {
4740 delta
.tv_usec
+= 1000000;
4744 * check for 0,0 is so that the message will be seen at least once.
4745 * if more than one second have passed since the last update of
4746 * lasttime, reset the counter.
4748 * we do increment *curpps even in *curpps < maxpps case, as some may
4749 * try to use *curpps for stat purposes as well.
4751 if ((lasttime
->tv_sec
== 0 && lasttime
->tv_usec
== 0) ||
4752 delta
.tv_sec
>= 1) {
4756 } else if (maxpps
< 0)
4758 else if (*curpps
< maxpps
)
4762 *curpps
= *curpps
+ 1;
4769 /* ------------------------------------------------------------------------ */
4770 /* Function: fr_derefrule */
4771 /* Returns: int - 0 == rule freed up, else rule not freed */
4772 /* Parameters: fr(I) - pointer to filter rule */
4774 /* Decrement the reference counter to a rule by one. If it reaches zero, */
4775 /* free it and any associated storage space being used by it. */
4776 /* ------------------------------------------------------------------------ */
4777 int fr_derefrule(frp
)
4785 MUTEX_ENTER(&fr
->fr_lock
);
4787 if (fr
->fr_ref
== 0) {
4788 MUTEX_EXIT(&fr
->fr_lock
);
4789 MUTEX_DESTROY(&fr
->fr_lock
);
4791 #ifdef IPFILTER_LOOKUP
4792 if (fr
->fr_type
== FR_T_IPF
&& fr
->fr_satype
== FRI_LOOKUP
)
4793 ip_lookup_deref(fr
->fr_srctype
, fr
->fr_srcptr
);
4794 if (fr
->fr_type
== FR_T_IPF
&& fr
->fr_datype
== FRI_LOOKUP
)
4795 ip_lookup_deref(fr
->fr_dsttype
, fr
->fr_dstptr
);
4799 KFREES(fr
->fr_data
, fr
->fr_dsize
);
4801 if ((fr
->fr_flags
& FR_COPIED
) != 0) {
4807 MUTEX_EXIT(&fr
->fr_lock
);
4813 #ifdef IPFILTER_LOOKUP
4814 /* ------------------------------------------------------------------------ */
4815 /* Function: fr_grpmapinit */
4816 /* Returns: int - 0 == success, else ESRCH because table entry not found*/
4817 /* Parameters: fr(I) - pointer to rule to find hash table for */
4819 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */
4820 /* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */
4821 /* ------------------------------------------------------------------------ */
4822 static int fr_grpmapinit(fr
)
4825 char name
[FR_GROUPLEN
];
4828 #if defined(SNPRINTF) && defined(_KERNEL)
4829 SNPRINTF(name
, sizeof(name
), "%d", fr
->fr_arg
);
4831 (void) sprintf(name
, "%d", fr
->fr_arg
);
4833 iph
= fr_findhtable(IPL_LOGIPF
, name
);
4836 if ((iph
->iph_flags
& FR_INOUT
) != (fr
->fr_flags
& FR_INOUT
))
4843 /* ------------------------------------------------------------------------ */
4844 /* Function: fr_srcgrpmap */
4845 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
4846 /* Parameters: fin(I) - pointer to packet information */
4847 /* passp(IO) - pointer to current/new filter decision (unused) */
4849 /* Look for a rule group head in a hash table, using the source address as */
4850 /* the key, and descend into that group and continue matching rules against */
4852 /* ------------------------------------------------------------------------ */
4853 frentry_t
*fr_srcgrpmap(fin
, passp
)
4860 rval
= fr_iphmfindgroup(fin
->fin_fr
->fr_ptr
, &fin
->fin_src
);
4865 fin
->fin_fr
= fg
->fg_start
;
4866 (void) fr_scanlist(fin
, *passp
);
4871 /* ------------------------------------------------------------------------ */
4872 /* Function: fr_dstgrpmap */
4873 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
4874 /* Parameters: fin(I) - pointer to packet information */
4875 /* passp(IO) - pointer to current/new filter decision (unused) */
4877 /* Look for a rule group head in a hash table, using the destination */
4878 /* address as the key, and descend into that group and continue matching */
4879 /* rules against the packet. */
4880 /* ------------------------------------------------------------------------ */
4881 frentry_t
*fr_dstgrpmap(fin
, passp
)
4888 rval
= fr_iphmfindgroup(fin
->fin_fr
->fr_ptr
, &fin
->fin_dst
);
4893 fin
->fin_fr
= fg
->fg_start
;
4894 (void) fr_scanlist(fin
, *passp
);
4897 #endif /* IPFILTER_LOOKUP */
4902 * These functions manage objects on queues for efficient timeouts. There are
4903 * a number of system defined queues as well as user defined timeouts. It is
4904 * expected that a lock is held in the domain in which the queue belongs
4905 * (i.e. either state or NAT) when calling any of these functions that prevents
4906 * fr_freetimeoutqueue() from being called at the same time as any other.
4910 /* ------------------------------------------------------------------------ */
4911 /* Function: fr_addtimeoutqueue */
4912 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */
4913 /* timeout queue with given interval. */
4914 /* Parameters: parent(I) - pointer to pointer to parent node of this list */
4915 /* of interface queues. */
4916 /* seconds(I) - timeout value in seconds for this queue. */
4918 /* This routine first looks for a timeout queue that matches the interval */
4919 /* being requested. If it finds one, increments the reference counter and */
4920 /* returns a pointer to it. If none are found, it allocates a new one and */
4921 /* inserts it at the top of the list. */
4924 /* It is assumed that the caller of this function has an appropriate lock */
4925 /* held (exclusively) in the domain that encompases 'parent'. */
4926 /* ------------------------------------------------------------------------ */
4927 ipftq_t
*fr_addtimeoutqueue(parent
, seconds
)
4934 period
= seconds
* IPF_HZ_DIVIDE
;
4936 MUTEX_ENTER(&ipf_timeoutlock
);
4937 for (ifq
= *parent
; ifq
!= NULL
; ifq
= ifq
->ifq_next
) {
4938 if (ifq
->ifq_ttl
== period
) {
4940 * Reset the delete flag, if set, so the structure
4941 * gets reused rather than freed and reallocated.
4943 MUTEX_ENTER(&ifq
->ifq_lock
);
4944 ifq
->ifq_flags
&= ~IFQF_DELETE
;
4946 MUTEX_EXIT(&ifq
->ifq_lock
);
4947 MUTEX_EXIT(&ipf_timeoutlock
);
4953 KMALLOC(ifq
, ipftq_t
*);
4955 ifq
->ifq_ttl
= period
;
4956 ifq
->ifq_head
= NULL
;
4957 ifq
->ifq_tail
= &ifq
->ifq_head
;
4958 ifq
->ifq_next
= *parent
;
4959 ifq
->ifq_pnext
= parent
;
4961 ifq
->ifq_flags
= IFQF_USER
;
4964 MUTEX_NUKE(&ifq
->ifq_lock
);
4965 MUTEX_INIT(&ifq
->ifq_lock
, "ipftq mutex");
4967 MUTEX_EXIT(&ipf_timeoutlock
);
4972 /* ------------------------------------------------------------------------ */
4973 /* Function: fr_deletetimeoutqueue */
4974 /* Returns: int - new reference count value of the timeout queue */
4975 /* Parameters: ifq(I) - timeout queue which is losing a reference. */
4976 /* Locks: ifq->ifq_lock */
4978 /* This routine must be called when we're discarding a pointer to a timeout */
4979 /* queue object, taking care of the reference counter. */
4981 /* Now that this just sets a DELETE flag, it requires the expire code to */
4982 /* check the list of user defined timeout queues and call the free function */
4983 /* below (currently commented out) to stop memory leaking. It is done this */
4984 /* way because the locking may not be sufficient to safely do a free when */
4985 /* this function is called. */
4986 /* ------------------------------------------------------------------------ */
4987 int fr_deletetimeoutqueue(ifq
)
4992 if ((ifq
->ifq_ref
== 0) && ((ifq
->ifq_flags
& IFQF_USER
) != 0)) {
4993 ifq
->ifq_flags
|= IFQF_DELETE
;
4996 return ifq
->ifq_ref
;
5000 /* ------------------------------------------------------------------------ */
5001 /* Function: fr_freetimeoutqueue */
5002 /* Parameters: ifq(I) - timeout queue which is losing a reference. */
5006 /* It is assumed that the caller of this function has an appropriate lock */
5007 /* held (exclusively) in the domain that encompases the callers "domain". */
5008 /* The ifq_lock for this structure should not be held. */
5010 /* Remove a user definde timeout queue from the list of queues it is in and */
5011 /* tidy up after this is done. */
5012 /* ------------------------------------------------------------------------ */
5013 void fr_freetimeoutqueue(ifq
)
5018 if (((ifq
->ifq_flags
& IFQF_DELETE
) == 0) || (ifq
->ifq_ref
!= 0) ||
5019 ((ifq
->ifq_flags
& IFQF_USER
) == 0)) {
5020 printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
5021 (u_long
)ifq
, ifq
->ifq_flags
, ifq
->ifq_ttl
,
5027 * Remove from its position in the list.
5029 *ifq
->ifq_pnext
= ifq
->ifq_next
;
5030 if (ifq
->ifq_next
!= NULL
)
5031 ifq
->ifq_next
->ifq_pnext
= ifq
->ifq_pnext
;
5033 MUTEX_DESTROY(&ifq
->ifq_lock
);
5034 ATOMIC_DEC(fr_userifqs
);
5039 /* ------------------------------------------------------------------------ */
5040 /* Function: fr_deletequeueentry */
5042 /* Parameters: tqe(I) - timeout queue entry to delete */
5043 /* ifq(I) - timeout queue to remove entry from */
5045 /* Remove a tail queue entry from its queue and make it an orphan. */
5046 /* fr_deletetimeoutqueue is called to make sure the reference count on the */
5047 /* queue is correct. We can't, however, call fr_freetimeoutqueue because */
5048 /* the correct lock(s) may not be held that would make it safe to do so. */
5049 /* ------------------------------------------------------------------------ */
5050 void fr_deletequeueentry(tqe
)
5057 MUTEX_ENTER(&ifq
->ifq_lock
);
5059 if (tqe
->tqe_pnext
!= NULL
) {
5060 *tqe
->tqe_pnext
= tqe
->tqe_next
;
5061 if (tqe
->tqe_next
!= NULL
)
5062 tqe
->tqe_next
->tqe_pnext
= tqe
->tqe_pnext
;
5063 else /* we must be the tail anyway */
5064 ifq
->ifq_tail
= tqe
->tqe_pnext
;
5066 tqe
->tqe_pnext
= NULL
;
5067 tqe
->tqe_ifq
= NULL
;
5070 (void) fr_deletetimeoutqueue(ifq
);
5072 MUTEX_EXIT(&ifq
->ifq_lock
);
5076 /* ------------------------------------------------------------------------ */
5077 /* Function: fr_queuefront */
5079 /* Parameters: tqe(I) - pointer to timeout queue entry */
5081 /* Move a queue entry to the front of the queue, if it isn't already there. */
5082 /* ------------------------------------------------------------------------ */
5083 void fr_queuefront(tqe
)
5092 MUTEX_ENTER(&ifq
->ifq_lock
);
5093 if (ifq
->ifq_head
!= tqe
) {
5094 *tqe
->tqe_pnext
= tqe
->tqe_next
;
5096 tqe
->tqe_next
->tqe_pnext
= tqe
->tqe_pnext
;
5098 ifq
->ifq_tail
= tqe
->tqe_pnext
;
5100 tqe
->tqe_next
= ifq
->ifq_head
;
5101 ifq
->ifq_head
->tqe_pnext
= &tqe
->tqe_next
;
5102 ifq
->ifq_head
= tqe
;
5103 tqe
->tqe_pnext
= &ifq
->ifq_head
;
5105 MUTEX_EXIT(&ifq
->ifq_lock
);
5109 /* ------------------------------------------------------------------------ */
5110 /* Function: fr_queueback */
5112 /* Parameters: tqe(I) - pointer to timeout queue entry */
5114 /* Move a queue entry to the back of the queue, if it isn't already there. */
5115 /* ------------------------------------------------------------------------ */
5116 void fr_queueback(tqe
)
5124 tqe
->tqe_die
= fr_ticks
+ ifq
->ifq_ttl
;
5126 MUTEX_ENTER(&ifq
->ifq_lock
);
5127 if (tqe
->tqe_next
!= NULL
) { /* at the end already ? */
5131 *tqe
->tqe_pnext
= tqe
->tqe_next
;
5132 tqe
->tqe_next
->tqe_pnext
= tqe
->tqe_pnext
;
5135 * Make it the last entry.
5137 tqe
->tqe_next
= NULL
;
5138 tqe
->tqe_pnext
= ifq
->ifq_tail
;
5139 *ifq
->ifq_tail
= tqe
;
5140 ifq
->ifq_tail
= &tqe
->tqe_next
;
5142 MUTEX_EXIT(&ifq
->ifq_lock
);
5146 /* ------------------------------------------------------------------------ */
5147 /* Function: fr_queueappend */
5149 /* Parameters: tqe(I) - pointer to timeout queue entry */
5150 /* ifq(I) - pointer to timeout queue */
5151 /* parent(I) - owing object pointer */
5153 /* Add a new item to this queue and put it on the very end. */
5154 /* ------------------------------------------------------------------------ */
5155 void fr_queueappend(tqe
, ifq
, parent
)
5161 MUTEX_ENTER(&ifq
->ifq_lock
);
5162 tqe
->tqe_parent
= parent
;
5163 tqe
->tqe_pnext
= ifq
->ifq_tail
;
5164 *ifq
->ifq_tail
= tqe
;
5165 ifq
->ifq_tail
= &tqe
->tqe_next
;
5166 tqe
->tqe_next
= NULL
;
5168 tqe
->tqe_die
= fr_ticks
+ ifq
->ifq_ttl
;
5170 MUTEX_EXIT(&ifq
->ifq_lock
);
5174 /* ------------------------------------------------------------------------ */
5175 /* Function: fr_movequeue */
5177 /* Parameters: tq(I) - pointer to timeout queue information */
5178 /* oifp(I) - old timeout queue entry was on */
5179 /* nifp(I) - new timeout queue to put entry on */
5181 /* Move a queue entry from one timeout queue to another timeout queue. */
5182 /* If it notices that the current entry is already last and does not need */
5183 /* to move queue, the return. */
5184 /* ------------------------------------------------------------------------ */
5185 void fr_movequeue(tqe
, oifq
, nifq
)
5187 ipftq_t
*oifq
, *nifq
;
5191 * If the queue hasn't changed and we last touched this entry at the
5192 * same ipf time, then we're not going to achieve anything by either
5193 * changing the ttl or moving it on the queue.
5195 if (oifq
== nifq
&& tqe
->tqe_touched
== fr_ticks
)
5199 * For any of this to be outside the lock, there is a risk that two
5200 * packets entering simultaneously, with one changing to a different
5201 * queue and one not, could end up with things in a bizarre state.
5203 MUTEX_ENTER(&oifq
->ifq_lock
);
5205 tqe
->tqe_touched
= fr_ticks
;
5206 tqe
->tqe_die
= fr_ticks
+ nifq
->ifq_ttl
;
5208 * Is the operation here going to be a no-op ?
5211 if ((tqe
->tqe_next
== NULL
) ||
5212 (tqe
->tqe_next
->tqe_die
== tqe
->tqe_die
)) {
5213 MUTEX_EXIT(&oifq
->ifq_lock
);
5219 * Remove from the old queue
5221 *tqe
->tqe_pnext
= tqe
->tqe_next
;
5223 tqe
->tqe_next
->tqe_pnext
= tqe
->tqe_pnext
;
5225 oifq
->ifq_tail
= tqe
->tqe_pnext
;
5226 tqe
->tqe_next
= NULL
;
5229 * If we're moving from one queue to another, release the
5230 * lock on the old queue and get a lock on the new queue.
5231 * For user defined queues, if we're moving off it, call
5232 * delete in case it can now be freed.
5235 tqe
->tqe_ifq
= NULL
;
5237 (void) fr_deletetimeoutqueue(oifq
);
5239 MUTEX_EXIT(&oifq
->ifq_lock
);
5241 MUTEX_ENTER(&nifq
->ifq_lock
);
5243 tqe
->tqe_ifq
= nifq
;
5248 * Add to the bottom of the new queue
5250 tqe
->tqe_pnext
= nifq
->ifq_tail
;
5251 *nifq
->ifq_tail
= tqe
;
5252 nifq
->ifq_tail
= &tqe
->tqe_next
;
5253 MUTEX_EXIT(&nifq
->ifq_lock
);
5257 /* ------------------------------------------------------------------------ */
5258 /* Function: fr_updateipid */
5259 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */
5260 /* Parameters: fin(I) - pointer to packet information */
5262 /* When we are doing NAT, change the IP of every packet to represent a */
5263 /* single sequence of packets coming from the host, hiding any host */
5264 /* specific sequencing that might otherwise be revealed. If the packet is */
5265 /* a fragment, then store the 'new' IPid in the fragment cache and look up */
5266 /* the fragment cache for non-leading fragments. If a non-leading fragment */
5267 /* has no match in the cache, return an error. */
5268 /* ------------------------------------------------------------------------ */
5269 static int fr_updateipid(fin
)
5272 u_short id
, ido
, sums
;
5276 if (fin
->fin_off
!= 0) {
5277 sum
= fr_ipid_knownfrag(fin
);
5278 if (sum
== 0xffffffff)
5283 id
= fr_nextipid(fin
);
5284 if (fin
->fin_off
== 0 && (fin
->fin_flx
& FI_FRAG
) != 0)
5285 (void) fr_ipid_newfrag(fin
, (u_32_t
)id
);
5289 ido
= ntohs(ip
->ip_id
);
5292 ip
->ip_id
= htons(id
);
5293 CALC_SUMD(ido
, id
, sumd
); /* DESTRUCTIVE MACRO! id,ido change */
5294 sum
= (~ntohs(ip
->ip_sum
)) & 0xffff;
5296 sum
= (sum
>> 16) + (sum
& 0xffff);
5297 sum
= (sum
>> 16) + (sum
& 0xffff);
5298 sums
= ~(u_short
)sum
;
5299 ip
->ip_sum
= htons(sums
);
5304 #ifdef NEED_FRGETIFNAME
5305 /* ------------------------------------------------------------------------ */
5306 /* Function: fr_getifname */
5307 /* Returns: char * - pointer to interface name */
5308 /* Parameters: ifp(I) - pointer to network interface */
5309 /* buffer(O) - pointer to where to store interface name */
5311 /* Constructs an interface name in the buffer passed. The buffer passed is */
5312 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */
5313 /* as a NULL pointer then return a pointer to a static array. */
5314 /* ------------------------------------------------------------------------ */
5315 char *fr_getifname(ifp
, buffer
)
5319 static char namebuf
[LIFNAMSIZ
];
5320 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
5321 defined(__sgi) || defined(linux) || defined(_AIX51) || \
5322 (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
5330 (void) strncpy(buffer
, ifp
->if_name
, LIFNAMSIZ
);
5331 buffer
[LIFNAMSIZ
- 1] = '\0';
5332 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
5333 defined(__sgi) || defined(_AIX51) || \
5334 (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
5335 for (s
= buffer
; *s
; s
++)
5337 unit
= ifp
->if_unit
;
5338 space
= LIFNAMSIZ
- (s
- buffer
);
5340 # if defined(SNPRINTF) && defined(_KERNEL)
5341 SNPRINTF(temp
, sizeof(temp
), "%d", unit
);
5343 (void) sprintf(temp
, "%d", unit
);
5345 (void) strncpy(s
, temp
, space
);
5353 /* ------------------------------------------------------------------------ */
5354 /* Function: fr_ioctlswitch */
5355 /* Returns: int - -1 continue processing, else ioctl return value */
5356 /* Parameters: unit(I) - device unit opened */
5357 /* data(I) - pointer to ioctl data */
5358 /* cmd(I) - ioctl command */
5359 /* mode(I) - mode value */
5360 /* uid(I) - uid making the ioctl call */
5361 /* ctx(I) - pointer to context data */
5363 /* Based on the value of unit, call the appropriate ioctl handler or return */
5364 /* EIO if ipfilter is not running. Also checks if write perms are req'd */
5365 /* for the device in order to execute the ioctl. */
5366 /* ------------------------------------------------------------------------ */
5367 int fr_ioctlswitch(unit
, data
, cmd
, mode
, uid
, ctx
)
5368 int unit
, mode
, uid
;
5377 error
= fr_ipf_ioctl(data
, cmd
, mode
, uid
, ctx
);
5381 error
= fr_nat_ioctl(data
, cmd
, mode
, uid
, ctx
);
5387 error
= fr_state_ioctl(data
, cmd
, mode
, uid
, ctx
);
5393 error
= fr_auth_ioctl(data
, cmd
, mode
, uid
, ctx
);
5398 #ifdef IPFILTER_SYNC
5400 error
= fr_sync_ioctl(data
, cmd
, mode
, uid
, ctx
);
5406 #ifdef IPFILTER_SCAN
5408 error
= fr_scan_ioctl(data
, cmd
, mode
, uid
, ctx
);
5413 case IPL_LOGLOOKUP
:
5414 #ifdef IPFILTER_LOOKUP
5416 error
= ip_lookup_ioctl(data
, cmd
, mode
, uid
, ctx
);
5431 * This array defines the expected size of objects coming into the kernel
5432 * for the various recognised object types.
5434 static int fr_objbytes
[IPFOBJ_COUNT
][2] = {
5435 { 1, sizeof(struct frentry
) }, /* frentry */
5436 { 0, sizeof(struct friostat
) },
5437 { 0, sizeof(struct fr_info
) },
5438 { 0, sizeof(struct fr_authstat
) },
5439 { 0, sizeof(struct ipfrstat
) },
5440 { 0, sizeof(struct ipnat
) },
5441 { 0, sizeof(struct natstat
) },
5442 { 0, sizeof(struct ipstate_save
) },
5443 { 1, sizeof(struct nat_save
) }, /* nat_save */
5444 { 0, sizeof(struct natlookup
) },
5445 { 1, sizeof(struct ipstate
) }, /* ipstate */
5446 { 0, sizeof(struct ips_stat
) },
5447 { 0, sizeof(struct frauth
) },
5448 { 0, sizeof(struct ipftune
) },
5449 { 0, sizeof(struct nat
) }, /* nat_t */
5450 { 0, sizeof(struct ipfruleiter
) },
5451 { 0, sizeof(struct ipfgeniter
) },
5452 { 0, sizeof(struct ipftable
) },
5453 { 0, sizeof(struct ipflookupiter
) },
5454 { 0, sizeof(struct ipftq
) * IPF_TCP_NSTATES
},
5458 /* ------------------------------------------------------------------------ */
5459 /* Function: fr_inobj */
5460 /* Returns: int - 0 = success, else failure */
5461 /* Parameters: data(I) - pointer to ioctl data */
5462 /* ptr(I) - pointer to store real data in */
5463 /* type(I) - type of structure being moved */
5465 /* Copy in the contents of what the ipfobj_t points to. In future, we */
5466 /* add things to check for version numbers, sizes, etc, to make it backward */
5467 /* compatible at the ABI for user land. */
5468 /* ------------------------------------------------------------------------ */
5469 int fr_inobj(data
, ptr
, type
)
5477 if ((type
< 0) || (type
>= IPFOBJ_COUNT
))
5480 error
= BCOPYIN(data
, &obj
, sizeof(obj
));
5484 if (obj
.ipfo_type
!= type
)
5487 #ifndef IPFILTER_COMPAT
5488 if ((fr_objbytes
[type
][0] & 1) != 0) {
5489 if (obj
.ipfo_size
< fr_objbytes
[type
][1])
5491 } else if (obj
.ipfo_size
!= fr_objbytes
[type
][1]) {
5495 if (obj
.ipfo_rev
!= IPFILTER_VERSION
)
5496 /* XXX compatibility hook here */
5498 if ((fr_objbytes
[type
][0] & 1) != 0) {
5499 if (obj
.ipfo_size
< fr_objbytes
[type
][1])
5500 /* XXX compatibility hook here */
5502 } else if (obj
.ipfo_size
!= fr_objbytes
[type
][1])
5503 /* XXX compatibility hook here */
5507 if ((fr_objbytes
[type
][0] & 1) != 0) {
5508 error
= COPYIN((void *)obj
.ipfo_ptr
, (void *)ptr
,
5509 fr_objbytes
[type
][1]);
5511 error
= COPYIN((void *)obj
.ipfo_ptr
, (void *)ptr
,
5520 /* ------------------------------------------------------------------------ */
5521 /* Function: fr_inobjsz */
5522 /* Returns: int - 0 = success, else failure */
5523 /* Parameters: data(I) - pointer to ioctl data */
5524 /* ptr(I) - pointer to store real data in */
5525 /* type(I) - type of structure being moved */
5526 /* sz(I) - size of data to copy */
5528 /* As per fr_inobj, except the size of the object to copy in is passed in */
5529 /* but it must not be smaller than the size defined for the type and the */
5530 /* type must allow for varied sized objects. The extra requirement here is */
5531 /* that sz must match the size of the object being passed in - this is not */
5532 /* not possible nor required in fr_inobj(). */
5533 /* ------------------------------------------------------------------------ */
5534 int fr_inobjsz(data
, ptr
, type
, sz
)
5542 if ((type
< 0) || (type
>= IPFOBJ_COUNT
))
5544 if (((fr_objbytes
[type
][0] & 1) == 0) || (sz
< fr_objbytes
[type
][1]))
5547 error
= BCOPYIN(data
, &obj
, sizeof(obj
));
5551 if (obj
.ipfo_type
!= type
)
5554 #ifndef IPFILTER_COMPAT
5555 if (obj
.ipfo_size
!= sz
)
5558 if (obj
.ipfo_rev
!= IPFILTER_VERSION
)
5559 /* XXX compatibility hook here */
5561 if (obj
.ipfo_size
!= sz
)
5562 /* XXX compatibility hook here */
5566 error
= COPYIN((void *)obj
.ipfo_ptr
, (void *)ptr
, sz
);
5573 /* ------------------------------------------------------------------------ */
5574 /* Function: fr_outobjsz */
5575 /* Returns: int - 0 = success, else failure */
5576 /* Parameters: data(I) - pointer to ioctl data */
5577 /* ptr(I) - pointer to store real data in */
5578 /* type(I) - type of structure being moved */
5579 /* sz(I) - size of data to copy */
5581 /* As per fr_outobj, except the size of the object to copy out is passed in */
5582 /* but it must not be smaller than the size defined for the type and the */
5583 /* type must allow for varied sized objects. The extra requirement here is */
5584 /* that sz must match the size of the object being passed in - this is not */
5585 /* not possible nor required in fr_outobj(). */
5586 /* ------------------------------------------------------------------------ */
5587 int fr_outobjsz(data
, ptr
, type
, sz
)
5595 if ((type
< 0) || (type
>= IPFOBJ_COUNT
) ||
5596 ((fr_objbytes
[type
][0] & 1) == 0) ||
5597 (sz
< fr_objbytes
[type
][1]))
5600 error
= BCOPYIN(data
, &obj
, sizeof(obj
));
5604 if (obj
.ipfo_type
!= type
)
5607 #ifndef IPFILTER_COMPAT
5608 if (obj
.ipfo_size
!= sz
)
5611 if (obj
.ipfo_rev
!= IPFILTER_VERSION
)
5612 /* XXX compatibility hook here */
5614 if (obj
.ipfo_size
!= sz
)
5615 /* XXX compatibility hook here */
5619 error
= COPYOUT((void *)ptr
, (void *)obj
.ipfo_ptr
, sz
);
5626 /* ------------------------------------------------------------------------ */
5627 /* Function: fr_outobj */
5628 /* Returns: int - 0 = success, else failure */
5629 /* Parameters: data(I) - pointer to ioctl data */
5630 /* ptr(I) - pointer to store real data in */
5631 /* type(I) - type of structure being moved */
5633 /* Copy out the contents of what ptr is to where ipfobj points to. In */
5634 /* future, we add things to check for version numbers, sizes, etc, to make */
5635 /* it backward compatible at the ABI for user land. */
5636 /* ------------------------------------------------------------------------ */
5637 int fr_outobj(data
, ptr
, type
)
5645 if ((type
< 0) || (type
>= IPFOBJ_COUNT
))
5648 error
= BCOPYIN(data
, &obj
, sizeof(obj
));
5652 if (obj
.ipfo_type
!= type
)
5655 #ifndef IPFILTER_COMPAT
5656 if ((fr_objbytes
[type
][0] & 1) != 0) {
5657 if (obj
.ipfo_size
< fr_objbytes
[type
][1])
5659 } else if (obj
.ipfo_size
!= fr_objbytes
[type
][1])
5662 if (obj
.ipfo_rev
!= IPFILTER_VERSION
)
5663 /* XXX compatibility hook here */
5665 if ((fr_objbytes
[type
][0] & 1) != 0) {
5666 if (obj
.ipfo_size
< fr_objbytes
[type
][1])
5667 /* XXX compatibility hook here */
5669 } else if (obj
.ipfo_size
!= fr_objbytes
[type
][1])
5670 /* XXX compatibility hook here */
5674 error
= COPYOUT((void *)ptr
, (void *)obj
.ipfo_ptr
, obj
.ipfo_size
);
5681 /* ------------------------------------------------------------------------ */
5682 /* Function: fr_checkl4sum */
5683 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */
5684 /* Parameters: fin(I) - pointer to packet information */
5686 /* If possible, calculate the layer 4 checksum for the packet. If this is */
5687 /* not possible, return without indicating a failure or success but in a */
5688 /* way that is ditinguishable. */
5689 /* ------------------------------------------------------------------------ */
5690 int fr_checkl4sum(fin
)
5693 u_short sum
, hdrsum
, *csump
;
5697 if ((fin
->fin_flx
& FI_NOCKSUM
) != 0)
5700 if (fin
->fin_cksum
== 1)
5703 if (fin
->fin_cksum
== -1)
5707 * If the TCP packet isn't a fragment, isn't too short and otherwise
5708 * isn't already considered "bad", then validate the checksum. If
5709 * this check fails then considered the packet to be "bad".
5711 if ((fin
->fin_flx
& (FI_FRAG
|FI_SHORT
|FI_BAD
)) != 0)
5719 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
5720 if (dohwcksum
&& ((*fin
->fin_mp
)->b_ick_flag
== ICK_VALID
)) {
5728 csump
= &((tcphdr_t
*)fin
->fin_dp
)->th_sum
;
5734 if (udp
->uh_sum
!= 0) {
5735 csump
= &udp
->uh_sum
;
5741 csump
= &((struct icmp
*)fin
->fin_dp
)->icmp_cksum
;
5755 sum
= fr_cksum(fin
->fin_m
, fin
->fin_ip
,
5756 fin
->fin_p
, fin
->fin_dp
,
5757 fin
->fin_dlen
+ fin
->fin_hlen
);
5762 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
5765 #if !defined(_KERNEL)
5766 if (sum
== hdrsum
) {
5767 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum
, hdrsum
));
5769 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum
, hdrsum
));
5772 if (hdrsum
== sum
) {
5776 fin
->fin_cksum
= -1;
5781 /* ------------------------------------------------------------------------ */
5782 /* Function: fr_ifpfillv4addr */
5783 /* Returns: int - 0 = address update, -1 = address not updated */
5784 /* Parameters: atype(I) - type of network address update to perform */
5785 /* sin(I) - pointer to source of address information */
5786 /* mask(I) - pointer to source of netmask information */
5787 /* inp(I) - pointer to destination address store */
5788 /* inpmask(I) - pointer to destination netmask store */
5790 /* Given a type of network address update (atype) to perform, copy */
5791 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */
5792 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */
5793 /* which case the operation fails. For all values of atype other than */
5794 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
5796 /* ------------------------------------------------------------------------ */
5797 int fr_ifpfillv4addr(atype
, sin
, mask
, inp
, inpmask
)
5799 struct sockaddr_in
*sin
, *mask
;
5800 struct in_addr
*inp
, *inpmask
;
5802 if (inpmask
!= NULL
&& atype
!= FRI_NETMASKED
)
5803 inpmask
->s_addr
= 0xffffffff;
5805 if (atype
== FRI_NETWORK
|| atype
== FRI_NETMASKED
) {
5806 if (atype
== FRI_NETMASKED
) {
5807 if (inpmask
== NULL
)
5809 inpmask
->s_addr
= mask
->sin_addr
.s_addr
;
5811 inp
->s_addr
= sin
->sin_addr
.s_addr
& mask
->sin_addr
.s_addr
;
5813 inp
->s_addr
= sin
->sin_addr
.s_addr
;
5820 /* ------------------------------------------------------------------------ */
5821 /* Function: fr_ifpfillv6addr */
5822 /* Returns: int - 0 = address update, -1 = address not updated */
5823 /* Parameters: atype(I) - type of network address update to perform */
5824 /* sin(I) - pointer to source of address information */
5825 /* mask(I) - pointer to source of netmask information */
5826 /* inp(I) - pointer to destination address store */
5827 /* inpmask(I) - pointer to destination netmask store */
5829 /* Given a type of network address update (atype) to perform, copy */
5830 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */
5831 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */
5832 /* which case the operation fails. For all values of atype other than */
5833 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
5835 /* ------------------------------------------------------------------------ */
5836 int fr_ifpfillv6addr(atype
, sin
, mask
, inp
, inpmask
)
5838 struct sockaddr_in6
*sin
, *mask
;
5839 struct in_addr
*inp
, *inpmask
;
5841 i6addr_t
*src
, *dst
, *and, *dmask
;
5843 src
= (i6addr_t
*)&sin
->sin6_addr
;
5844 and = (i6addr_t
*)&mask
->sin6_addr
;
5845 dst
= (i6addr_t
*)inp
;
5846 dmask
= (i6addr_t
*)inpmask
;
5848 if (inpmask
!= NULL
&& atype
!= FRI_NETMASKED
) {
5849 dmask
->i6
[0] = 0xffffffff;
5850 dmask
->i6
[1] = 0xffffffff;
5851 dmask
->i6
[2] = 0xffffffff;
5852 dmask
->i6
[3] = 0xffffffff;
5855 if (atype
== FRI_NETWORK
|| atype
== FRI_NETMASKED
) {
5856 if (atype
== FRI_NETMASKED
) {
5857 if (inpmask
== NULL
)
5859 dmask
->i6
[0] = and->i6
[0];
5860 dmask
->i6
[1] = and->i6
[1];
5861 dmask
->i6
[2] = and->i6
[2];
5862 dmask
->i6
[3] = and->i6
[3];
5865 dst
->i6
[0] = src
->i6
[0] & and->i6
[0];
5866 dst
->i6
[1] = src
->i6
[1] & and->i6
[1];
5867 dst
->i6
[2] = src
->i6
[2] & and->i6
[2];
5868 dst
->i6
[3] = src
->i6
[3] & and->i6
[3];
5870 dst
->i6
[0] = src
->i6
[0];
5871 dst
->i6
[1] = src
->i6
[1];
5872 dst
->i6
[2] = src
->i6
[2];
5873 dst
->i6
[3] = src
->i6
[3];
5880 /* ------------------------------------------------------------------------ */
5881 /* Function: fr_matchtag */
5882 /* Returns: 0 == mismatch, 1 == match. */
5883 /* Parameters: tag1(I) - pointer to first tag to compare */
5884 /* tag2(I) - pointer to second tag to compare */
5886 /* Returns true (non-zero) or false(0) if the two tag structures can be */
5887 /* considered to be a match or not match, respectively. The tag is 16 */
5888 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */
5889 /* compare the ints instead, for speed. tag1 is the master of the */
5890 /* comparison. This function should only be called with both tag1 and tag2 */
5891 /* as non-NULL pointers. */
5892 /* ------------------------------------------------------------------------ */
5893 int fr_matchtag(tag1
, tag2
)
5894 ipftag_t
*tag1
, *tag2
;
5899 if ((tag1
->ipt_num
[0] == 0) && (tag2
->ipt_num
[0] == 0))
5902 if ((tag1
->ipt_num
[0] == tag2
->ipt_num
[0]) &&
5903 (tag1
->ipt_num
[1] == tag2
->ipt_num
[1]) &&
5904 (tag1
->ipt_num
[2] == tag2
->ipt_num
[2]) &&
5905 (tag1
->ipt_num
[3] == tag2
->ipt_num
[3]))
5911 /* ------------------------------------------------------------------------ */
5912 /* Function: fr_coalesce */
5913 /* Returns: 1 == success, -1 == failure, 0 == no change */
5914 /* Parameters: fin(I) - pointer to packet information */
5916 /* Attempt to get all of the packet data into a single, contiguous buffer. */
5917 /* If this call returns a failure then the buffers have also been freed. */
5918 /* ------------------------------------------------------------------------ */
5919 int fr_coalesce(fin
)
5922 if ((fin
->fin_flx
& FI_COALESCE
) != 0)
5926 * If the mbuf pointers indicate that there is no mbuf to work with,
5927 * return but do not indicate success or failure.
5929 if (fin
->fin_m
== NULL
|| fin
->fin_mp
== NULL
)
5932 #if defined(_KERNEL)
5933 if (fr_pullup(fin
->fin_m
, fin
, fin
->fin_plen
) == NULL
) {
5934 ATOMIC_INCL(fr_badcoalesces
[fin
->fin_out
]);
5936 FREE_MB_T(*fin
->fin_mp
);
5938 *fin
->fin_mp
= NULL
;
5943 fin
= fin
; /* LINT */
5950 * The following table lists all of the tunable variables that can be
5951 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row
5952 * in the table below is as follows:
5954 * pointer to value, name of value, minimum, maximum, size of the value's
5955 * container, value attribute flags
5957 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED
5958 * means the value can only be written to when IPFilter is loaded but disabled.
5959 * The obvious implication is if neither of these are set then the value can be
5960 * changed at any time without harm.
5962 ipftuneable_t ipf_tuneables
[] = {
5964 { { &fr_flags
}, "fr_flags", 0, 0xffffffff,
5965 sizeof(fr_flags
), 0, NULL
},
5966 { { &fr_active
}, "fr_active", 0, 0,
5967 sizeof(fr_active
), IPFT_RDONLY
, NULL
},
5968 { { &fr_control_forwarding
}, "fr_control_forwarding", 0, 1,
5969 sizeof(fr_control_forwarding
), 0, NULL
},
5970 { { &fr_update_ipid
}, "fr_update_ipid", 0, 1,
5971 sizeof(fr_update_ipid
), 0, NULL
},
5972 { { &fr_chksrc
}, "fr_chksrc", 0, 1,
5973 sizeof(fr_chksrc
), 0, NULL
},
5974 { { &fr_minttl
}, "fr_minttl", 0, 1,
5975 sizeof(fr_minttl
), 0, NULL
},
5976 { { &fr_icmpminfragmtu
}, "fr_icmpminfragmtu", 0, 1,
5977 sizeof(fr_icmpminfragmtu
), 0, NULL
},
5978 { { &fr_pass
}, "fr_pass", 0, 0xffffffff,
5979 sizeof(fr_pass
), 0, NULL
},
5981 { { &fr_tcpidletimeout
}, "fr_tcpidletimeout", 1, 0x7fffffff,
5982 sizeof(fr_tcpidletimeout
), IPFT_WRDISABLED
, NULL
},
5983 { { &fr_tcpclosewait
}, "fr_tcpclosewait", 1, 0x7fffffff,
5984 sizeof(fr_tcpclosewait
), IPFT_WRDISABLED
, NULL
},
5985 { { &fr_tcplastack
}, "fr_tcplastack", 1, 0x7fffffff,
5986 sizeof(fr_tcplastack
), IPFT_WRDISABLED
, NULL
},
5987 { { &fr_tcptimeout
}, "fr_tcptimeout", 1, 0x7fffffff,
5988 sizeof(fr_tcptimeout
), IPFT_WRDISABLED
, NULL
},
5989 { { &fr_tcpclosed
}, "fr_tcpclosed", 1, 0x7fffffff,
5990 sizeof(fr_tcpclosed
), IPFT_WRDISABLED
, NULL
},
5991 { { &fr_tcphalfclosed
}, "fr_tcphalfclosed", 1, 0x7fffffff,
5992 sizeof(fr_tcphalfclosed
), IPFT_WRDISABLED
, NULL
},
5993 { { &fr_tcptimewait
}, "fr_tcptimewait", 1, 0x7fffffff,
5994 sizeof(fr_tcptimewait
), IPFT_WRDISABLED
, NULL
},
5995 { { &fr_udptimeout
}, "fr_udptimeout", 1, 0x7fffffff,
5996 sizeof(fr_udptimeout
), IPFT_WRDISABLED
, NULL
},
5997 { { &fr_udpacktimeout
}, "fr_udpacktimeout", 1, 0x7fffffff,
5998 sizeof(fr_udpacktimeout
), IPFT_WRDISABLED
, NULL
},
5999 { { &fr_icmptimeout
}, "fr_icmptimeout", 1, 0x7fffffff,
6000 sizeof(fr_icmptimeout
), IPFT_WRDISABLED
, NULL
},
6001 { { &fr_icmpacktimeout
}, "fr_icmpacktimeout", 1, 0x7fffffff,
6002 sizeof(fr_icmpacktimeout
), IPFT_WRDISABLED
, NULL
},
6003 { { &fr_iptimeout
}, "fr_iptimeout", 1, 0x7fffffff,
6004 sizeof(fr_iptimeout
), IPFT_WRDISABLED
, NULL
},
6005 { { &fr_statemax
}, "fr_statemax", 1, 0x7fffffff,
6006 sizeof(fr_statemax
), 0, NULL
},
6007 { { &fr_statesize
}, "fr_statesize", 1, 0x7fffffff,
6008 sizeof(fr_statesize
), IPFT_WRDISABLED
, NULL
},
6009 { { &fr_state_lock
}, "fr_state_lock", 0, 1,
6010 sizeof(fr_state_lock
), IPFT_RDONLY
, NULL
},
6011 { { &fr_state_maxbucket
}, "fr_state_maxbucket", 1, 0x7fffffff,
6012 sizeof(fr_state_maxbucket
), IPFT_WRDISABLED
, NULL
},
6013 { { &fr_state_maxbucket_reset
}, "fr_state_maxbucket_reset", 0, 1,
6014 sizeof(fr_state_maxbucket_reset
), IPFT_WRDISABLED
, NULL
},
6015 { { &ipstate_logging
}, "ipstate_logging", 0, 1,
6016 sizeof(ipstate_logging
), 0, NULL
},
6018 { { &fr_nat_lock
}, "fr_nat_lock", 0, 1,
6019 sizeof(fr_nat_lock
), IPFT_RDONLY
, NULL
},
6020 { { &ipf_nattable_sz
}, "ipf_nattable_sz", 1, 0x7fffffff,
6021 sizeof(ipf_nattable_sz
), IPFT_WRDISABLED
, NULL
},
6022 { { &ipf_nattable_max
}, "ipf_nattable_max", 1, 0x7fffffff,
6023 sizeof(ipf_nattable_max
), 0, NULL
},
6024 { { &ipf_natrules_sz
}, "ipf_natrules_sz", 1, 0x7fffffff,
6025 sizeof(ipf_natrules_sz
), IPFT_WRDISABLED
, NULL
},
6026 { { &ipf_rdrrules_sz
}, "ipf_rdrrules_sz", 1, 0x7fffffff,
6027 sizeof(ipf_rdrrules_sz
), IPFT_WRDISABLED
, NULL
},
6028 { { &ipf_hostmap_sz
}, "ipf_hostmap_sz", 1, 0x7fffffff,
6029 sizeof(ipf_hostmap_sz
), IPFT_WRDISABLED
, NULL
},
6030 { { &fr_nat_maxbucket
}, "fr_nat_maxbucket", 1, 0x7fffffff,
6031 sizeof(fr_nat_maxbucket
), 0, NULL
},
6032 { { &fr_nat_maxbucket_reset
}, "fr_nat_maxbucket_reset", 0, 1,
6033 sizeof(fr_nat_maxbucket_reset
), IPFT_WRDISABLED
, NULL
},
6034 { { &nat_logging
}, "nat_logging", 0, 1,
6035 sizeof(nat_logging
), 0, NULL
},
6036 { { &fr_defnatage
}, "fr_defnatage", 1, 0x7fffffff,
6037 sizeof(fr_defnatage
), IPFT_WRDISABLED
, NULL
},
6038 { { &fr_defnatipage
}, "fr_defnatipage", 1, 0x7fffffff,
6039 sizeof(fr_defnatipage
), IPFT_WRDISABLED
, NULL
},
6040 { { &fr_defnaticmpage
}, "fr_defnaticmpage", 1, 0x7fffffff,
6041 sizeof(fr_defnaticmpage
), IPFT_WRDISABLED
, NULL
},
6042 { { &fr_nat_doflush
}, "fr_nat_doflush", 0, 1,
6043 sizeof(fr_nat_doflush
), 0, NULL
},
6045 { { &ipf_proxy_debug
}, "ipf_proxy_debug", 0, 10,
6046 sizeof(ipf_proxy_debug
), 0, 0 },
6048 { { &ipfr_size
}, "ipfr_size", 1, 0x7fffffff,
6049 sizeof(ipfr_size
), IPFT_WRDISABLED
, NULL
},
6050 { { &fr_ipfrttl
}, "fr_ipfrttl", 1, 0x7fffffff,
6051 sizeof(fr_ipfrttl
), IPFT_WRDISABLED
, NULL
},
6054 { { &ipl_suppress
}, "ipl_suppress", 0, 1,
6055 sizeof(ipl_suppress
), 0, NULL
},
6056 { { &ipl_logmax
}, "ipl_logmax", 0, 0x7fffffff,
6057 sizeof(ipl_logmax
), IPFT_WRDISABLED
, NULL
},
6058 { { &ipl_logall
}, "ipl_logall", 0, 1,
6059 sizeof(ipl_logall
), 0, NULL
},
6060 { { &ipl_logsize
}, "ipl_logsize", 0, 0x80000,
6061 sizeof(ipl_logsize
), 0, NULL
},
6063 { { NULL
}, NULL
, 0, 0,
6067 static ipftuneable_t
*ipf_tunelist
= NULL
;
6070 /* ------------------------------------------------------------------------ */
6071 /* Function: fr_findtunebycookie */
6072 /* Returns: NULL = search failed, else pointer to tune struct */
6073 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */
6074 /* next(O) - pointer to place to store the cookie for the */
6075 /* "next" tuneable, if it is desired. */
6077 /* This function is used to walk through all of the existing tunables with */
6078 /* successive calls. It searches the known tunables for the one which has */
6079 /* a matching value for "cookie" - ie its address. When returning a match, */
6080 /* the next one to be found may be returned inside next. */
6081 /* ------------------------------------------------------------------------ */
6082 static ipftuneable_t
*fr_findtunebycookie(cookie
, next
)
6083 void *cookie
, **next
;
6085 ipftuneable_t
*ta
, **tap
;
6087 for (ta
= ipf_tuneables
; ta
->ipft_name
!= NULL
; ta
++)
6091 * If the next entry in the array has a name
6092 * present, then return a pointer to it for
6093 * where to go next, else return a pointer to
6094 * the dynaminc list as a key to search there
6095 * next. This facilitates a weak linking of
6096 * the two "lists" together.
6098 if ((ta
+ 1)->ipft_name
!= NULL
)
6101 *next
= &ipf_tunelist
;
6106 for (tap
= &ipf_tunelist
; (ta
= *tap
) != NULL
; tap
= &ta
->ipft_next
)
6107 if (tap
== cookie
) {
6109 *next
= &ta
->ipft_next
;
6119 /* ------------------------------------------------------------------------ */
6120 /* Function: fr_findtunebyname */
6121 /* Returns: NULL = search failed, else pointer to tune struct */
6122 /* Parameters: name(I) - name of the tuneable entry to find. */
6124 /* Search the static array of tuneables and the list of dynamic tuneables */
6125 /* for an entry with a matching name. If we can find one, return a pointer */
6126 /* to the matching structure. */
6127 /* ------------------------------------------------------------------------ */
6128 static ipftuneable_t
*fr_findtunebyname(name
)
6133 for (ta
= ipf_tuneables
; ta
->ipft_name
!= NULL
; ta
++)
6134 if (!strcmp(ta
->ipft_name
, name
)) {
6138 for (ta
= ipf_tunelist
; ta
!= NULL
; ta
= ta
->ipft_next
)
6139 if (!strcmp(ta
->ipft_name
, name
)) {
6147 /* ------------------------------------------------------------------------ */
6148 /* Function: fr_addipftune */
6149 /* Returns: int - 0 == success, else failure */
6150 /* Parameters: newtune - pointer to new tune struct to add to tuneables */
6152 /* Appends the tune structure pointer to by "newtune" to the end of the */
6153 /* current list of "dynamic" tuneable parameters. Once added, the owner */
6154 /* of the object is not expected to ever change "ipft_next". */
6155 /* ------------------------------------------------------------------------ */
6156 int fr_addipftune(newtune
)
6157 ipftuneable_t
*newtune
;
6159 ipftuneable_t
*ta
, **tap
;
6161 ta
= fr_findtunebyname(newtune
->ipft_name
);
6165 for (tap
= &ipf_tunelist
; *tap
!= NULL
; tap
= &(*tap
)->ipft_next
)
6168 newtune
->ipft_next
= NULL
;
6174 /* ------------------------------------------------------------------------ */
6175 /* Function: fr_delipftune */
6176 /* Returns: int - 0 == success, else failure */
6177 /* Parameters: oldtune - pointer to tune struct to remove from the list of */
6178 /* current dynamic tuneables */
6180 /* Search for the tune structure, by pointer, in the list of those that are */
6181 /* dynamically added at run time. If found, adjust the list so that this */
6182 /* structure is no longer part of it. */
6183 /* ------------------------------------------------------------------------ */
6184 int fr_delipftune(oldtune
)
6185 ipftuneable_t
*oldtune
;
6187 ipftuneable_t
*ta
, **tap
;
6189 for (tap
= &ipf_tunelist
; (ta
= *tap
) != NULL
; tap
= &ta
->ipft_next
)
6190 if (ta
== oldtune
) {
6191 *tap
= oldtune
->ipft_next
;
6192 oldtune
->ipft_next
= NULL
;
6200 /* ------------------------------------------------------------------------ */
6201 /* Function: fr_ipftune */
6202 /* Returns: int - 0 == success, else failure */
6203 /* Parameters: cmd(I) - ioctl command number */
6204 /* data(I) - pointer to ioctl data structure */
6206 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */
6207 /* three ioctls provide the means to access and control global variables */
6208 /* within IPFilter, allowing (for example) timeouts and table sizes to be */
6209 /* changed without rebooting, reloading or recompiling. The initialisation */
6210 /* and 'destruction' routines of the various components of ipfilter are all */
6211 /* each responsible for handling their own values being too big. */
6212 /* ------------------------------------------------------------------------ */
6213 int fr_ipftune(cmd
, data
)
6222 error
= fr_inobj(data
, &tu
, IPFOBJ_TUNEABLE
);
6226 tu
.ipft_name
[sizeof(tu
.ipft_name
) - 1] = '\0';
6227 cookie
= tu
.ipft_cookie
;
6232 case SIOCIPFGETNEXT
:
6234 * If cookie is non-NULL, assume it to be a pointer to the last
6235 * entry we looked at, so find it (if possible) and return a
6236 * pointer to the next one after it. The last entry in the
6237 * the table is a NULL entry, so when we get to it, set cookie
6238 * to NULL and return that, indicating end of list, erstwhile
6239 * if we come in with cookie set to NULL, we are starting anew
6240 * at the front of the list.
6242 if (cookie
!= NULL
) {
6243 ta
= fr_findtunebycookie(cookie
, &tu
.ipft_cookie
);
6246 tu
.ipft_cookie
= ta
+ 1;
6250 * Entry found, but does the data pointed to by that
6251 * row fit in what we can return?
6253 if (ta
->ipft_sz
> sizeof(tu
.ipft_un
))
6257 if (ta
->ipft_sz
== sizeof(u_long
))
6258 tu
.ipft_vlong
= *ta
->ipft_plong
;
6259 else if (ta
->ipft_sz
== sizeof(u_int
))
6260 tu
.ipft_vint
= *ta
->ipft_pint
;
6261 else if (ta
->ipft_sz
== sizeof(u_short
))
6262 tu
.ipft_vshort
= *ta
->ipft_pshort
;
6263 else if (ta
->ipft_sz
== sizeof(u_char
))
6264 tu
.ipft_vchar
= *ta
->ipft_pchar
;
6266 tu
.ipft_sz
= ta
->ipft_sz
;
6267 tu
.ipft_min
= ta
->ipft_min
;
6268 tu
.ipft_max
= ta
->ipft_max
;
6269 tu
.ipft_flags
= ta
->ipft_flags
;
6270 bcopy(ta
->ipft_name
, tu
.ipft_name
,
6271 MIN(sizeof(tu
.ipft_name
),
6272 strlen(ta
->ipft_name
) + 1));
6274 error
= fr_outobj(data
, &tu
, IPFOBJ_TUNEABLE
);
6280 * Search by name or by cookie value for a particular entry
6281 * in the tuning paramter table.
6284 if (cookie
!= NULL
) {
6285 ta
= fr_findtunebycookie(cookie
, NULL
);
6288 } else if (tu
.ipft_name
[0] != '\0') {
6289 ta
= fr_findtunebyname(tu
.ipft_name
);
6296 if (cmd
== (ioctlcmd_t
)SIOCIPFGET
) {
6298 * Fetch the tuning parameters for a particular value
6301 if (ta
->ipft_sz
== sizeof(u_long
))
6302 tu
.ipft_vlong
= *ta
->ipft_plong
;
6303 else if (ta
->ipft_sz
== sizeof(u_int
))
6304 tu
.ipft_vint
= *ta
->ipft_pint
;
6305 else if (ta
->ipft_sz
== sizeof(u_short
))
6306 tu
.ipft_vshort
= *ta
->ipft_pshort
;
6307 else if (ta
->ipft_sz
== sizeof(u_char
))
6308 tu
.ipft_vchar
= *ta
->ipft_pchar
;
6309 tu
.ipft_cookie
= ta
;
6310 tu
.ipft_sz
= ta
->ipft_sz
;
6311 tu
.ipft_min
= ta
->ipft_min
;
6312 tu
.ipft_max
= ta
->ipft_max
;
6313 tu
.ipft_flags
= ta
->ipft_flags
;
6314 error
= fr_outobj(data
, &tu
, IPFOBJ_TUNEABLE
);
6316 } else if (cmd
== (ioctlcmd_t
)SIOCIPFSET
) {
6318 * Set an internal parameter. The hard part here is
6319 * getting the new value safely and correctly out of
6320 * the kernel (given we only know its size, not type.)
6324 if (((ta
->ipft_flags
& IPFT_WRDISABLED
) != 0) &&
6331 if (in
< ta
->ipft_min
|| in
> ta
->ipft_max
) {
6336 if (ta
->ipft_sz
== sizeof(u_long
)) {
6337 tu
.ipft_vlong
= *ta
->ipft_plong
;
6338 *ta
->ipft_plong
= in
;
6339 } else if (ta
->ipft_sz
== sizeof(u_int
)) {
6340 tu
.ipft_vint
= *ta
->ipft_pint
;
6341 *ta
->ipft_pint
= (u_int
)(in
& 0xffffffff);
6342 } else if (ta
->ipft_sz
== sizeof(u_short
)) {
6343 tu
.ipft_vshort
= *ta
->ipft_pshort
;
6344 *ta
->ipft_pshort
= (u_short
)(in
& 0xffff);
6345 } else if (ta
->ipft_sz
== sizeof(u_char
)) {
6346 tu
.ipft_vchar
= *ta
->ipft_pchar
;
6347 *ta
->ipft_pchar
= (u_char
)(in
& 0xff);
6349 error
= fr_outobj(data
, &tu
, IPFOBJ_TUNEABLE
);
6362 /* ------------------------------------------------------------------------ */
6363 /* Function: fr_initialise */
6364 /* Returns: int - 0 == success, < 0 == failure */
6365 /* Parameters: None. */
6367 /* Call of the initialise functions for all the various subsystems inside */
6368 /* of IPFilter. If any of them should fail, return immeadiately a failure */
6369 /* BUT do not try to recover from the error here. */
6370 /* ------------------------------------------------------------------------ */
6375 bzero(&frstats
, sizeof(frstats
));
6402 #ifdef IPFILTER_SYNC
6407 #ifdef IPFILTER_SCAN
6412 #ifdef IPFILTER_LOOKUP
6413 i
= ip_lookup_init();
6417 #ifdef IPFILTER_COMPILED
6424 /* ------------------------------------------------------------------------ */
6425 /* Function: fr_deinitialise */
6426 /* Returns: None. */
6427 /* Parameters: None. */
6429 /* Call all the various subsystem cleanup routines to deallocate memory or */
6430 /* destroy locks or whatever they've done that they need to now undo. */
6431 /* The order here IS important as there are some cross references of */
6432 /* internal data structures. */
6433 /* ------------------------------------------------------------------------ */
6434 void fr_deinitialise()
6440 #ifdef IPFILTER_SCAN
6445 #ifdef IPFILTER_COMPILED
6449 (void) frflush(IPL_LOGIPF
, 0, FR_INQUE
|FR_OUTQUE
|FR_INACTIVE
);
6450 (void) frflush(IPL_LOGIPF
, 0, FR_INQUE
|FR_OUTQUE
);
6451 (void) frflush(IPL_LOGCOUNT
, 0, FR_INQUE
|FR_OUTQUE
|FR_INACTIVE
);
6452 (void) frflush(IPL_LOGCOUNT
, 0, FR_INQUE
|FR_OUTQUE
);
6454 #ifdef IPFILTER_LOOKUP
6464 /* ------------------------------------------------------------------------ */
6465 /* Function: fr_zerostats */
6466 /* Returns: int - 0 = success, else failure */
6467 /* Parameters: data(O) - pointer to pointer for copying data back to */
6469 /* Copies the current statistics out to userspace and then zero's the */
6470 /* current ones in the kernel. The lock is only held across the bzero() as */
6471 /* the copyout may result in paging (ie network activity.) */
6472 /* ------------------------------------------------------------------------ */
6473 int fr_zerostats(data
)
6480 error
= fr_outobj(data
, &fio
, IPFOBJ_IPFSTAT
);
6484 WRITE_ENTER(&ipf_mutex
);
6485 bzero(&frstats
, sizeof(frstats
));
6486 RWLOCK_EXIT(&ipf_mutex
);
6492 /* ------------------------------------------------------------------------ */
6493 /* Function: fr_resolvedest */
6495 /* Parameters: fdp(IO) - pointer to destination information to resolve */
6496 /* v(I) - IP protocol version to match */
6498 /* Looks up an interface name in the frdest structure pointed to by fdp and */
6499 /* if a matching name can be found for the particular IP protocol version */
6500 /* then store the interface pointer in the frdest struct. If no match is */
6501 /* found, then set the interface pointer to be -1 as NULL is considered to */
6502 /* indicate there is no information at all in the structure. */
6503 /* ------------------------------------------------------------------------ */
6504 void fr_resolvedest(fdp
, v
)
6513 if (*fdp
->fd_ifname
!= '\0') {
6514 ifp
= GETIFP(fdp
->fd_ifname
, v
);
6522 /* ------------------------------------------------------------------------ */
6523 /* Function: fr_resolvenic */
6524 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */
6525 /* pointer to interface structure for NIC */
6526 /* Parameters: name(I) - complete interface name */
6527 /* v(I) - IP protocol version */
6529 /* Look for a network interface structure that firstly has a matching name */
6530 /* to that passed in and that is also being used for that IP protocol */
6531 /* version (necessary on some platforms where there are separate listings */
6532 /* for both IPv4 and IPv6 on the same physical NIC. */
6534 /* One might wonder why name gets terminated with a \0 byte in here. The */
6535 /* reason is an interface name could get into the kernel structures of ipf */
6536 /* in any number of ways and so long as they all use the same sized array */
6537 /* to put the name in, it makes sense to ensure it gets null terminated */
6538 /* before it is used for its intended purpose - finding its match in the */
6539 /* kernel's list of configured interfaces. */
6541 /* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */
6542 /* array for the name that is LIFNAMSIZ bytes (at least) in length. */
6543 /* ------------------------------------------------------------------------ */
6544 void *fr_resolvenic(char *name
, int v
)
6548 if (name
[0] == '\0')
6551 if ((name
[1] == '\0') && ((name
[0] == '-') || (name
[0] == '*'))) {
6555 name
[LIFNAMSIZ
- 1] = '\0';
6557 nic
= GETIFP(name
, v
);
6564 ipftoken_t
*ipftokenhead
= NULL
, **ipftokentail
= &ipftokenhead
;
6567 /* ------------------------------------------------------------------------ */
6568 /* Function: ipf_expiretokens */
6569 /* Returns: None. */
6570 /* Parameters: None. */
6572 /* This function is run every ipf tick to see if there are any tokens that */
6573 /* have been held for too long and need to be freed up. */
6574 /* ------------------------------------------------------------------------ */
6575 void ipf_expiretokens()
6579 WRITE_ENTER(&ipf_tokens
);
6580 while ((it
= ipftokenhead
) != NULL
) {
6581 if (it
->ipt_die
> fr_ticks
)
6586 RWLOCK_EXIT(&ipf_tokens
);
6590 /* ------------------------------------------------------------------------ */
6591 /* Function: ipf_deltoken */
6592 /* Returns: int - 0 = success, else error */
6593 /* Parameters: type(I) - the token type to match */
6594 /* uid(I) - uid owning the token */
6595 /* ptr(I) - context pointer for the token */
6597 /* This function looks for a a token in the current list that matches up */
6598 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */
6599 /* call ipf_freetoken() to remove it from the list. */
6600 /* ------------------------------------------------------------------------ */
6601 int ipf_deltoken(type
, uid
, ptr
)
6608 WRITE_ENTER(&ipf_tokens
);
6609 for (it
= ipftokenhead
; it
!= NULL
; it
= it
->ipt_next
)
6610 if (ptr
== it
->ipt_ctx
&& type
== it
->ipt_type
&&
6611 uid
== it
->ipt_uid
) {
6616 RWLOCK_EXIT(&ipf_tokens
);
6622 /* ------------------------------------------------------------------------ */
6623 /* Function: ipf_findtoken */
6624 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */
6625 /* Parameters: type(I) - the token type to match */
6626 /* uid(I) - uid owning the token */
6627 /* ptr(I) - context pointer for the token */
6629 /* This function looks for a live token in the list of current tokens that */
6630 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */
6631 /* allocated. If one is found then it is moved to the top of the list of */
6632 /* currently active tokens. */
6634 /* NOTE: It is by design that this function returns holding a read lock on */
6635 /* ipf_tokens. Callers must make sure they release it! */
6636 /* ------------------------------------------------------------------------ */
6637 ipftoken_t
*ipf_findtoken(type
, uid
, ptr
)
6641 ipftoken_t
*it
, *new;
6643 KMALLOC(new, ipftoken_t
*);
6645 WRITE_ENTER(&ipf_tokens
);
6646 for (it
= ipftokenhead
; it
!= NULL
; it
= it
->ipt_next
) {
6647 if (ptr
== it
->ipt_ctx
&& type
== it
->ipt_type
&&
6657 it
->ipt_data
= NULL
;
6660 it
->ipt_type
= type
;
6661 it
->ipt_next
= NULL
;
6669 ipf_unlinktoken(it
);
6672 it
->ipt_pnext
= ipftokentail
;
6674 ipftokentail
= &it
->ipt_next
;
6675 it
->ipt_next
= NULL
;
6677 it
->ipt_die
= fr_ticks
+ 2;
6679 RWLOCK_EXIT(&ipf_tokens
);
6685 /* ------------------------------------------------------------------------ */
6686 /* Function: ipf_unlinktoken */
6687 /* Returns: None. */
6688 /* Parameters: token(I) - pointer to token structure */
6689 /* Write Locks: ipf_tokens */
6691 /* This function unlinks a token structure from the linked list of tokens */
6692 /* that "own" it. The head pointer never needs to be explicitly adjusted */
6693 /* but the tail does due to the linked list implementation. */
6694 /* ------------------------------------------------------------------------ */
6695 static void ipf_unlinktoken(token
)
6699 if (ipftokentail
== &token
->ipt_next
)
6700 ipftokentail
= token
->ipt_pnext
;
6702 *token
->ipt_pnext
= token
->ipt_next
;
6703 if (token
->ipt_next
!= NULL
)
6704 token
->ipt_next
->ipt_pnext
= token
->ipt_pnext
;
6709 /* ------------------------------------------------------------------------ */
6710 /* Function: ipf_dereftoken */
6711 /* Returns: None. */
6712 /* Parameters: token(I) - pointer to token structure */
6713 /* Write Locks: ipf_tokens */
6715 /* Drop the reference count on the token structure and if it drops to zero, */
6716 /* call the dereference function for the token type because it is then */
6717 /* possible to free the token data structure. */
6718 /* ------------------------------------------------------------------------ */
6719 void ipf_dereftoken(token
)
6722 void *data
, **datap
;
6725 if (token
->ipt_ref
> 0)
6728 data
= token
->ipt_data
;
6731 if ((data
!= NULL
) && (data
!= (void *)-1)) {
6732 switch (token
->ipt_type
)
6734 case IPFGENITER_IPF
:
6735 (void) fr_derefrule((frentry_t
**)datap
);
6737 case IPFGENITER_IPNAT
:
6738 WRITE_ENTER(&ipf_nat
);
6739 fr_ipnatderef((ipnat_t
**)datap
);
6740 RWLOCK_EXIT(&ipf_nat
);
6742 case IPFGENITER_NAT
:
6743 fr_natderef((nat_t
**)datap
);
6745 case IPFGENITER_STATE
:
6746 fr_statederef((ipstate_t
**)datap
);
6748 case IPFGENITER_FRAG
:
6750 fr_fragderef((ipfr_t
**)datap
, &ipf_frag
);
6752 fr_fragderef((ipfr_t
**)datap
);
6755 case IPFGENITER_NATFRAG
:
6757 fr_fragderef((ipfr_t
**)datap
, &ipf_natfrag
);
6759 fr_fragderef((ipfr_t
**)datap
);
6762 case IPFGENITER_HOSTMAP
:
6763 WRITE_ENTER(&ipf_nat
);
6764 fr_hostmapdel((hostmap_t
**)datap
);
6765 RWLOCK_EXIT(&ipf_nat
);
6768 #ifdef IPFILTER_LOOKUP
6769 ip_lookup_iterderef(token
->ipt_type
, data
);
6779 /* ------------------------------------------------------------------------ */
6780 /* Function: ipf_freetoken */
6781 /* Returns: None. */
6782 /* Parameters: token(I) - pointer to token structure */
6783 /* Write Locks: ipf_tokens */
6785 /* This function unlinks a token from the linked list and does a dereference*/
6786 /* on it to encourage it to be freed. */
6787 /* ------------------------------------------------------------------------ */
6788 void ipf_freetoken(token
)
6792 ipf_unlinktoken(token
);
6794 ipf_dereftoken(token
);
6798 /* ------------------------------------------------------------------------ */
6799 /* Function: ipf_getnextrule */
6800 /* Returns: int - 0 = success, else error */
6801 /* Parameters: t(I) - pointer to destination information to resolve */
6802 /* ptr(I) - pointer to ipfobj_t to copyin from user space */
6804 /* This function's first job is to bring in the ipfruleiter_t structure via */
6805 /* the ipfobj_t structure to determine what should be the next rule to */
6806 /* return. Once the ipfruleiter_t has been brought in, it then tries to */
6807 /* find the 'next rule'. This may include searching rule group lists or */
6808 /* just be as simple as looking at the 'next' field in the rule structure. */
6809 /* When we have found the rule to return, increase its reference count and */
6810 /* if we used an existing rule to get here, decrease its reference count. */
6811 /* ------------------------------------------------------------------------ */
6812 int ipf_getnextrule(ipftoken_t
*t
, void *ptr
)
6814 frentry_t
*fr
, *next
, zero
;
6815 int error
, count
, out
;
6820 if (t
== NULL
|| ptr
== NULL
)
6822 error
= fr_inobj(ptr
, &it
, IPFOBJ_IPFITER
);
6825 if ((it
.iri_inout
< 0) || (it
.iri_inout
> 3))
6827 if ((it
.iri_active
!= 0) && (it
.iri_active
!= 1))
6829 if (it
.iri_nrules
== 0)
6831 if (it
.iri_rule
== NULL
)
6834 out
= it
.iri_inout
& F_OUT
;
6835 READ_ENTER(&ipf_mutex
);
6838 * Retrieve "previous" entry from token and find the next entry.
6842 if (*it
.iri_group
== '\0') {
6843 if ((it
.iri_inout
& F_ACIN
) != 0) {
6845 next
= ipacct
[out
][it
.iri_active
];
6847 next
= ipacct6
[out
][it
.iri_active
];
6850 next
= ipfilter
[out
][it
.iri_active
];
6852 next
= ipfilter6
[out
][it
.iri_active
];
6855 fg
= fr_findgroup(it
.iri_group
, IPL_LOGIPF
,
6856 it
.iri_active
, NULL
);
6858 next
= fg
->fg_start
;
6866 dst
= (char *)it
.iri_rule
;
6868 * The ipfruleiter may ask for more than 1 rule at a time to be
6869 * copied out, so long as that many exist in the list to start with!
6871 for (count
= it
.iri_nrules
; count
> 0; count
--) {
6873 * If we found an entry, add reference to it and update token.
6874 * Otherwise, zero out data to be returned and NULL out token.
6877 MUTEX_ENTER(&next
->fr_lock
);
6879 MUTEX_EXIT(&next
->fr_lock
);
6882 bzero(&zero
, sizeof(zero
));
6888 * Now that we have ref, it's save to give up lock.
6890 RWLOCK_EXIT(&ipf_mutex
);
6893 * Copy out data and clean up references and token as needed.
6895 error
= COPYOUT(next
, dst
, sizeof(*next
));
6898 if (t
->ipt_data
== NULL
) {
6902 (void) fr_derefrule(&fr
);
6903 if (next
->fr_data
!= NULL
) {
6904 dst
+= sizeof(*next
);
6905 error
= COPYOUT(next
->fr_data
, dst
,
6910 dst
+= next
->fr_dsize
;
6912 if (next
->fr_next
== NULL
) {
6918 if ((count
== 1) || (error
!= 0))
6921 READ_ENTER(&ipf_mutex
);
6923 next
= next
->fr_next
;
6929 /* ------------------------------------------------------------------------ */
6930 /* Function: fr_frruleiter */
6931 /* Returns: int - 0 = success, else error */
6932 /* Parameters: data(I) - the token type to match */
6933 /* uid(I) - uid owning the token */
6934 /* ptr(I) - context pointer for the token */
6936 /* This function serves as a stepping stone between fr_ipf_ioctl and */
6937 /* ipf_getnextrule. It's role is to find the right token in the kernel for */
6938 /* the process doing the ioctl and use that to ask for the next rule. */
6939 /* ------------------------------------------------------------------------ */
6940 static int ipf_frruleiter(data
, uid
, ctx
)
6947 token
= ipf_findtoken(IPFGENITER_IPF
, uid
, ctx
);
6948 if (token
!= NULL
) {
6949 error
= ipf_getnextrule(token
, data
);
6950 WRITE_ENTER(&ipf_tokens
);
6951 if (token
->ipt_data
== NULL
)
6952 ipf_freetoken(token
);
6954 ipf_dereftoken(token
);
6955 RWLOCK_EXIT(&ipf_tokens
);
6964 /* ------------------------------------------------------------------------ */
6965 /* Function: fr_geniter */
6966 /* Returns: int - 0 = success, else error */
6967 /* Parameters: token(I) - pointer to ipftoken_t structure */
6970 /* ------------------------------------------------------------------------ */
6971 static int ipf_geniter(token
, itp
)
6977 switch (itp
->igi_type
)
6979 case IPFGENITER_FRAG
:
6981 error
= fr_nextfrag(token
, itp
,
6982 &ipfr_list
, &ipfr_tail
, &ipf_frag
);
6984 error
= fr_nextfrag(token
, itp
, &ipfr_list
, &ipfr_tail
);
6996 /* ------------------------------------------------------------------------ */
6997 /* Function: fr_genericiter */
6998 /* Returns: int - 0 = success, else error */
6999 /* Parameters: data(I) - the token type to match */
7000 /* uid(I) - uid owning the token */
7001 /* ptr(I) - context pointer for the token */
7003 /* ------------------------------------------------------------------------ */
7004 int ipf_genericiter(data
, uid
, ctx
)
7012 error
= fr_inobj(data
, &iter
, IPFOBJ_GENITER
);
7016 token
= ipf_findtoken(iter
.igi_type
, uid
, ctx
);
7017 if (token
!= NULL
) {
7018 token
->ipt_subtype
= iter
.igi_type
;
7019 error
= ipf_geniter(token
, &iter
);
7020 WRITE_ENTER(&ipf_tokens
);
7021 if (token
->ipt_data
== NULL
)
7022 ipf_freetoken(token
);
7024 ipf_dereftoken(token
);
7025 RWLOCK_EXIT(&ipf_tokens
);
7028 RWLOCK_EXIT(&ipf_tokens
);
7034 /* ------------------------------------------------------------------------ */
7035 /* Function: fr_ipf_ioctl */
7036 /* Returns: int - 0 = success, else error */
7037 /* Parameters: data(I) - the token type to match */
7038 /* cmd(I) - the ioctl command number */
7039 /* mode(I) - mode flags for the ioctl */
7040 /* uid(I) - uid owning the token */
7041 /* ptr(I) - context pointer for the token */
7043 /* This function handles all of the ioctl command that are actually isssued */
7044 /* to the /dev/ipl device. */
7045 /* ------------------------------------------------------------------------ */
7046 int fr_ipf_ioctl(data
, cmd
, mode
, uid
, ctx
)
7059 if (!(mode
& FWRITE
))
7062 error
= BCOPYIN(data
, &tmp
, sizeof(tmp
));
7068 WRITE_ENTER(&ipf_global
);
7073 error
= ipfattach();
7079 error
= ipfdetach();
7083 RWLOCK_EXIT(&ipf_global
);
7088 if (!(mode
& FWRITE
)) {
7093 case SIOCIPFGETNEXT
:
7095 error
= fr_ipftune(cmd
, (void *)data
);
7099 if (!(mode
& FWRITE
))
7102 error
= BCOPYIN(data
, &fr_flags
, sizeof(fr_flags
));
7109 error
= BCOPYOUT(&fr_flags
, data
, sizeof(fr_flags
));
7115 error
= fr_resolvefunc((void *)data
);
7122 if (!(mode
& FWRITE
))
7125 error
= frrequest(IPL_LOGIPF
, cmd
, data
, fr_active
, 1);
7131 if (!(mode
& FWRITE
))
7134 error
= frrequest(IPL_LOGIPF
, cmd
, data
,
7139 if (!(mode
& FWRITE
))
7142 WRITE_ENTER(&ipf_mutex
);
7143 bzero((char *)frcache
, sizeof(frcache
[0]) * 2);
7144 error
= BCOPYOUT(&fr_active
, data
, sizeof(fr_active
));
7148 fr_active
= 1 - fr_active
;
7149 RWLOCK_EXIT(&ipf_mutex
);
7155 error
= fr_outobj((void *)data
, &fio
, IPFOBJ_IPFSTAT
);
7159 if (!(mode
& FWRITE
))
7162 error
= fr_zerostats(data
);
7166 if (!(mode
& FWRITE
))
7169 error
= BCOPYIN(data
, &tmp
, sizeof(tmp
));
7171 tmp
= frflush(IPL_LOGIPF
, 4, tmp
);
7172 error
= BCOPYOUT(&tmp
, data
, sizeof(tmp
));
7182 if (!(mode
& FWRITE
))
7185 error
= BCOPYIN(data
, &tmp
, sizeof(tmp
));
7187 tmp
= frflush(IPL_LOGIPF
, 6, tmp
);
7188 error
= BCOPYOUT(&tmp
, data
, sizeof(tmp
));
7198 error
= BCOPYIN(data
, &tmp
, sizeof(tmp
));
7200 fr_state_lock
= tmp
;
7210 if (!(mode
& FWRITE
))
7213 tmp
= ipflog_clear(IPL_LOGIPF
);
7214 error
= BCOPYOUT(&tmp
, data
, sizeof(tmp
));
7219 #endif /* IPFILTER_LOG */
7222 if (!(mode
& FWRITE
))
7225 WRITE_ENTER(&ipf_global
);
7232 RWLOCK_EXIT(&ipf_global
);
7238 error
= fr_outobj((void *)data
, fr_fragstats(),
7244 tmp
= (int)iplused
[IPL_LOGIPF
];
7246 error
= BCOPYOUT(&tmp
, data
, sizeof(tmp
));
7252 error
= ipf_frruleiter(data
, uid
, ctx
);
7258 error
= ipf_genericiter(data
, uid
, ctx
);
7262 case SIOCIPFDELTOK
:
7264 error
= BCOPYIN(data
, &tmp
, sizeof(tmp
));
7266 error
= ipf_deltoken(tmp
, uid
, ctx
);
7279 /* ------------------------------------------------------------------------ */
7280 /* Function: ipf_queueflush */
7281 /* Returns: int - number of entries flushed (0 = none) */
7282 /* Parameters: deletefn(I) - function to call to delete entry */
7283 /* ipfqs(I) - top of the list of ipf internal queues */
7284 /* userqs(I) - top of the list of user defined timeouts */
7286 /* This fucntion gets called when the state/NAT hash tables fill up and we */
7287 /* need to try a bit harder to free up some space. The algorithm used is */
7288 /* to look for the oldest entries on each timeout queue and free them if */
7289 /* they are within the given window we are considering. Where the window */
7290 /* starts and the steps taken to increase its size depend upon how long ipf */
7291 /* has been running (fr_ticks.) Anything modified in the last 30 seconds */
7292 /* is not touched. */
7294 /* die fr_ticks 30*1.5 1800*1.5 | 43200*1.5 */
7296 /* future <--+----------+--------+-----------+-----+-----+-----------> past */
7297 /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */
7299 /* Points to note: */
7300 /* - tqe_die is the time, in the future, when entries die. */
7301 /* - tqe_die - fr_ticks is how long left the connection has to live in ipf */
7303 /* - tqe_touched is when the entry was last used by NAT/state */
7304 /* - the closer tqe_touched is to fr_ticks, the further tqe_die will be for */
7305 /* any given timeout queue and vice versa. */
7306 /* - both tqe_die and tqe_touched increase over time */
7307 /* - timeout queues are sorted with the highest value of tqe_die at the */
7308 /* bottom and therefore the smallest values of each are at the top */
7310 /* We start by setting up a maximum range to scan for things to move of */
7311 /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */
7312 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */
7313 /* we start again with a new value for "iend" and "istart". The downside */
7314 /* of the current implementation is that it may return removing just 1 entry*/
7315 /* every time (pathological case) where it could remove more. */
7316 /* ------------------------------------------------------------------------ */
7317 int ipf_queueflush(deletefn
, ipfqs
, userqs
)
7318 ipftq_delete_fn_t deletefn
;
7319 ipftq_t
*ipfqs
, *userqs
;
7321 u_long interval
, istart
, iend
;
7322 ipftq_t
*ifq
, *ifqnext
;
7323 ipftqent_t
*tqe
, *tqn
;
7327 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
7328 * used then the operations are upgraded to floating point
7329 * and kernels don't like floating point...
7331 if (fr_ticks
> IPF_TTLVAL(43200 * 15 / 10)) {
7332 istart
= IPF_TTLVAL(86400 * 4);
7333 interval
= IPF_TTLVAL(43200);
7334 } else if (fr_ticks
> IPF_TTLVAL(1800 * 15 / 10)) {
7335 istart
= IPF_TTLVAL(43200);
7336 interval
= IPF_TTLVAL(1800);
7337 } else if (fr_ticks
> IPF_TTLVAL(30 * 15 / 10)) {
7338 istart
= IPF_TTLVAL(1800);
7339 interval
= IPF_TTLVAL(30);
7343 if (istart
> fr_ticks
) {
7344 if (fr_ticks
- interval
< interval
)
7347 istart
= (fr_ticks
/ interval
) * interval
;
7350 iend
= fr_ticks
- interval
;
7356 try = fr_ticks
- istart
;
7358 for (ifq
= ipfqs
; ifq
!= NULL
; ifq
= ifq
->ifq_next
) {
7359 for (tqn
= ifq
->ifq_head
; ((tqe
= tqn
) != NULL
); ) {
7360 if (try < tqe
->tqe_touched
)
7362 tqn
= tqe
->tqe_next
;
7363 if ((*deletefn
)(tqe
->tqe_parent
) == 0)
7368 for (ifq
= userqs
; ifq
!= NULL
; ifq
= ifqnext
) {
7369 ifqnext
= ifq
->ifq_next
;
7371 for (tqn
= ifq
->ifq_head
; ((tqe
= tqn
) != NULL
); ) {
7372 if (try < tqe
->tqe_touched
)
7374 tqn
= tqe
->tqe_next
;
7375 if ((*deletefn
)(tqe
->tqe_parent
) == 0)
7383 if (interval
== IPF_TTLVAL(43200)) {
7384 interval
= IPF_TTLVAL(1800);
7385 } else if (interval
== IPF_TTLVAL(1800)) {
7386 interval
= IPF_TTLVAL(30);
7390 if (interval
>= fr_ticks
)
7393 iend
= fr_ticks
- interval
;