1 
2 /*
3  * Copyright (C) 2012 by Darren Reed.
4  *
5  * See the IPFILTER.LICENCE file for details on licencing.
6  *
7  * Copyright 2008 Sun Microsystems.
8  *
9  * $Id$
10  *
11  */
12 #if defined(KERNEL) || defined(_KERNEL)
13 # undef KERNEL
14 # undef _KERNEL
15 # define        KERNEL	1
16 # define        _KERNEL	1
17 #endif
18 #include <sys/errno.h>
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/time.h>
22 #if defined(_KERNEL) && defined(__FreeBSD__)
23 #  if !defined(IPFILTER_LKM)
24 #   include "opt_inet6.h"
25 #  endif
26 # include <sys/filio.h>
27 #else
28 # include <sys/ioctl.h>
29 #endif
30 #if defined(__SVR4) || defined(sun) /* SOLARIS */
31 # include <sys/filio.h>
32 #endif
33 # include <sys/fcntl.h>
34 #if defined(_KERNEL)
35 # include <sys/systm.h>
36 # include <sys/file.h>
37 #else
38 # include <stdio.h>
39 # include <string.h>
40 # include <stdlib.h>
41 # include <stddef.h>
42 # include <sys/file.h>
43 # define _KERNEL
44 # include <sys/uio.h>
45 # undef _KERNEL
46 #endif
47 #if !defined(__SVR4)
48 # include <sys/mbuf.h>
49 #else
50 # include <sys/byteorder.h>
51 # if (SOLARIS2 < 5) && defined(sun)
52 #  include <sys/dditypes.h>
53 # endif
54 #endif
55 # include <sys/protosw.h>
56 #include <sys/socket.h>
57 #include <net/if.h>
58 #ifdef sun
59 # include <net/af.h>
60 #endif
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #include <netinet/tcp.h>
65 # include <netinet/udp.h>
66 # include <netinet/ip_icmp.h>
67 #include "netinet/ip_compat.h"
68 #ifdef	USE_INET6
69 # include <netinet/icmp6.h>
70 # if !SOLARIS && defined(_KERNEL)
71 #  include <netinet6/in6_var.h>
72 # endif
73 #endif
74 #include "netinet/ip_fil.h"
75 #include "netinet/ip_nat.h"
76 #include "netinet/ip_frag.h"
77 #include "netinet/ip_state.h"
78 #include "netinet/ip_proxy.h"
79 #include "netinet/ip_auth.h"
80 #ifdef IPFILTER_SCAN
81 # include "netinet/ip_scan.h"
82 #endif
83 #include "netinet/ip_sync.h"
84 #include "netinet/ip_lookup.h"
85 #include "netinet/ip_pool.h"
86 #include "netinet/ip_htable.h"
87 #ifdef IPFILTER_COMPILED
88 # include "netinet/ip_rules.h"
89 #endif
90 #if defined(IPFILTER_BPF) && defined(_KERNEL)
91 # include <net/bpf.h>
92 #endif
93 #if defined(__FreeBSD__)
94 # include <sys/malloc.h>
95 #endif
96 #include "netinet/ipl.h"
97 
98 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
99 # include <sys/callout.h>
100 extern struct callout ipf_slowtimer_ch;
101 #endif
102 /* END OF INCLUDES */
103 
104 #if !defined(lint)
105 static const char sccsid[] = "@(#)fil.c	1.36 6/5/96 (C) 1993-2000 Darren Reed";
106 /* static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $"; */
107 #endif
108 
109 #ifndef	_KERNEL
110 # include "ipf.h"
111 # include "ipt.h"
112 extern	int	opts;
113 extern	int	blockreason;
114 #endif /* _KERNEL */
115 
116 #define FASTROUTE_RECURSION
117 
118 #define	LBUMP(x)	softc->x++
119 #define	LBUMPD(x, y)	do { softc->x.y++; DT(y); } while (0)
120 
121 static	inline int	ipf_check_ipf(fr_info_t *, frentry_t *, int);
122 static	u_32_t		ipf_checkcipso(fr_info_t *, u_char *, int);
123 static	u_32_t		ipf_checkripso(u_char *);
124 static	u_32_t		ipf_decaps(fr_info_t *, u_32_t, int);
125 #ifdef IPFILTER_LOG
126 static	frentry_t	*ipf_dolog(fr_info_t *, u_32_t *);
127 #endif
128 static	int		ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **);
129 static	int		ipf_flush_groups(ipf_main_softc_t *, frgroup_t **,
130 					      int);
131 static	ipfunc_t	ipf_findfunc(ipfunc_t);
132 static	void		*ipf_findlookup(ipf_main_softc_t *, int, frentry_t *,
133 					     i6addr_t *, i6addr_t *);
134 static	frentry_t	*ipf_firewall(fr_info_t *, u_32_t *);
135 static	int		ipf_fr_matcharray(fr_info_t *, int *);
136 static	int		ipf_frruleiter(ipf_main_softc_t *, void *, int,
137 					    void *);
138 static	void		ipf_funcfini(ipf_main_softc_t *, frentry_t *);
139 static	int		ipf_funcinit(ipf_main_softc_t *, frentry_t *);
140 static	int		ipf_geniter(ipf_main_softc_t *, ipftoken_t *,
141 					 ipfgeniter_t *);
142 static	void		ipf_getstat(ipf_main_softc_t *,
143 					 struct friostat *, int);
144 static	int		ipf_group_flush(ipf_main_softc_t *, frgroup_t *);
145 static	void		ipf_group_free(frgroup_t *);
146 static	int		ipf_grpmapfini(struct ipf_main_softc_s *,
147 					    frentry_t *);
148 static	int		ipf_grpmapinit(struct ipf_main_softc_s *,
149 					    frentry_t *);
150 static	frentry_t	*ipf_nextrule(ipf_main_softc_t *, int, int,
151 					   frentry_t *, int);
152 static	int		ipf_portcheck(frpcmp_t *, u_32_t);
153 static	inline int	ipf_pr_ah(fr_info_t *);
154 static	inline void	ipf_pr_esp(fr_info_t *);
155 static	inline void	ipf_pr_gre(fr_info_t *);
156 static	inline void	ipf_pr_udp(fr_info_t *);
157 static	inline void	ipf_pr_tcp(fr_info_t *);
158 static	inline void	ipf_pr_icmp(fr_info_t *);
159 static	inline void	ipf_pr_ipv4hdr(fr_info_t *);
160 static	inline void	ipf_pr_short(fr_info_t *, int);
161 static	inline int	ipf_pr_tcpcommon(fr_info_t *);
162 static	inline int	ipf_pr_udpcommon(fr_info_t *);
163 static	void		ipf_rule_delete(ipf_main_softc_t *, frentry_t *f,
164 					     int, int);
165 static	void		ipf_rule_expire_insert(ipf_main_softc_t *,
166 						    frentry_t *, int);
167 static	int		ipf_synclist(ipf_main_softc_t *, frentry_t *,
168 					  void *);
169 static	void		ipf_token_flush(ipf_main_softc_t *);
170 static	void		ipf_token_unlink(ipf_main_softc_t *,
171 					      ipftoken_t *);
172 static	ipftuneable_t	*ipf_tune_findbyname(ipftuneable_t *,
173 						  const char *);
174 static	ipftuneable_t	*ipf_tune_findbycookie(ipftuneable_t **, void *,
175 						    void **);
176 static	int		ipf_updateipid(fr_info_t *);
177 static	int		ipf_settimeout(struct ipf_main_softc_s *,
178 					    struct ipftuneable *,
179 					    ipftuneval_t *);
180 #if !defined(_KERNEL) || SOLARIS
181 static	int		ppsratecheck(struct timeval *, int *, int);
182 #endif
183 
184 
185 /*
186  * bit values for identifying presence of individual IP options
187  * All of these tables should be ordered by increasing key value on the left
188  * hand side to allow for binary searching of the array and include a trailer
189  * with a 0 for the bitmask for linear searches to easily find the end with.
190  */
191 static const	struct	optlist	ipopts[] = {
192 	{ IPOPT_NOP,	0x000001 },
193 	{ IPOPT_RR,	0x000002 },
194 	{ IPOPT_ZSU,	0x000004 },
195 	{ IPOPT_MTUP,	0x000008 },
196 	{ IPOPT_MTUR,	0x000010 },
197 	{ IPOPT_ENCODE,	0x000020 },
198 	{ IPOPT_TS,	0x000040 },
199 	{ IPOPT_TR,	0x000080 },
200 	{ IPOPT_SECURITY, 0x000100 },
201 	{ IPOPT_LSRR,	0x000200 },
202 	{ IPOPT_E_SEC,	0x000400 },
203 	{ IPOPT_CIPSO,	0x000800 },
204 	{ IPOPT_SATID,	0x001000 },
205 	{ IPOPT_SSRR,	0x002000 },
206 	{ IPOPT_ADDEXT,	0x004000 },
207 	{ IPOPT_VISA,	0x008000 },
208 	{ IPOPT_IMITD,	0x010000 },
209 	{ IPOPT_EIP,	0x020000 },
210 	{ IPOPT_FINN,	0x040000 },
211 	{ 0,		0x000000 }
212 };
213 
214 #ifdef USE_INET6
215 static const struct optlist ip6exthdr[] = {
216 	{ IPPROTO_HOPOPTS,		0x000001 },
217 	{ IPPROTO_IPV6,			0x000002 },
218 	{ IPPROTO_ROUTING,		0x000004 },
219 	{ IPPROTO_FRAGMENT,		0x000008 },
220 	{ IPPROTO_ESP,			0x000010 },
221 	{ IPPROTO_AH,			0x000020 },
222 	{ IPPROTO_NONE,			0x000040 },
223 	{ IPPROTO_DSTOPTS,		0x000080 },
224 	{ IPPROTO_MOBILITY,		0x000100 },
225 	{ 0,				0 }
226 };
227 #endif
228 
229 /*
230  * bit values for identifying presence of individual IP security options
231  */
232 static const	struct	optlist	secopt[] = {
233 	{ IPSO_CLASS_RES4,	0x01 },
234 	{ IPSO_CLASS_TOPS,	0x02 },
235 	{ IPSO_CLASS_SECR,	0x04 },
236 	{ IPSO_CLASS_RES3,	0x08 },
237 	{ IPSO_CLASS_CONF,	0x10 },
238 	{ IPSO_CLASS_UNCL,	0x20 },
239 	{ IPSO_CLASS_RES2,	0x40 },
240 	{ IPSO_CLASS_RES1,	0x80 }
241 };
242 
243 char	ipfilter_version[] = IPL_VERSION;
244 
245 int	ipf_features = 0
246 #ifdef	IPFILTER_LKM
247 		| IPF_FEAT_LKM
248 #endif
249 #ifdef	IPFILTER_LOG
250 		| IPF_FEAT_LOG
251 #endif
252 		| IPF_FEAT_LOOKUP
253 #ifdef	IPFILTER_BPF
254 		| IPF_FEAT_BPF
255 #endif
256 #ifdef	IPFILTER_COMPILED
257 		| IPF_FEAT_COMPILED
258 #endif
259 #ifdef	IPFILTER_CKSUM
260 		| IPF_FEAT_CKSUM
261 #endif
262 		| IPF_FEAT_SYNC
263 #ifdef	IPFILTER_SCAN
264 		| IPF_FEAT_SCAN
265 #endif
266 #ifdef	USE_INET6
267 		| IPF_FEAT_IPV6
268 #endif
269 	;
270 
271 
272 /*
273  * Table of functions available for use with call rules.
274  */
275 static ipfunc_resolve_t ipf_availfuncs[] = {
276 	{ "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini },
277 	{ "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini },
278 	{ "",	      NULL,	      NULL,	      NULL }
279 };
280 
281 static ipftuneable_t ipf_main_tuneables[] = {
282 	{ { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) },
283 		"ipf_flags",		0,	0xffffffff,
284 		stsizeof(ipf_main_softc_t, ipf_flags),
285 		0,			NULL,	NULL },
286 	{ { (void *)offsetof(struct ipf_main_softc_s, ipf_active) },
287 		"active",		0,	0,
288 		stsizeof(ipf_main_softc_t, ipf_active),
289 		IPFT_RDONLY,		NULL,	NULL },
290 	{ { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) },
291 		"control_forwarding",	0, 1,
292 		stsizeof(ipf_main_softc_t, ipf_control_forwarding),
293 		0,			NULL,	NULL },
294 	{ { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) },
295 		"update_ipid",		0,	1,
296 		stsizeof(ipf_main_softc_t, ipf_update_ipid),
297 		0,			NULL,	NULL },
298 	{ { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) },
299 		"chksrc",		0,	1,
300 		stsizeof(ipf_main_softc_t, ipf_chksrc),
301 		0,			NULL,	NULL },
302 	{ { (void *)offsetof(ipf_main_softc_t, ipf_minttl) },
303 		"min_ttl",		0,	1,
304 		stsizeof(ipf_main_softc_t, ipf_minttl),
305 		0,			NULL,	NULL },
306 	{ { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) },
307 		"icmp_minfragmtu",	0,	1,
308 		stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu),
309 		0,			NULL,	NULL },
310 	{ { (void *)offsetof(ipf_main_softc_t, ipf_pass) },
311 		"default_pass",		0,	0xffffffff,
312 		stsizeof(ipf_main_softc_t, ipf_pass),
313 		0,			NULL,	NULL },
314 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) },
315 		"tcp_idle_timeout",	1,	0x7fffffff,
316 		stsizeof(ipf_main_softc_t, ipf_tcpidletimeout),
317 		0,			NULL,	ipf_settimeout },
318 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) },
319 		"tcp_close_wait",	1,	0x7fffffff,
320 		stsizeof(ipf_main_softc_t, ipf_tcpclosewait),
321 		0,			NULL,	ipf_settimeout },
322 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) },
323 		"tcp_last_ack",		1,	0x7fffffff,
324 		stsizeof(ipf_main_softc_t, ipf_tcplastack),
325 		0,			NULL,	ipf_settimeout },
326 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) },
327 		"tcp_timeout",		1,	0x7fffffff,
328 		stsizeof(ipf_main_softc_t, ipf_tcptimeout),
329 		0,			NULL,	ipf_settimeout },
330 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) },
331 		"tcp_syn_sent",		1,	0x7fffffff,
332 		stsizeof(ipf_main_softc_t, ipf_tcpsynsent),
333 		0,			NULL,	ipf_settimeout },
334 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) },
335 		"tcp_syn_received",	1,	0x7fffffff,
336 		stsizeof(ipf_main_softc_t, ipf_tcpsynrecv),
337 		0,			NULL,	ipf_settimeout },
338 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) },
339 		"tcp_closed",		1,	0x7fffffff,
340 		stsizeof(ipf_main_softc_t, ipf_tcpclosed),
341 		0,			NULL,	ipf_settimeout },
342 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) },
343 		"tcp_half_closed",	1,	0x7fffffff,
344 		stsizeof(ipf_main_softc_t, ipf_tcphalfclosed),
345 		0,			NULL,	ipf_settimeout },
346 	{ { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) },
347 		"tcp_time_wait",	1,	0x7fffffff,
348 		stsizeof(ipf_main_softc_t, ipf_tcptimewait),
349 		0,			NULL,	ipf_settimeout },
350 	{ { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) },
351 		"udp_timeout",		1,	0x7fffffff,
352 		stsizeof(ipf_main_softc_t, ipf_udptimeout),
353 		0,			NULL,	ipf_settimeout },
354 	{ { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) },
355 		"udp_ack_timeout",	1,	0x7fffffff,
356 		stsizeof(ipf_main_softc_t, ipf_udpacktimeout),
357 		0,			NULL,	ipf_settimeout },
358 	{ { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) },
359 		"icmp_timeout",		1,	0x7fffffff,
360 		stsizeof(ipf_main_softc_t, ipf_icmptimeout),
361 		0,			NULL,	ipf_settimeout },
362 	{ { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) },
363 		"icmp_ack_timeout",	1,	0x7fffffff,
364 		stsizeof(ipf_main_softc_t, ipf_icmpacktimeout),
365 		0,			NULL,	ipf_settimeout },
366 	{ { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) },
367 		"ip_timeout",		1,	0x7fffffff,
368 		stsizeof(ipf_main_softc_t, ipf_iptimeout),
369 		0,			NULL,	ipf_settimeout },
370 #if defined(INSTANCES) && defined(_KERNEL)
371 	{ { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) },
372 		"intercept_loopback",	0,	1,
373 		stsizeof(ipf_main_softc_t, ipf_get_loopback),
374 		0,			NULL,	ipf_set_loopback },
375 #endif
376 	{ { 0 },
377 		NULL,			0,	0,
378 		0,
379 		0,			NULL,	NULL }
380 };
381 
382 
383 /*
384  * The next section of code is a collection of small routines that set
385  * fields in the fr_info_t structure passed based on properties of the
386  * current packet.  There are different routines for the same protocol
387  * for each of IPv4 and IPv6.  Adding a new protocol, for which there
388  * will "special" inspection for setup, is now more easily done by adding
389  * a new routine and expanding the ipf_pr_ipinit*() function rather than by
390  * adding more code to a growing switch statement.
391  */
392 #ifdef USE_INET6
393 static	inline int	ipf_pr_ah6(fr_info_t *);
394 static	inline void	ipf_pr_esp6(fr_info_t *);
395 static	inline void	ipf_pr_gre6(fr_info_t *);
396 static	inline void	ipf_pr_udp6(fr_info_t *);
397 static	inline void	ipf_pr_tcp6(fr_info_t *);
398 static	inline void	ipf_pr_icmp6(fr_info_t *);
399 static	inline void	ipf_pr_ipv6hdr(fr_info_t *);
400 static	inline void	ipf_pr_short6(fr_info_t *, int);
401 static	inline int	ipf_pr_hopopts6(fr_info_t *);
402 static	inline int	ipf_pr_mobility6(fr_info_t *);
403 static	inline int	ipf_pr_routing6(fr_info_t *);
404 static	inline int	ipf_pr_dstopts6(fr_info_t *);
405 static	inline int	ipf_pr_fragment6(fr_info_t *);
406 static	inline struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int);
407 
408 
409 /* ------------------------------------------------------------------------ */
410 /* Function:    ipf_pr_short6                                               */
411 /* Returns:     void                                                        */
412 /* Parameters:  fin(I)  - pointer to packet information                     */
413 /*              xmin(I) - minimum header size                               */
414 /*                                                                          */
415 /* IPv6 Only                                                                */
416 /* This is function enforces the 'is a packet too short to be legit' rule   */
417 /* for IPv6 and marks the packet with FI_SHORT if so.  See function comment */
418 /* for ipf_pr_short() for more details.                                     */
419 /* ------------------------------------------------------------------------ */
420 static inline void
ipf_pr_short6(fr_info_t * fin,int xmin)421 ipf_pr_short6(fr_info_t *fin, int xmin)
422 {
423 
424 	if (fin->fin_dlen < xmin)
425 		fin->fin_flx |= FI_SHORT;
426 }
427 
428 
429 /* ------------------------------------------------------------------------ */
430 /* Function:    ipf_pr_ipv6hdr                                              */
431 /* Returns:     void                                                        */
432 /* Parameters:  fin(I) - pointer to packet information                      */
433 /*                                                                          */
434 /* IPv6 Only                                                                */
435 /* Copy values from the IPv6 header into the fr_info_t struct and call the  */
436 /* per-protocol analyzer if it exists.  In validating the packet, a protocol*/
437 /* analyzer may pullup or free the packet itself so we need to be vigiliant */
438 /* of that possibility arising.                                             */
439 /* ------------------------------------------------------------------------ */
440 static inline void
ipf_pr_ipv6hdr(fr_info_t * fin)441 ipf_pr_ipv6hdr(fr_info_t *fin)
442 {
443 	ip6_t *ip6 = (ip6_t *)fin->fin_ip;
444 	int p, go = 1, i, hdrcount;
445 	fr_ip_t *fi = &fin->fin_fi;
446 
447 	fin->fin_off = 0;
448 
449 	fi->fi_tos = 0;
450 	fi->fi_optmsk = 0;
451 	fi->fi_secmsk = 0;
452 	fi->fi_auth = 0;
453 
454 	p = ip6->ip6_nxt;
455 	fin->fin_crc = p;
456 	fi->fi_ttl = ip6->ip6_hlim;
457 	fi->fi_src.in6 = ip6->ip6_src;
458 	fin->fin_crc += fi->fi_src.i6[0];
459 	fin->fin_crc += fi->fi_src.i6[1];
460 	fin->fin_crc += fi->fi_src.i6[2];
461 	fin->fin_crc += fi->fi_src.i6[3];
462 	fi->fi_dst.in6 = ip6->ip6_dst;
463 	fin->fin_crc += fi->fi_dst.i6[0];
464 	fin->fin_crc += fi->fi_dst.i6[1];
465 	fin->fin_crc += fi->fi_dst.i6[2];
466 	fin->fin_crc += fi->fi_dst.i6[3];
467 	fin->fin_id = 0;
468 	if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
469 		fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
470 
471 	hdrcount = 0;
472 	while (go && !(fin->fin_flx & FI_SHORT)) {
473 		switch (p)
474 		{
475 		case IPPROTO_UDP :
476 			ipf_pr_udp6(fin);
477 			go = 0;
478 			break;
479 
480 		case IPPROTO_TCP :
481 			ipf_pr_tcp6(fin);
482 			go = 0;
483 			break;
484 
485 		case IPPROTO_ICMPV6 :
486 			ipf_pr_icmp6(fin);
487 			go = 0;
488 			break;
489 
490 		case IPPROTO_GRE :
491 			ipf_pr_gre6(fin);
492 			go = 0;
493 			break;
494 
495 		case IPPROTO_HOPOPTS :
496 			p = ipf_pr_hopopts6(fin);
497 			break;
498 
499 		case IPPROTO_MOBILITY :
500 			p = ipf_pr_mobility6(fin);
501 			break;
502 
503 		case IPPROTO_DSTOPTS :
504 			p = ipf_pr_dstopts6(fin);
505 			break;
506 
507 		case IPPROTO_ROUTING :
508 			p = ipf_pr_routing6(fin);
509 			break;
510 
511 		case IPPROTO_AH :
512 			p = ipf_pr_ah6(fin);
513 			break;
514 
515 		case IPPROTO_ESP :
516 			ipf_pr_esp6(fin);
517 			go = 0;
518 			break;
519 
520 		case IPPROTO_IPV6 :
521 			for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
522 				if (ip6exthdr[i].ol_val == p) {
523 					fin->fin_flx |= ip6exthdr[i].ol_bit;
524 					break;
525 				}
526 			go = 0;
527 			break;
528 
529 		case IPPROTO_NONE :
530 			go = 0;
531 			break;
532 
533 		case IPPROTO_FRAGMENT :
534 			p = ipf_pr_fragment6(fin);
535 			/*
536 			 * Given that the only fragments we want to let through
537 			 * (where fin_off != 0) are those where the non-first
538 			 * fragments only have data, we can safely stop looking
539 			 * at headers if this is a non-leading fragment.
540 			 */
541 			if (fin->fin_off != 0)
542 				go = 0;
543 			break;
544 
545 		default :
546 			go = 0;
547 			break;
548 		}
549 		hdrcount++;
550 
551 		/*
552 		 * It is important to note that at this point, for the
553 		 * extension headers (go != 0), the entire header may not have
554 		 * been pulled up when the code gets to this point.  This is
555 		 * only done for "go != 0" because the other header handlers
556 		 * will all pullup their complete header.  The other indicator
557 		 * of an incomplete packet is that this was just an extension
558 		 * header.
559 		 */
560 		if ((go != 0) && (p != IPPROTO_NONE) &&
561 		    (ipf_pr_pullup(fin, 0) == -1)) {
562 			p = IPPROTO_NONE;
563 			break;
564 		}
565 	}
566 
567 	/*
568 	 * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup
569 	 * and destroy whatever packet was here.  The caller of this function
570 	 * expects us to return if there is a problem with ipf_pullup.
571 	 */
572 	if (fin->fin_m == NULL) {
573 		ipf_main_softc_t *softc = fin->fin_main_soft;
574 
575 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad);
576 		return;
577 	}
578 
579 	fi->fi_p = p;
580 
581 	/*
582 	 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6().
583 	 * "go != 0" implies the above loop hasn't arrived at a layer 4 header.
584 	 */
585 	if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) {
586 		ipf_main_softc_t *softc = fin->fin_main_soft;
587 
588 		fin->fin_flx |= FI_BAD;
589 		DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go);
590 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag);
591 		LBUMP(ipf_stats[fin->fin_out].fr_v6_bad);
592 	}
593 }
594 
595 
596 /* ------------------------------------------------------------------------ */
597 /* Function:    ipf_pr_ipv6exthdr                                           */
598 /* Returns:     struct ip6_ext * - pointer to the start of the next header  */
599 /*                                 or NULL if there is a prolblem.          */
600 /* Parameters:  fin(I)      - pointer to packet information                 */
601 /*              multiple(I) - flag indicating yes/no if multiple occurances */
602 /*                            of this extension header are allowed.         */
603 /*              proto(I)    - protocol number for this extension header     */
604 /*                                                                          */
605 /* IPv6 Only                                                                */
606 /* This function embodies a number of common checks that all IPv6 extension */
607 /* headers must be subjected to.  For example, making sure the packet is    */
608 /* big enough for it to be in, checking if it is repeated and setting a     */
609 /* flag to indicate its presence.                                           */
610 /* ------------------------------------------------------------------------ */
611 static inline struct ip6_ext *
ipf_pr_ipv6exthdr(fr_info_t * fin,int multiple,int proto)612 ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto)
613 {
614 	ipf_main_softc_t *softc = fin->fin_main_soft;
615 	struct ip6_ext *hdr;
616 	u_short shift;
617 	int i;
618 
619 	fin->fin_flx |= FI_V6EXTHDR;
620 
621 				/* 8 is default length of extension hdr */
622 	if ((fin->fin_dlen - 8) < 0) {
623 		fin->fin_flx |= FI_SHORT;
624 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short);
625 		return (NULL);
626 	}
627 
628 	if (ipf_pr_pullup(fin, 8) == -1) {
629 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup);
630 		return (NULL);
631 	}
632 
633 	hdr = fin->fin_dp;
634 	switch (proto)
635 	{
636 	case IPPROTO_FRAGMENT :
637 		shift = 8;
638 		break;
639 	default :
640 		shift = 8 + (hdr->ip6e_len << 3);
641 		break;
642 	}
643 
644 	if (shift > fin->fin_dlen) {	/* Nasty extension header length? */
645 		fin->fin_flx |= FI_BAD;
646 		DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen);
647 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen);
648 		return (NULL);
649 	}
650 
651 	fin->fin_dp = (char *)fin->fin_dp + shift;
652 	fin->fin_dlen -= shift;
653 
654 	/*
655 	 * If we have seen a fragment header, do not set any flags to indicate
656 	 * the presence of this extension header as it has no impact on the
657 	 * end result until after it has been defragmented.
658 	 */
659 	if (fin->fin_flx & FI_FRAG)
660 		return (hdr);
661 
662 	for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
663 		if (ip6exthdr[i].ol_val == proto) {
664 			/*
665 			 * Most IPv6 extension headers are only allowed once.
666 			 */
667 			if ((multiple == 0) &&
668 			    ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) {
669 				fin->fin_flx |= FI_BAD;
670 				DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit));
671 			} else
672 				fin->fin_optmsk |= ip6exthdr[i].ol_bit;
673 			break;
674 		}
675 
676 	return (hdr);
677 }
678 
679 
680 /* ------------------------------------------------------------------------ */
681 /* Function:    ipf_pr_hopopts6                                             */
682 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
683 /* Parameters:  fin(I) - pointer to packet information                      */
684 /*                                                                          */
685 /* IPv6 Only                                                                */
686 /* This is function checks pending hop by hop options extension header      */
687 /* ------------------------------------------------------------------------ */
688 static inline int
ipf_pr_hopopts6(fr_info_t * fin)689 ipf_pr_hopopts6(fr_info_t *fin)
690 {
691 	struct ip6_ext *hdr;
692 
693 	hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
694 	if (hdr == NULL)
695 		return (IPPROTO_NONE);
696 	return (hdr->ip6e_nxt);
697 }
698 
699 
700 /* ------------------------------------------------------------------------ */
701 /* Function:    ipf_pr_mobility6                                            */
702 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
703 /* Parameters:  fin(I) - pointer to packet information                      */
704 /*                                                                          */
705 /* IPv6 Only                                                                */
706 /* This is function checks the IPv6 mobility extension header               */
707 /* ------------------------------------------------------------------------ */
708 static inline int
ipf_pr_mobility6(fr_info_t * fin)709 ipf_pr_mobility6(fr_info_t *fin)
710 {
711 	struct ip6_ext *hdr;
712 
713 	hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
714 	if (hdr == NULL)
715 		return (IPPROTO_NONE);
716 	return (hdr->ip6e_nxt);
717 }
718 
719 
720 /* ------------------------------------------------------------------------ */
721 /* Function:    ipf_pr_routing6                                             */
722 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
723 /* Parameters:  fin(I) - pointer to packet information                      */
724 /*                                                                          */
725 /* IPv6 Only                                                                */
726 /* This is function checks pending routing extension header                 */
727 /* ------------------------------------------------------------------------ */
728 static inline int
ipf_pr_routing6(fr_info_t * fin)729 ipf_pr_routing6(fr_info_t *fin)
730 {
731 	struct ip6_routing *hdr;
732 
733 	hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING);
734 	if (hdr == NULL)
735 		return (IPPROTO_NONE);
736 
737 	switch (hdr->ip6r_type)
738 	{
739 	case 0 :
740 		/*
741 		 * Nasty extension header length?
742 		 */
743 		if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) ||
744 		    (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) {
745 			ipf_main_softc_t *softc = fin->fin_main_soft;
746 
747 			fin->fin_flx |= FI_BAD;
748 			DT1(ipf_fi_bad_routing6, fr_info_t *, fin);
749 			LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad);
750 			return (IPPROTO_NONE);
751 		}
752 		break;
753 
754 	default :
755 		break;
756 	}
757 
758 	return (hdr->ip6r_nxt);
759 }
760 
761 
762 /* ------------------------------------------------------------------------ */
763 /* Function:    ipf_pr_fragment6                                            */
764 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
765 /* Parameters:  fin(I) - pointer to packet information                      */
766 /*                                                                          */
767 /* IPv6 Only                                                                */
768 /* Examine the IPv6 fragment header and extract fragment offset information.*/
769 /*                                                                          */
770 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */
771 /* so than in IPv4.  There are 5 cases of fragments with IPv6 that all      */
772 /* packets with a fragment header can fit into.  They are as follows:       */
773 /*                                                                          */
774 /* 1.  [IPv6][0-n EH][FH][0-n EH] (no L4HDR present)                        */
775 /* 2.  [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short)                       */
776 /* 3.  [IPV6][0-n EH][FH][L4HDR part][0-n data] (short)                     */
777 /* 4.  [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data]                          */
778 /* 5.  [IPV6][0-n EH][FH][data]                                             */
779 /*                                                                          */
780 /* IPV6 = IPv6 header, FH = Fragment Header,                                */
781 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */
782 /*                                                                          */
783 /* Packets that match 1, 2, 3 will be dropped as the only reasonable        */
784 /* scenario in which they happen is in extreme circumstances that are most  */
785 /* likely to be an indication of an attack rather than normal traffic.      */
786 /* A type 3 packet may be sent by an attacked after a type 4 packet.  There */
787 /* are two rules that can be used to guard against type 3 packets: L4       */
788 /* headers must always be in a packet that has the offset field set to 0    */
789 /* and no packet is allowed to overlay that where offset = 0.               */
790 /* ------------------------------------------------------------------------ */
791 static inline int
ipf_pr_fragment6(fr_info_t * fin)792 ipf_pr_fragment6(fr_info_t *fin)
793 {
794 	ipf_main_softc_t *softc = fin->fin_main_soft;
795 	struct ip6_frag *frag;
796 
797 	fin->fin_flx |= FI_FRAG;
798 
799 	frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT);
800 	if (frag == NULL) {
801 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad);
802 		return (IPPROTO_NONE);
803 	}
804 
805 	if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
806 		/*
807 		 * Any fragment that isn't the last fragment must have its
808 		 * length as a multiple of 8.
809 		 */
810 		if ((fin->fin_plen & 7) != 0) {
811 			fin->fin_flx |= FI_BAD;
812 			DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7));
813 		}
814 	}
815 
816 	fin->fin_fraghdr = frag;
817 	fin->fin_id = frag->ip6f_ident;
818 	fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
819 	if (fin->fin_off != 0)
820 		fin->fin_flx |= FI_FRAGBODY;
821 
822 	/*
823 	 * Jumbograms aren't handled, so the max. length is 64k
824 	 */
825 	if ((fin->fin_off << 3) + fin->fin_dlen > 65535) {
826 		  fin->fin_flx |= FI_BAD;
827 		  DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen));
828 	}
829 
830 	/*
831 	 * We don't know where the transport layer header (or whatever is next
832 	 * is), as it could be behind destination options (amongst others) so
833 	* return the fragment header as the type of packet this is.  Note that
834 	 * this effectively disables the fragment cache for > 1 protocol at a
835 	 * time.
836 	 */
837 	return (frag->ip6f_nxt);
838 }
839 
840 
841 /* ------------------------------------------------------------------------ */
842 /* Function:    ipf_pr_dstopts6                                             */
843 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
844 /* Parameters:  fin(I) - pointer to packet information                      */
845 /*                                                                          */
846 /* IPv6 Only                                                                */
847 /* This is function checks pending destination options extension header     */
848 /* ------------------------------------------------------------------------ */
849 static inline int
ipf_pr_dstopts6(fr_info_t * fin)850 ipf_pr_dstopts6(fr_info_t *fin)
851 {
852 	ipf_main_softc_t *softc = fin->fin_main_soft;
853 	struct ip6_ext *hdr;
854 
855 	hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS);
856 	if (hdr == NULL) {
857 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad);
858 		return (IPPROTO_NONE);
859 	}
860 	return (hdr->ip6e_nxt);
861 }
862 
863 
864 /* ------------------------------------------------------------------------ */
865 /* Function:    ipf_pr_icmp6                                                */
866 /* Returns:     void                                                        */
867 /* Parameters:  fin(I) - pointer to packet information                      */
868 /*                                                                          */
869 /* IPv6 Only                                                                */
870 /* This routine is mainly concerned with determining the minimum valid size */
871 /* for an ICMPv6 packet.                                                    */
872 /* ------------------------------------------------------------------------ */
873 static inline void
ipf_pr_icmp6(fr_info_t * fin)874 ipf_pr_icmp6(fr_info_t *fin)
875 {
876 	int minicmpsz = sizeof(struct icmp6_hdr);
877 	struct icmp6_hdr *icmp6;
878 
879 	if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) {
880 		ipf_main_softc_t *softc = fin->fin_main_soft;
881 
882 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup);
883 		return;
884 	}
885 
886 	if (fin->fin_dlen > 1) {
887 		ip6_t *ip6;
888 
889 		icmp6 = fin->fin_dp;
890 
891 		fin->fin_data[0] = *(u_short *)icmp6;
892 
893 		if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
894 			fin->fin_flx |= FI_ICMPQUERY;
895 
896 		switch (icmp6->icmp6_type)
897 		{
898 		case ICMP6_ECHO_REPLY :
899 		case ICMP6_ECHO_REQUEST :
900 			if (fin->fin_dlen >= 6)
901 				fin->fin_data[1] = icmp6->icmp6_id;
902 			minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
903 			break;
904 
905 		case ICMP6_DST_UNREACH :
906 		case ICMP6_PACKET_TOO_BIG :
907 		case ICMP6_TIME_EXCEEDED :
908 		case ICMP6_PARAM_PROB :
909 			fin->fin_flx |= FI_ICMPERR;
910 			minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
911 			if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
912 				break;
913 
914 			if (M_LEN(fin->fin_m) < fin->fin_plen) {
915 				if (ipf_coalesce(fin) != 1)
916 					return;
917 			}
918 
919 			if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
920 				return;
921 
922 			/*
923 			 * If the destination of this packet doesn't match the
924 			 * source of the original packet then this packet is
925 			 * not correct.
926 			 */
927 			icmp6 = fin->fin_dp;
928 			ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN);
929 			if (IP6_NEQ(&fin->fin_fi.fi_dst,
930 				    (i6addr_t *)&ip6->ip6_src)) {
931 				fin->fin_flx |= FI_BAD;
932 				DT1(ipf_fi_bad_icmp6, fr_info_t *, fin);
933 			}
934 			break;
935 		default :
936 			break;
937 		}
938 	}
939 
940 	ipf_pr_short6(fin, minicmpsz);
941 	if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) {
942 		u_char p = fin->fin_p;
943 
944 		fin->fin_p = IPPROTO_ICMPV6;
945 		ipf_checkv6sum(fin);
946 		fin->fin_p = p;
947 	}
948 }
949 
950 
951 /* ------------------------------------------------------------------------ */
952 /* Function:    ipf_pr_udp6                                                 */
953 /* Returns:     void                                                        */
954 /* Parameters:  fin(I) - pointer to packet information                      */
955 /*                                                                          */
956 /* IPv6 Only                                                                */
957 /* Analyse the packet for IPv6/UDP properties.                              */
958 /* Is not expected to be called for fragmented packets.                     */
959 /* ------------------------------------------------------------------------ */
960 static inline void
ipf_pr_udp6(fr_info_t * fin)961 ipf_pr_udp6(fr_info_t *fin)
962 {
963 
964 	if (ipf_pr_udpcommon(fin) == 0) {
965 		u_char p = fin->fin_p;
966 
967 		fin->fin_p = IPPROTO_UDP;
968 		ipf_checkv6sum(fin);
969 		fin->fin_p = p;
970 	}
971 }
972 
973 
974 /* ------------------------------------------------------------------------ */
975 /* Function:    ipf_pr_tcp6                                                 */
976 /* Returns:     void                                                        */
977 /* Parameters:  fin(I) - pointer to packet information                      */
978 /*                                                                          */
979 /* IPv6 Only                                                                */
980 /* Analyse the packet for IPv6/TCP properties.                              */
981 /* Is not expected to be called for fragmented packets.                     */
982 /* ------------------------------------------------------------------------ */
983 static inline void
ipf_pr_tcp6(fr_info_t * fin)984 ipf_pr_tcp6(fr_info_t *fin)
985 {
986 
987 	if (ipf_pr_tcpcommon(fin) == 0) {
988 		u_char p = fin->fin_p;
989 
990 		fin->fin_p = IPPROTO_TCP;
991 		ipf_checkv6sum(fin);
992 		fin->fin_p = p;
993 	}
994 }
995 
996 
997 /* ------------------------------------------------------------------------ */
998 /* Function:    ipf_pr_esp6                                                 */
999 /* Returns:     void                                                        */
1000 /* Parameters:  fin(I) - pointer to packet information                      */
1001 /*                                                                          */
1002 /* IPv6 Only                                                                */
1003 /* Analyse the packet for ESP properties.                                   */
1004 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
1005 /* even though the newer ESP packets must also have a sequence number that  */
1006 /* is 32bits as well, it is not possible(?) to determine the version from a */
1007 /* simple packet header.                                                    */
1008 /* ------------------------------------------------------------------------ */
1009 static inline void
ipf_pr_esp6(fr_info_t * fin)1010 ipf_pr_esp6(fr_info_t *fin)
1011 {
1012 
1013 	if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) {
1014 		ipf_main_softc_t *softc = fin->fin_main_soft;
1015 
1016 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup);
1017 		return;
1018 	}
1019 }
1020 
1021 
1022 /* ------------------------------------------------------------------------ */
1023 /* Function:    ipf_pr_ah6                                                  */
1024 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
1025 /* Parameters:  fin(I) - pointer to packet information                      */
1026 /*                                                                          */
1027 /* IPv6 Only                                                                */
1028 /* Analyse the packet for AH properties.                                    */
1029 /* The minimum length is taken to be the combination of all fields in the   */
1030 /* header being present and no authentication data (null algorithm used.)   */
1031 /* ------------------------------------------------------------------------ */
1032 static inline int
ipf_pr_ah6(fr_info_t * fin)1033 ipf_pr_ah6(fr_info_t *fin)
1034 {
1035 	authhdr_t *ah;
1036 
1037 	fin->fin_flx |= FI_AH;
1038 
1039 	ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
1040 	if (ah == NULL) {
1041 		ipf_main_softc_t *softc = fin->fin_main_soft;
1042 
1043 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad);
1044 		return (IPPROTO_NONE);
1045 	}
1046 
1047 	ipf_pr_short6(fin, sizeof(*ah));
1048 
1049 	/*
1050 	 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup
1051 	 * enough data to satisfy ah_next (the very first one.)
1052 	 */
1053 	return (ah->ah_next);
1054 }
1055 
1056 
1057 /* ------------------------------------------------------------------------ */
1058 /* Function:    ipf_pr_gre6                                                 */
1059 /* Returns:     void                                                        */
1060 /* Parameters:  fin(I) - pointer to packet information                      */
1061 /*                                                                          */
1062 /* Analyse the packet for GRE properties.                                   */
1063 /* ------------------------------------------------------------------------ */
1064 static inline void
ipf_pr_gre6(fr_info_t * fin)1065 ipf_pr_gre6(fr_info_t *fin)
1066 {
1067 	grehdr_t *gre;
1068 
1069 	if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
1070 		ipf_main_softc_t *softc = fin->fin_main_soft;
1071 
1072 		LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup);
1073 		return;
1074 	}
1075 
1076 	gre = fin->fin_dp;
1077 	if (GRE_REV(gre->gr_flags) == 1)
1078 		fin->fin_data[0] = gre->gr_call;
1079 }
1080 #endif	/* USE_INET6 */
1081 
1082 
1083 /* ------------------------------------------------------------------------ */
1084 /* Function:    ipf_pr_pullup                                               */
1085 /* Returns:     int     - 0 == pullup succeeded, -1 == failure              */
1086 /* Parameters:  fin(I)  - pointer to packet information                     */
1087 /*              plen(I) - length (excluding L3 header) to pullup            */
1088 /*                                                                          */
1089 /* Short inline function to cut down on code duplication to perform a call  */
1090 /* to ipf_pullup to ensure there is the required amount of data,            */
1091 /* consecutively in the packet buffer.                                      */
1092 /*                                                                          */
1093 /* This function pulls up 'extra' data at the location of fin_dp.  fin_dp   */
1094 /* points to the first byte after the complete layer 3 header, which will   */
1095 /* include all of the known extension headers for IPv6 or options for IPv4. */
1096 /*                                                                          */
1097 /* Since fr_pullup() expects the total length of bytes to be pulled up, it  */
1098 /* is necessary to add those we can already assume to be pulled up (fin_dp  */
1099 /* - fin_ip) to what is passed through.                                     */
1100 /* ------------------------------------------------------------------------ */
1101 int
ipf_pr_pullup(fr_info_t * fin,int plen)1102 ipf_pr_pullup(fr_info_t *fin, int plen)
1103 {
1104 	ipf_main_softc_t *softc = fin->fin_main_soft;
1105 
1106 	if (fin->fin_m != NULL) {
1107 		if (fin->fin_dp != NULL)
1108 			plen += (char *)fin->fin_dp -
1109 				((char *)fin->fin_ip + fin->fin_hlen);
1110 		plen += fin->fin_hlen;
1111 		if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
1112 #if defined(_KERNEL)
1113 			if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
1114 				DT1(ipf_pullup_fail, fr_info_t *, fin);
1115 				LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
1116 				fin->fin_reason = FRB_PULLUP;
1117 				fin->fin_flx |= FI_BAD;
1118 				return (-1);
1119 			}
1120 			LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
1121 #else
1122 			LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
1123 			/*
1124 			 * Fake ipf_pullup failing
1125 			 */
1126 			fin->fin_reason = FRB_PULLUP;
1127 			*fin->fin_mp = NULL;
1128 			fin->fin_m = NULL;
1129 			fin->fin_ip = NULL;
1130 			fin->fin_flx |= FI_BAD;
1131 			return (-1);
1132 #endif
1133 		}
1134 	}
1135 	return (0);
1136 }
1137 
1138 
1139 /* ------------------------------------------------------------------------ */
1140 /* Function:    ipf_pr_short                                                */
1141 /* Returns:     void                                                        */
1142 /* Parameters:  fin(I)  - pointer to packet information                     */
1143 /*              xmin(I) - minimum header size                               */
1144 /*                                                                          */
1145 /* Check if a packet is "short" as defined by xmin.  The rule we are        */
1146 /* applying here is that the packet must not be fragmented within the layer */
1147 /* 4 header.  That is, it must not be a fragment that has its offset set to */
1148 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the    */
1149 /* entire layer 4 header must be present (min).                             */
1150 /* ------------------------------------------------------------------------ */
1151 static inline void
ipf_pr_short(fr_info_t * fin,int xmin)1152 ipf_pr_short(fr_info_t *fin, int xmin)
1153 {
1154 
1155 	if (fin->fin_off == 0) {
1156 		if (fin->fin_dlen < xmin)
1157 			fin->fin_flx |= FI_SHORT;
1158 	} else if (fin->fin_off < xmin) {
1159 		fin->fin_flx |= FI_SHORT;
1160 	}
1161 }
1162 
1163 
1164 /* ------------------------------------------------------------------------ */
1165 /* Function:    ipf_pr_icmp                                                 */
1166 /* Returns:     void                                                        */
1167 /* Parameters:  fin(I) - pointer to packet information                      */
1168 /*                                                                          */
1169 /* IPv4 Only                                                                */
1170 /* Do a sanity check on the packet for ICMP (v4).  In nearly all cases,     */
1171 /* except extrememly bad packets, both type and code will be present.       */
1172 /* The expected minimum size of an ICMP packet is very much dependent on    */
1173 /* the type of it.                                                          */
1174 /*                                                                          */
1175 /* XXX - other ICMP sanity checks?                                          */
1176 /* ------------------------------------------------------------------------ */
1177 static inline void
ipf_pr_icmp(fr_info_t * fin)1178 ipf_pr_icmp(fr_info_t *fin)
1179 {
1180 	ipf_main_softc_t *softc = fin->fin_main_soft;
1181 	int minicmpsz = sizeof(struct icmp);
1182 	icmphdr_t *icmp;
1183 	ip_t *oip;
1184 
1185 	ipf_pr_short(fin, ICMPERR_ICMPHLEN);
1186 
1187 	if (fin->fin_off != 0) {
1188 		LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag);
1189 		return;
1190 	}
1191 
1192 	if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) {
1193 		LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup);
1194 		return;
1195 	}
1196 
1197 	icmp = fin->fin_dp;
1198 
1199 	fin->fin_data[0] = *(u_short *)icmp;
1200 	fin->fin_data[1] = icmp->icmp_id;
1201 
1202 	switch (icmp->icmp_type)
1203 	{
1204 	case ICMP_ECHOREPLY :
1205 	case ICMP_ECHO :
1206 	/* Router discovery messaes - RFC 1256 */
1207 	case ICMP_ROUTERADVERT :
1208 	case ICMP_ROUTERSOLICIT :
1209 		fin->fin_flx |= FI_ICMPQUERY;
1210 		minicmpsz = ICMP_MINLEN;
1211 		break;
1212 	/*
1213 	 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1214 	 * 3 * timestamp(3 * 4)
1215 	 */
1216 	case ICMP_TSTAMP :
1217 	case ICMP_TSTAMPREPLY :
1218 		fin->fin_flx |= FI_ICMPQUERY;
1219 		minicmpsz = 20;
1220 		break;
1221 	/*
1222 	 * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1223 	 * mask(4)
1224 	 */
1225 	case ICMP_IREQ :
1226 	case ICMP_IREQREPLY :
1227 	case ICMP_MASKREQ :
1228 	case ICMP_MASKREPLY :
1229 		fin->fin_flx |= FI_ICMPQUERY;
1230 		minicmpsz = 12;
1231 		break;
1232 	/*
1233 	 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
1234 	 */
1235 	case ICMP_UNREACH :
1236 #ifdef icmp_nextmtu
1237 		if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
1238 			if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) {
1239 				fin->fin_flx |= FI_BAD;
1240 				DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu);
1241 			}
1242 		}
1243 #endif
1244 		/* FALLTHROUGH */
1245 	case ICMP_SOURCEQUENCH :
1246 	case ICMP_REDIRECT :
1247 	case ICMP_TIMXCEED :
1248 	case ICMP_PARAMPROB :
1249 		fin->fin_flx |= FI_ICMPERR;
1250 		if (ipf_coalesce(fin) != 1) {
1251 			LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce);
1252 			return;
1253 		}
1254 
1255 		/*
1256 		 * ICMP error packets should not be generated for IP
1257 		 * packets that are a fragment that isn't the first
1258 		 * fragment.
1259 		 */
1260 		oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
1261 		if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) {
1262 			fin->fin_flx |= FI_BAD;
1263 			DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK));
1264 		}
1265 
1266 		/*
1267 		 * If the destination of this packet doesn't match the
1268 		 * source of the original packet then this packet is
1269 		 * not correct.
1270 		 */
1271 		if (oip->ip_src.s_addr != fin->fin_daddr) {
1272 			fin->fin_flx |= FI_BAD;
1273 			DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin);
1274 		}
1275 		break;
1276 	default :
1277 		break;
1278 	}
1279 
1280 	ipf_pr_short(fin, minicmpsz);
1281 
1282 	ipf_checkv4sum(fin);
1283 }
1284 
1285 
1286 /* ------------------------------------------------------------------------ */
1287 /* Function:    ipf_pr_tcpcommon                                            */
1288 /* Returns:     int    - 0 = header ok, 1 = bad packet, -1 = buffer error   */
1289 /* Parameters:  fin(I) - pointer to packet information                      */
1290 /*                                                                          */
1291 /* TCP header sanity checking.  Look for bad combinations of TCP flags,     */
1292 /* and make some checks with how they interact with other fields.           */
1293 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is     */
1294 /* valid and mark the packet as bad if not.                                 */
1295 /* ------------------------------------------------------------------------ */
1296 static inline int
ipf_pr_tcpcommon(fr_info_t * fin)1297 ipf_pr_tcpcommon(fr_info_t *fin)
1298 {
1299 	ipf_main_softc_t *softc = fin->fin_main_soft;
1300 	int flags, tlen;
1301 	tcphdr_t *tcp;
1302 
1303 	fin->fin_flx |= FI_TCPUDP;
1304 	if (fin->fin_off != 0) {
1305 		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag);
1306 		return (0);
1307 	}
1308 
1309 	if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) {
1310 		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
1311 		return (-1);
1312 	}
1313 
1314 	tcp = fin->fin_dp;
1315 	if (fin->fin_dlen > 3) {
1316 		fin->fin_sport = ntohs(tcp->th_sport);
1317 		fin->fin_dport = ntohs(tcp->th_dport);
1318 	}
1319 
1320 	if ((fin->fin_flx & FI_SHORT) != 0) {
1321 		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short);
1322 		return (1);
1323 	}
1324 
1325 	/*
1326 	 * Use of the TCP data offset *must* result in a value that is at
1327 	 * least the same size as the TCP header.
1328 	 */
1329 	tlen = TCP_OFF(tcp) << 2;
1330 	if (tlen < sizeof(tcphdr_t)) {
1331 		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small);
1332 		fin->fin_flx |= FI_BAD;
1333 		DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t));
1334 		return (1);
1335 	}
1336 
1337 	flags = tcp->th_flags;
1338 	fin->fin_tcpf = tcp->th_flags;
1339 
1340 	/*
1341 	 * If the urgent flag is set, then the urgent pointer must
1342 	 * also be set and vice versa.  Good TCP packets do not have
1343 	 * just one of these set.
1344 	 */
1345 	if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) {
1346 		fin->fin_flx |= FI_BAD;
1347 		DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp);
1348 #if 0
1349 	} else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) {
1350 		/*
1351 		 * Ignore this case (#if 0) as it shows up in "real"
1352 		 * traffic with bogus values in the urgent pointer field.
1353 		 */
1354 		fin->fin_flx |= FI_BAD;
1355 		DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp);
1356 #endif
1357 	} else if (((flags & (TH_SYN|TH_FIN)) != 0) &&
1358 		   ((flags & (TH_RST|TH_ACK)) == TH_RST)) {
1359 		/* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
1360 		fin->fin_flx |= FI_BAD;
1361 		DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin);
1362 #if 1
1363 	} else if (((flags & TH_SYN) != 0) &&
1364 		   ((flags & (TH_URG|TH_PUSH)) != 0)) {
1365 		/*
1366 		 * SYN with URG and PUSH set is not for normal TCP but it is
1367 		 * possible(?) with T/TCP...but who uses T/TCP?
1368 		 */
1369 		fin->fin_flx |= FI_BAD;
1370 		DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin);
1371 #endif
1372 	} else if (!(flags & TH_ACK)) {
1373 		/*
1374 		 * If the ack bit isn't set, then either the SYN or
1375 		 * RST bit must be set.  If the SYN bit is set, then
1376 		 * we expect the ACK field to be 0.  If the ACK is
1377 		 * not set and if URG, PSH or FIN are set, consdier
1378 		 * that to indicate a bad TCP packet.
1379 		 */
1380 		if ((flags == TH_SYN) && (tcp->th_ack != 0)) {
1381 			/*
1382 			 * Cisco PIX sets the ACK field to a random value.
1383 			 * In light of this, do not set FI_BAD until a patch
1384 			 * is available from Cisco to ensure that
1385 			 * interoperability between existing systems is
1386 			 * achieved.
1387 			 */
1388 			/*fin->fin_flx |= FI_BAD*/;
1389 			/*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/
1390 		} else if (!(flags & (TH_RST|TH_SYN))) {
1391 			fin->fin_flx |= FI_BAD;
1392 			DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin);
1393 		} else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) {
1394 			fin->fin_flx |= FI_BAD;
1395 			DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin);
1396 		}
1397 	}
1398 	if (fin->fin_flx & FI_BAD) {
1399 		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags);
1400 		return (1);
1401 	}
1402 
1403 	/*
1404 	 * At this point, it's not exactly clear what is to be gained by
1405 	 * marking up which TCP options are and are not present.  The one we
1406 	 * are most interested in is the TCP window scale.  This is only in
1407 	 * a SYN packet [RFC1323] so we don't need this here...?
1408 	 * Now if we were to analyse the header for passive fingerprinting,
1409 	 * then that might add some weight to adding this...
1410 	 */
1411 	if (tlen == sizeof(tcphdr_t)) {
1412 		return (0);
1413 	}
1414 
1415 	if (ipf_pr_pullup(fin, tlen) == -1) {
1416 		LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
1417 		return (-1);
1418 	}
1419 
1420 #if 0
1421 	tcp = fin->fin_dp;
1422 	ip = fin->fin_ip;
1423 	s = (u_char *)(tcp + 1);
1424 	off = IP_HL(ip) << 2;
1425 # ifdef _KERNEL
1426 	if (fin->fin_mp != NULL) {
1427 		mb_t *m = *fin->fin_mp;
1428 
1429 		if (off + tlen > M_LEN(m))
1430 			return;
1431 	}
1432 # endif
1433 	for (tlen -= (int)sizeof(*tcp); tlen > 0; ) {
1434 		opt = *s;
1435 		if (opt == '\0')
1436 			break;
1437 		else if (opt == TCPOPT_NOP)
1438 			ol = 1;
1439 		else {
1440 			if (tlen < 2)
1441 				break;
1442 			ol = (int)*(s + 1);
1443 			if (ol < 2 || ol > tlen)
1444 				break;
1445 		}
1446 
1447 		for (i = 9, mv = 4; mv >= 0; ) {
1448 			op = ipopts + i;
1449 			if (opt == (u_char)op->ol_val) {
1450 				optmsk |= op->ol_bit;
1451 				break;
1452 			}
1453 		}
1454 		tlen -= ol;
1455 		s += ol;
1456 	}
1457 #endif /* 0 */
1458 
1459 	return (0);
1460 }
1461 
1462 
1463 
1464 /* ------------------------------------------------------------------------ */
1465 /* Function:    ipf_pr_udpcommon                                            */
1466 /* Returns:     int    - 0 = header ok, 1 = bad packet                      */
1467 /* Parameters:  fin(I) - pointer to packet information                      */
1468 /*                                                                          */
1469 /* Extract the UDP source and destination ports, if present.  If compiled   */
1470 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid.          */
1471 /* ------------------------------------------------------------------------ */
1472 static inline int
ipf_pr_udpcommon(fr_info_t * fin)1473 ipf_pr_udpcommon(fr_info_t *fin)
1474 {
1475 	udphdr_t *udp;
1476 
1477 	fin->fin_flx |= FI_TCPUDP;
1478 
1479 	if (!fin->fin_off && (fin->fin_dlen > 3)) {
1480 		if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) {
1481 			ipf_main_softc_t *softc = fin->fin_main_soft;
1482 
1483 			fin->fin_flx |= FI_SHORT;
1484 			LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup);
1485 			return (1);
1486 		}
1487 
1488 		udp = fin->fin_dp;
1489 
1490 		fin->fin_sport = ntohs(udp->uh_sport);
1491 		fin->fin_dport = ntohs(udp->uh_dport);
1492 	}
1493 
1494 	return (0);
1495 }
1496 
1497 
1498 /* ------------------------------------------------------------------------ */
1499 /* Function:    ipf_pr_tcp                                                  */
1500 /* Returns:     void                                                        */
1501 /* Parameters:  fin(I) - pointer to packet information                      */
1502 /*                                                                          */
1503 /* IPv4 Only                                                                */
1504 /* Analyse the packet for IPv4/TCP properties.                              */
1505 /* ------------------------------------------------------------------------ */
1506 static inline void
ipf_pr_tcp(fr_info_t * fin)1507 ipf_pr_tcp(fr_info_t *fin)
1508 {
1509 
1510 	ipf_pr_short(fin, sizeof(tcphdr_t));
1511 
1512 	if (ipf_pr_tcpcommon(fin) == 0)
1513 		ipf_checkv4sum(fin);
1514 }
1515 
1516 
1517 /* ------------------------------------------------------------------------ */
1518 /* Function:    ipf_pr_udp                                                  */
1519 /* Returns:     void                                                        */
1520 /* Parameters:  fin(I) - pointer to packet information                      */
1521 /*                                                                          */
1522 /* IPv4 Only                                                                */
1523 /* Analyse the packet for IPv4/UDP properties.                              */
1524 /* ------------------------------------------------------------------------ */
1525 static inline void
ipf_pr_udp(fr_info_t * fin)1526 ipf_pr_udp(fr_info_t *fin)
1527 {
1528 
1529 	ipf_pr_short(fin, sizeof(udphdr_t));
1530 
1531 	if (ipf_pr_udpcommon(fin) == 0)
1532 		ipf_checkv4sum(fin);
1533 }
1534 
1535 
1536 /* ------------------------------------------------------------------------ */
1537 /* Function:    ipf_pr_esp                                                  */
1538 /* Returns:     void                                                        */
1539 /* Parameters:  fin(I) - pointer to packet information                      */
1540 /*                                                                          */
1541 /* Analyse the packet for ESP properties.                                   */
1542 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
1543 /* even though the newer ESP packets must also have a sequence number that  */
1544 /* is 32bits as well, it is not possible(?) to determine the version from a */
1545 /* simple packet header.                                                    */
1546 /* ------------------------------------------------------------------------ */
1547 static inline void
ipf_pr_esp(fr_info_t * fin)1548 ipf_pr_esp(fr_info_t *fin)
1549 {
1550 
1551 	if (fin->fin_off == 0) {
1552 		ipf_pr_short(fin, 8);
1553 		if (ipf_pr_pullup(fin, 8) == -1) {
1554 			ipf_main_softc_t *softc = fin->fin_main_soft;
1555 
1556 			LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup);
1557 		}
1558 	}
1559 }
1560 
1561 
1562 /* ------------------------------------------------------------------------ */
1563 /* Function:    ipf_pr_ah                                                   */
1564 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
1565 /* Parameters:  fin(I) - pointer to packet information                      */
1566 /*                                                                          */
1567 /* Analyse the packet for AH properties.                                    */
1568 /* The minimum length is taken to be the combination of all fields in the   */
1569 /* header being present and no authentication data (null algorithm used.)   */
1570 /* ------------------------------------------------------------------------ */
1571 static inline int
ipf_pr_ah(fr_info_t * fin)1572 ipf_pr_ah(fr_info_t *fin)
1573 {
1574 	ipf_main_softc_t *softc = fin->fin_main_soft;
1575 	authhdr_t *ah;
1576 	int len;
1577 
1578 	fin->fin_flx |= FI_AH;
1579 	ipf_pr_short(fin, sizeof(*ah));
1580 
1581 	if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) {
1582 		LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad);
1583 		return (IPPROTO_NONE);
1584 	}
1585 
1586 	if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) {
1587 		DT(fr_v4_ah_pullup_1);
1588 		LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
1589 		return (IPPROTO_NONE);
1590 	}
1591 
1592 	ah = (authhdr_t *)fin->fin_dp;
1593 
1594 	len = (ah->ah_plen + 2) << 2;
1595 	ipf_pr_short(fin, len);
1596 	if (ipf_pr_pullup(fin, len) == -1) {
1597 		DT(fr_v4_ah_pullup_2);
1598 		LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
1599 		return (IPPROTO_NONE);
1600 	}
1601 
1602 	/*
1603 	 * Adjust fin_dp and fin_dlen for skipping over the authentication
1604 	 * header.
1605 	 */
1606 	fin->fin_dp = (char *)fin->fin_dp + len;
1607 	fin->fin_dlen -= len;
1608 	return (ah->ah_next);
1609 }
1610 
1611 
1612 /* ------------------------------------------------------------------------ */
1613 /* Function:    ipf_pr_gre                                                  */
1614 /* Returns:     void                                                        */
1615 /* Parameters:  fin(I) - pointer to packet information                      */
1616 /*                                                                          */
1617 /* Analyse the packet for GRE properties.                                   */
1618 /* ------------------------------------------------------------------------ */
1619 static inline void
ipf_pr_gre(fr_info_t * fin)1620 ipf_pr_gre(fr_info_t *fin)
1621 {
1622 	ipf_main_softc_t *softc = fin->fin_main_soft;
1623 	grehdr_t *gre;
1624 
1625 	ipf_pr_short(fin, sizeof(grehdr_t));
1626 
1627 	if (fin->fin_off != 0) {
1628 		LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag);
1629 		return;
1630 	}
1631 
1632 	if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
1633 		LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup);
1634 		return;
1635 	}
1636 
1637 	gre = fin->fin_dp;
1638 	if (GRE_REV(gre->gr_flags) == 1)
1639 		fin->fin_data[0] = gre->gr_call;
1640 }
1641 
1642 
1643 /* ------------------------------------------------------------------------ */
1644 /* Function:    ipf_pr_ipv4hdr                                              */
1645 /* Returns:     void                                                        */
1646 /* Parameters:  fin(I) - pointer to packet information                      */
1647 /*                                                                          */
1648 /* IPv4 Only                                                                */
1649 /* Analyze the IPv4 header and set fields in the fr_info_t structure.       */
1650 /* Check all options present and flag their presence if any exist.          */
1651 /* ------------------------------------------------------------------------ */
1652 static inline void
ipf_pr_ipv4hdr(fr_info_t * fin)1653 ipf_pr_ipv4hdr(fr_info_t *fin)
1654 {
1655 	u_short optmsk = 0, secmsk = 0, auth = 0;
1656 	int hlen, ol, mv, p, i;
1657 	const struct optlist *op;
1658 	u_char *s, opt;
1659 	u_short off;
1660 	fr_ip_t *fi;
1661 	ip_t *ip;
1662 
1663 	fi = &fin->fin_fi;
1664 	hlen = fin->fin_hlen;
1665 
1666 	ip = fin->fin_ip;
1667 	p = ip->ip_p;
1668 	fi->fi_p = p;
1669 	fin->fin_crc = p;
1670 	fi->fi_tos = ip->ip_tos;
1671 	fin->fin_id = ntohs(ip->ip_id);
1672 	off = ntohs(ip->ip_off);
1673 
1674 	/* Get both TTL and protocol */
1675 	fi->fi_p = ip->ip_p;
1676 	fi->fi_ttl = ip->ip_ttl;
1677 
1678 	/* Zero out bits not used in IPv6 address */
1679 	fi->fi_src.i6[1] = 0;
1680 	fi->fi_src.i6[2] = 0;
1681 	fi->fi_src.i6[3] = 0;
1682 	fi->fi_dst.i6[1] = 0;
1683 	fi->fi_dst.i6[2] = 0;
1684 	fi->fi_dst.i6[3] = 0;
1685 
1686 	fi->fi_saddr = ip->ip_src.s_addr;
1687 	fin->fin_crc += fi->fi_saddr;
1688 	fi->fi_daddr = ip->ip_dst.s_addr;
1689 	fin->fin_crc += fi->fi_daddr;
1690 	if (IN_MULTICAST(ntohl(fi->fi_daddr)))
1691 		fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
1692 
1693 	/*
1694 	 * set packet attribute flags based on the offset and
1695 	 * calculate the byte offset that it represents.
1696 	 */
1697 	off &= IP_MF|IP_OFFMASK;
1698 	if (off != 0) {
1699 		int morefrag = off & IP_MF;
1700 
1701 		fi->fi_flx |= FI_FRAG;
1702 		off &= IP_OFFMASK;
1703 		if (off == 1 && p == IPPROTO_TCP) {
1704 			fin->fin_flx |= FI_SHORT;	/* RFC 3128 */
1705 			DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin);
1706 		}
1707 		if (off != 0) {
1708 			fin->fin_flx |= FI_FRAGBODY;
1709 			off <<= 3;
1710 			if ((off + fin->fin_dlen > 65535) ||
1711 			    (fin->fin_dlen == 0) ||
1712 			    ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
1713 				/*
1714 				 * The length of the packet, starting at its
1715 				 * offset cannot exceed 65535 (0xffff) as the
1716 				 * length of an IP packet is only 16 bits.
1717 				 *
1718 				 * Any fragment that isn't the last fragment
1719 				 * must have a length greater than 0 and it
1720 				 * must be an even multiple of 8.
1721 				 */
1722 				fi->fi_flx |= FI_BAD;
1723 				DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin);
1724 			}
1725 		}
1726 	}
1727 	fin->fin_off = off;
1728 
1729 	/*
1730 	 * Call per-protocol setup and checking
1731 	 */
1732 	if (p == IPPROTO_AH) {
1733 		/*
1734 		 * Treat AH differently because we expect there to be another
1735 		 * layer 4 header after it.
1736 		 */
1737 		p = ipf_pr_ah(fin);
1738 	}
1739 
1740 	switch (p)
1741 	{
1742 	case IPPROTO_UDP :
1743 		ipf_pr_udp(fin);
1744 		break;
1745 	case IPPROTO_TCP :
1746 		ipf_pr_tcp(fin);
1747 		break;
1748 	case IPPROTO_ICMP :
1749 		ipf_pr_icmp(fin);
1750 		break;
1751 	case IPPROTO_ESP :
1752 		ipf_pr_esp(fin);
1753 		break;
1754 	case IPPROTO_GRE :
1755 		ipf_pr_gre(fin);
1756 		break;
1757 	}
1758 
1759 	ip = fin->fin_ip;
1760 	if (ip == NULL)
1761 		return;
1762 
1763 	/*
1764 	 * If it is a standard IP header (no options), set the flag fields
1765 	 * which relate to options to 0.
1766 	 */
1767 	if (hlen == sizeof(*ip)) {
1768 		fi->fi_optmsk = 0;
1769 		fi->fi_secmsk = 0;
1770 		fi->fi_auth = 0;
1771 		return;
1772 	}
1773 
1774 	/*
1775 	 * So the IP header has some IP options attached.  Walk the entire
1776 	 * list of options present with this packet and set flags to indicate
1777 	 * which ones are here and which ones are not.  For the somewhat out
1778 	 * of date and obscure security classification options, set a flag to
1779 	 * represent which classification is present.
1780 	 */
1781 	fi->fi_flx |= FI_OPTIONS;
1782 
1783 	for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
1784 		opt = *s;
1785 		if (opt == '\0')
1786 			break;
1787 		else if (opt == IPOPT_NOP)
1788 			ol = 1;
1789 		else {
1790 			if (hlen < 2)
1791 				break;
1792 			ol = (int)*(s + 1);
1793 			if (ol < 2 || ol > hlen)
1794 				break;
1795 		}
1796 		for (i = 9, mv = 4; mv >= 0; ) {
1797 			op = ipopts + i;
1798 
1799 			if ((opt == (u_char)op->ol_val) && (ol > 4)) {
1800 				u_32_t doi;
1801 
1802 				switch (opt)
1803 				{
1804 				case IPOPT_SECURITY :
1805 					if (optmsk & op->ol_bit) {
1806 						fin->fin_flx |= FI_BAD;
1807 						DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit));
1808 					} else {
1809 						doi = ipf_checkripso(s);
1810 						secmsk = doi >> 16;
1811 						auth = doi & 0xffff;
1812 					}
1813 					break;
1814 
1815 				case IPOPT_CIPSO :
1816 
1817 					if (optmsk & op->ol_bit) {
1818 						fin->fin_flx |= FI_BAD;
1819 						DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit));
1820 					} else {
1821 						doi = ipf_checkcipso(fin,
1822 								     s, ol);
1823 						secmsk = doi >> 16;
1824 						auth = doi & 0xffff;
1825 					}
1826 					break;
1827 				}
1828 				optmsk |= op->ol_bit;
1829 			}
1830 
1831 			if (opt < op->ol_val)
1832 				i -= mv;
1833 			else
1834 				i += mv;
1835 			mv--;
1836 		}
1837 		hlen -= ol;
1838 		s += ol;
1839 	}
1840 
1841 	/*
1842 	 *
1843 	 */
1844 	if (auth && !(auth & 0x0100))
1845 		auth &= 0xff00;
1846 	fi->fi_optmsk = optmsk;
1847 	fi->fi_secmsk = secmsk;
1848 	fi->fi_auth = auth;
1849 }
1850 
1851 
1852 /* ------------------------------------------------------------------------ */
1853 /* Function:    ipf_checkripso                                              */
1854 /* Returns:     void                                                        */
1855 /* Parameters:  s(I)   - pointer to start of RIPSO option                   */
1856 /*                                                                          */
1857 /* ------------------------------------------------------------------------ */
1858 static u_32_t
ipf_checkripso(u_char * s)1859 ipf_checkripso(u_char *s)
1860 {
1861 	const struct optlist *sp;
1862 	u_short secmsk = 0, auth = 0;
1863 	u_char sec;
1864 	int j, m;
1865 
1866 	sec = *(s + 2);	/* classification */
1867 	for (j = 3, m = 2; m >= 0; ) {
1868 		sp = secopt + j;
1869 		if (sec == sp->ol_val) {
1870 			secmsk |= sp->ol_bit;
1871 			auth = *(s + 3);
1872 			auth *= 256;
1873 			auth += *(s + 4);
1874 			break;
1875 		}
1876 		if (sec < sp->ol_val)
1877 			j -= m;
1878 		else
1879 			j += m;
1880 		m--;
1881 	}
1882 
1883 	return (secmsk << 16) | auth;
1884 }
1885 
1886 
1887 /* ------------------------------------------------------------------------ */
1888 /* Function:    ipf_checkcipso                                              */
1889 /* Returns:     u_32_t  - 0 = failure, else the doi from the header         */
1890 /* Parameters:  fin(IO) - pointer to packet information                     */
1891 /*              s(I)    - pointer to start of CIPSO option                  */
1892 /*              ol(I)   - length of CIPSO option field                      */
1893 /*                                                                          */
1894 /* This function returns the domain of integrity (DOI) field from the CIPSO */
1895 /* header and returns that whilst also storing the highest sensitivity      */
1896 /* value found in the fr_info_t structure.                                  */
1897 /*                                                                          */
1898 /* No attempt is made to extract the category bitmaps as these are defined  */
1899 /* by the user (rather than the protocol) and can be rather numerous on the */
1900 /* end nodes.                                                               */
1901 /* ------------------------------------------------------------------------ */
1902 static u_32_t
ipf_checkcipso(fr_info_t * fin,u_char * s,int ol)1903 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol)
1904 {
1905 	ipf_main_softc_t *softc = fin->fin_main_soft;
1906 	fr_ip_t *fi;
1907 	u_32_t doi;
1908 	u_char *t, tag, tlen, sensitivity;
1909 	int len;
1910 
1911 	if (ol < 6 || ol > 40) {
1912 		LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad);
1913 		fin->fin_flx |= FI_BAD;
1914 		DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol);
1915 		return (0);
1916 	}
1917 
1918 	fi = &fin->fin_fi;
1919 	fi->fi_sensitivity = 0;
1920 	/*
1921 	 * The DOI field MUST be there.
1922 	 */
1923 	bcopy(s + 2, &doi, sizeof(doi));
1924 
1925 	t = (u_char *)s + 6;
1926 	for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) {
1927 		tag = *t;
1928 		tlen = *(t + 1);
1929 		if (tlen > len || tlen < 4 || tlen > 34) {
1930 			LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen);
1931 			fin->fin_flx |= FI_BAD;
1932 			DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen);
1933 			return (0);
1934 		}
1935 
1936 		sensitivity = 0;
1937 		/*
1938 		 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet
1939 		 * draft (16 July 1992) that has expired.
1940 		 */
1941 		if (tag == 0) {
1942 			fin->fin_flx |= FI_BAD;
1943 			DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag);
1944 			continue;
1945 		} else if (tag == 1) {
1946 			if (*(t + 2) != 0) {
1947 				fin->fin_flx |= FI_BAD;
1948 				DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2));
1949 				continue;
1950 			}
1951 			sensitivity = *(t + 3);
1952 			/* Category bitmap for categories 0-239 */
1953 
1954 		} else if (tag == 4) {
1955 			if (*(t + 2) != 0) {
1956 				fin->fin_flx |= FI_BAD;
1957 				DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2));
1958 				continue;
1959 			}
1960 			sensitivity = *(t + 3);
1961 			/* Enumerated categories, 16bits each, upto 15 */
1962 
1963 		} else if (tag == 5) {
1964 			if (*(t + 2) != 0) {
1965 				fin->fin_flx |= FI_BAD;
1966 				DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2));
1967 				continue;
1968 			}
1969 			sensitivity = *(t + 3);
1970 			/* Range of categories (2*16bits), up to 7 pairs */
1971 
1972 		} else if (tag > 127) {
1973 			/* Custom defined DOI */
1974 			;
1975 		} else {
1976 			fin->fin_flx |= FI_BAD;
1977 			DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag);
1978 			continue;
1979 		}
1980 
1981 		if (sensitivity > fi->fi_sensitivity)
1982 			fi->fi_sensitivity = sensitivity;
1983 	}
1984 
1985 	return (doi);
1986 }
1987 
1988 
1989 /* ------------------------------------------------------------------------ */
1990 /* Function:    ipf_makefrip                                                */
1991 /* Returns:     int     - 0 == packet ok, -1 == packet freed                */
1992 /* Parameters:  hlen(I) - length of IP packet header                        */
1993 /*              ip(I)   - pointer to the IP header                          */
1994 /*              fin(IO) - pointer to packet information                     */
1995 /*                                                                          */
1996 /* Compact the IP header into a structure which contains just the info.     */
1997 /* which is useful for comparing IP headers with and store this information */
1998 /* in the fr_info_t structure pointer to by fin.  At present, it is assumed */
1999 /* this function will be called with either an IPv4 or IPv6 packet.         */
2000 /* ------------------------------------------------------------------------ */
2001 int
ipf_makefrip(int hlen,ip_t * ip,fr_info_t * fin)2002 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin)
2003 {
2004 	ipf_main_softc_t *softc = fin->fin_main_soft;
2005 	int v;
2006 
2007 	fin->fin_depth = 0;
2008 	fin->fin_hlen = (u_short)hlen;
2009 	fin->fin_ip = ip;
2010 	fin->fin_rule = 0xffffffff;
2011 	fin->fin_group[0] = -1;
2012 	fin->fin_group[1] = '\0';
2013 	fin->fin_dp = (char *)ip + hlen;
2014 
2015 	v = fin->fin_v;
2016 	if (v == 4) {
2017 		fin->fin_plen = ntohs(ip->ip_len);
2018 		fin->fin_dlen = fin->fin_plen - hlen;
2019 		ipf_pr_ipv4hdr(fin);
2020 #ifdef	USE_INET6
2021 	} else if (v == 6) {
2022 		fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
2023 		fin->fin_dlen = fin->fin_plen;
2024 		fin->fin_plen += hlen;
2025 
2026 		ipf_pr_ipv6hdr(fin);
2027 #endif
2028 	}
2029 	if (fin->fin_ip == NULL) {
2030 		LBUMP(ipf_stats[fin->fin_out].fr_ip_freed);
2031 		return (-1);
2032 	}
2033 	return (0);
2034 }
2035 
2036 
2037 /* ------------------------------------------------------------------------ */
2038 /* Function:    ipf_portcheck                                               */
2039 /* Returns:     int - 1 == port matched, 0 == port match failed             */
2040 /* Parameters:  frp(I) - pointer to port check `expression'                 */
2041 /*              pop(I) - port number to evaluate                            */
2042 /*                                                                          */
2043 /* Perform a comparison of a port number against some other(s), using a     */
2044 /* structure with compare information stored in it.                         */
2045 /* ------------------------------------------------------------------------ */
2046 static inline int
ipf_portcheck(frpcmp_t * frp,u_32_t pop)2047 ipf_portcheck(frpcmp_t *frp, u_32_t pop)
2048 {
2049 	int err = 1;
2050 	u_32_t po;
2051 
2052 	po = frp->frp_port;
2053 
2054 	/*
2055 	 * Do opposite test to that required and continue if that succeeds.
2056 	 */
2057 	switch (frp->frp_cmp)
2058 	{
2059 	case FR_EQUAL :
2060 		if (pop != po) /* EQUAL */
2061 			err = 0;
2062 		break;
2063 	case FR_NEQUAL :
2064 		if (pop == po) /* NOTEQUAL */
2065 			err = 0;
2066 		break;
2067 	case FR_LESST :
2068 		if (pop >= po) /* LESSTHAN */
2069 			err = 0;
2070 		break;
2071 	case FR_GREATERT :
2072 		if (pop <= po) /* GREATERTHAN */
2073 			err = 0;
2074 		break;
2075 	case FR_LESSTE :
2076 		if (pop > po) /* LT or EQ */
2077 			err = 0;
2078 		break;
2079 	case FR_GREATERTE :
2080 		if (pop < po) /* GT or EQ */
2081 			err = 0;
2082 		break;
2083 	case FR_OUTRANGE :
2084 		if (pop >= po && pop <= frp->frp_top) /* Out of range */
2085 			err = 0;
2086 		break;
2087 	case FR_INRANGE :
2088 		if (pop <= po || pop >= frp->frp_top) /* In range */
2089 			err = 0;
2090 		break;
2091 	case FR_INCRANGE :
2092 		if (pop < po || pop > frp->frp_top) /* Inclusive range */
2093 			err = 0;
2094 		break;
2095 	default :
2096 		break;
2097 	}
2098 	return (err);
2099 }
2100 
2101 
2102 /* ------------------------------------------------------------------------ */
2103 /* Function:    ipf_tcpudpchk                                               */
2104 /* Returns:     int - 1 == protocol matched, 0 == check failed              */
2105 /* Parameters:  fda(I) - pointer to packet information                      */
2106 /*              ft(I)  - pointer to structure with comparison data          */
2107 /*                                                                          */
2108 /* Compares the current pcket (assuming it is TCP/UDP) information with a   */
2109 /* structure containing information that we want to match against.          */
2110 /* ------------------------------------------------------------------------ */
2111 int
ipf_tcpudpchk(fr_ip_t * fi,frtuc_t * ft)2112 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft)
2113 {
2114 	int err = 1;
2115 
2116 	/*
2117 	 * Both ports should *always* be in the first fragment.
2118 	 * So far, I cannot find any cases where they can not be.
2119 	 *
2120 	 * compare destination ports
2121 	 */
2122 	if (ft->ftu_dcmp)
2123 		err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]);
2124 
2125 	/*
2126 	 * compare source ports
2127 	 */
2128 	if (err && ft->ftu_scmp)
2129 		err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]);
2130 
2131 	/*
2132 	 * If we don't have all the TCP/UDP header, then how can we
2133 	 * expect to do any sort of match on it ?  If we were looking for
2134 	 * TCP flags, then NO match.  If not, then match (which should
2135 	 * satisfy the "short" class too).
2136 	 */
2137 	if (err && (fi->fi_p == IPPROTO_TCP)) {
2138 		if (fi->fi_flx & FI_SHORT)
2139 			return (!(ft->ftu_tcpf | ft->ftu_tcpfm));
2140 		/*
2141 		 * Match the flags ?  If not, abort this match.
2142 		 */
2143 		if (ft->ftu_tcpfm &&
2144 		    ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) {
2145 			FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf,
2146 				 ft->ftu_tcpfm, ft->ftu_tcpf));
2147 			err = 0;
2148 		}
2149 	}
2150 	return (err);
2151 }
2152 
2153 
2154 /* ------------------------------------------------------------------------ */
2155 /* Function:    ipf_check_ipf                                               */
2156 /* Returns:     int - 0 == match, else no match                             */
2157 /* Parameters:  fin(I)     - pointer to packet information                  */
2158 /*              fr(I)      - pointer to filter rule                         */
2159 /*              portcmp(I) - flag indicating whether to attempt matching on */
2160 /*                           TCP/UDP port data.                             */
2161 /*                                                                          */
2162 /* Check to see if a packet matches an IPFilter rule.  Checks of addresses, */
2163 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
2164 /* this function.                                                           */
2165 /* ------------------------------------------------------------------------ */
2166 static inline int
ipf_check_ipf(fr_info_t * fin,frentry_t * fr,int portcmp)2167 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp)
2168 {
2169 	u_32_t	*ld, *lm, *lip;
2170 	fripf_t *fri;
2171 	fr_ip_t *fi;
2172 	int i;
2173 
2174 	fi = &fin->fin_fi;
2175 	fri = fr->fr_ipf;
2176 	lip = (u_32_t *)fi;
2177 	lm = (u_32_t *)&fri->fri_mip;
2178 	ld = (u_32_t *)&fri->fri_ip;
2179 
2180 	/*
2181 	 * first 32 bits to check coversion:
2182 	 * IP version, TOS, TTL, protocol
2183 	 */
2184 	i = ((*lip & *lm) != *ld);
2185 	FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
2186 		   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2187 	if (i)
2188 		return (1);
2189 
2190 	/*
2191 	 * Next 32 bits is a constructed bitmask indicating which IP options
2192 	 * are present (if any) in this packet.
2193 	 */
2194 	lip++, lm++, ld++;
2195 	i = ((*lip & *lm) != *ld);
2196 	FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
2197 		   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2198 	if (i != 0)
2199 		return (1);
2200 
2201 	lip++, lm++, ld++;
2202 	/*
2203 	 * Unrolled loops (4 each, for 32 bits) for address checks.
2204 	 */
2205 	/*
2206 	 * Check the source address.
2207 	 */
2208 	if (fr->fr_satype == FRI_LOOKUP) {
2209 		i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr,
2210 				      fi->fi_v, lip, fin->fin_plen);
2211 		if (i == -1)
2212 			return (1);
2213 		lip += 3;
2214 		lm += 3;
2215 		ld += 3;
2216 	} else {
2217 		i = ((*lip & *lm) != *ld);
2218 		FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
2219 			   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2220 		if (fi->fi_v == 6) {
2221 			lip++, lm++, ld++;
2222 			i |= ((*lip & *lm) != *ld);
2223 			FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
2224 				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2225 			lip++, lm++, ld++;
2226 			i |= ((*lip & *lm) != *ld);
2227 			FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
2228 				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2229 			lip++, lm++, ld++;
2230 			i |= ((*lip & *lm) != *ld);
2231 			FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
2232 				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2233 		} else {
2234 			lip += 3;
2235 			lm += 3;
2236 			ld += 3;
2237 		}
2238 	}
2239 	i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
2240 	if (i != 0)
2241 		return (1);
2242 
2243 	/*
2244 	 * Check the destination address.
2245 	 */
2246 	lip++, lm++, ld++;
2247 	if (fr->fr_datype == FRI_LOOKUP) {
2248 		i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr,
2249 				      fi->fi_v, lip, fin->fin_plen);
2250 		if (i == -1)
2251 			return (1);
2252 		lip += 3;
2253 		lm += 3;
2254 		ld += 3;
2255 	} else {
2256 		i = ((*lip & *lm) != *ld);
2257 		FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
2258 			   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2259 		if (fi->fi_v == 6) {
2260 			lip++, lm++, ld++;
2261 			i |= ((*lip & *lm) != *ld);
2262 			FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
2263 				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2264 			lip++, lm++, ld++;
2265 			i |= ((*lip & *lm) != *ld);
2266 			FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
2267 				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2268 			lip++, lm++, ld++;
2269 			i |= ((*lip & *lm) != *ld);
2270 			FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
2271 				   ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2272 		} else {
2273 			lip += 3;
2274 			lm += 3;
2275 			ld += 3;
2276 		}
2277 	}
2278 	i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
2279 	if (i != 0)
2280 		return (1);
2281 	/*
2282 	 * IP addresses matched.  The next 32bits contains:
2283 	 * mast of old IP header security & authentication bits.
2284 	 */
2285 	lip++, lm++, ld++;
2286 	i = (*ld - (*lip & *lm));
2287 	FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
2288 
2289 	/*
2290 	 * Next we have 32 bits of packet flags.
2291 	 */
2292 	lip++, lm++, ld++;
2293 	i |= (*ld - (*lip & *lm));
2294 	FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
2295 
2296 	if (i == 0) {
2297 		/*
2298 		 * If a fragment, then only the first has what we're
2299 		 * looking for here...
2300 		 */
2301 		if (portcmp) {
2302 			if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc))
2303 				i = 1;
2304 		} else {
2305 			if (fr->fr_dcmp || fr->fr_scmp ||
2306 			    fr->fr_tcpf || fr->fr_tcpfm)
2307 				i = 1;
2308 			if (fr->fr_icmpm || fr->fr_icmp) {
2309 				if (((fi->fi_p != IPPROTO_ICMP) &&
2310 				     (fi->fi_p != IPPROTO_ICMPV6)) ||
2311 				    fin->fin_off || (fin->fin_dlen < 2))
2312 					i = 1;
2313 				else if ((fin->fin_data[0] & fr->fr_icmpm) !=
2314 					 fr->fr_icmp) {
2315 					FR_DEBUG(("i. %#x & %#x != %#x\n",
2316 						 fin->fin_data[0],
2317 						 fr->fr_icmpm, fr->fr_icmp));
2318 					i = 1;
2319 				}
2320 			}
2321 		}
2322 	}
2323 	return (i);
2324 }
2325 
2326 
2327 /* ------------------------------------------------------------------------ */
2328 /* Function:    ipf_scanlist                                                */
2329 /* Returns:     int - result flags of scanning filter list                  */
2330 /* Parameters:  fin(I) - pointer to packet information                      */
2331 /*              pass(I) - default result to return for filtering            */
2332 /*                                                                          */
2333 /* Check the input/output list of rules for a match to the current packet.  */
2334 /* If a match is found, the value of fr_flags from the rule becomes the     */
2335 /* return value and fin->fin_fr points to the matched rule.                 */
2336 /*                                                                          */
2337 /* This function may be called recursively upto 16 times (limit inbuilt.)   */
2338 /* When unwinding, it should finish up with fin_depth as 0.                 */
2339 /*                                                                          */
2340 /* Could be per interface, but this gets real nasty when you don't have,    */
2341 /* or can't easily change, the kernel source code to .                      */
2342 /* ------------------------------------------------------------------------ */
2343 int
ipf_scanlist(fr_info_t * fin,u_32_t pass)2344 ipf_scanlist(fr_info_t *fin, u_32_t pass)
2345 {
2346 	ipf_main_softc_t *softc = fin->fin_main_soft;
2347 	int rulen, portcmp, off, skip;
2348 	struct frentry *fr, *fnext;
2349 	u_32_t passt, passo;
2350 
2351 	/*
2352 	 * Do not allow nesting deeper than 16 levels.
2353 	 */
2354 	if (fin->fin_depth >= 16)
2355 		return (pass);
2356 
2357 	fr = fin->fin_fr;
2358 
2359 	/*
2360 	* If there are no rules in this list, return now.
2361 	 */
2362 	if (fr == NULL)
2363 		return (pass);
2364 
2365 	skip = 0;
2366 	portcmp = 0;
2367 	fin->fin_depth++;
2368 	fin->fin_fr = NULL;
2369 	off = fin->fin_off;
2370 
2371 	if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
2372 		portcmp = 1;
2373 
2374 	for (rulen = 0; fr; fr = fnext, rulen++) {
2375 		fnext = fr->fr_next;
2376 		if (skip != 0) {
2377 			FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags));
2378 			skip--;
2379 			continue;
2380 		}
2381 
2382 		/*
2383 		 * In all checks below, a null (zero) value in the
2384 		 * filter struture is taken to mean a wildcard.
2385 		 *
2386 		 * check that we are working for the right interface
2387 		 */
2388 #ifdef	_KERNEL
2389 		if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
2390 			continue;
2391 #else
2392 		if (opts & (OPT_VERBOSE|OPT_DEBUG))
2393 			printf("\n");
2394 		FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' :
2395 				  FR_ISPASS(pass) ? 'p' :
2396 				  FR_ISACCOUNT(pass) ? 'A' :
2397 				  FR_ISAUTH(pass) ? 'a' :
2398 				  (pass & FR_NOMATCH) ? 'n' :'b'));
2399 		if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
2400 			continue;
2401 		FR_VERBOSE((":i"));
2402 #endif
2403 
2404 		switch (fr->fr_type)
2405 		{
2406 		case FR_T_IPF :
2407 		case FR_T_IPF_BUILTIN :
2408 			if (ipf_check_ipf(fin, fr, portcmp))
2409 				continue;
2410 			break;
2411 #if defined(IPFILTER_BPF)
2412 		case FR_T_BPFOPC :
2413 		case FR_T_BPFOPC_BUILTIN :
2414 		    {
2415 			u_char *mc;
2416 			int wlen;
2417 
2418 			if (*fin->fin_mp == NULL)
2419 				continue;
2420 			if (fin->fin_family != fr->fr_family)
2421 				continue;
2422 			mc = (u_char *)fin->fin_m;
2423 			wlen = fin->fin_dlen + fin->fin_hlen;
2424 			if (!bpf_filter(fr->fr_data, mc, wlen, 0))
2425 				continue;
2426 			break;
2427 		    }
2428 #endif
2429 		case FR_T_CALLFUNC_BUILTIN :
2430 		    {
2431 			frentry_t *f;
2432 
2433 			f = (*fr->fr_func)(fin, &pass);
2434 			if (f != NULL)
2435 				fr = f;
2436 			else
2437 				continue;
2438 			break;
2439 		    }
2440 
2441 		case FR_T_IPFEXPR :
2442 		case FR_T_IPFEXPR_BUILTIN :
2443 			if (fin->fin_family != fr->fr_family)
2444 				continue;
2445 			if (ipf_fr_matcharray(fin, fr->fr_data) == 0)
2446 				continue;
2447 			break;
2448 
2449 		default :
2450 			break;
2451 		}
2452 
2453 		if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
2454 			if (fin->fin_nattag == NULL)
2455 				continue;
2456 			if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
2457 				continue;
2458 		}
2459 		FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen));
2460 
2461 		passt = fr->fr_flags;
2462 
2463 		/*
2464 		 * If the rule is a "call now" rule, then call the function
2465 		 * in the rule, if it exists and use the results from that.
2466 		 * If the function pointer is bad, just make like we ignore
2467 		 * it, except for increasing the hit counter.
2468 		 */
2469 		if ((passt & FR_CALLNOW) != 0) {
2470 			frentry_t *frs;
2471 
2472 			ATOMIC_INC64(fr->fr_hits);
2473 			if ((fr->fr_func == NULL) ||
2474 			    (fr->fr_func == (ipfunc_t)-1))
2475 				continue;
2476 
2477 			frs = fin->fin_fr;
2478 			fin->fin_fr = fr;
2479 			fr = (*fr->fr_func)(fin, &passt);
2480 			if (fr == NULL) {
2481 				fin->fin_fr = frs;
2482 				continue;
2483 			}
2484 			passt = fr->fr_flags;
2485 		}
2486 		fin->fin_fr = fr;
2487 
2488 #ifdef  IPFILTER_LOG
2489 		/*
2490 		 * Just log this packet...
2491 		 */
2492 		if ((passt & FR_LOGMASK) == FR_LOG) {
2493 			if (ipf_log_pkt(fin, passt) == -1) {
2494 				if (passt & FR_LOGORBLOCK) {
2495 					DT(frb_logfail);
2496 					passt &= ~FR_CMDMASK;
2497 					passt |= FR_BLOCK|FR_QUICK;
2498 					fin->fin_reason = FRB_LOGFAIL;
2499 				}
2500 			}
2501 		}
2502 #endif /* IPFILTER_LOG */
2503 
2504 		MUTEX_ENTER(&fr->fr_lock);
2505 		fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
2506 		fr->fr_hits++;
2507 		MUTEX_EXIT(&fr->fr_lock);
2508 		fin->fin_rule = rulen;
2509 
2510 		passo = pass;
2511 		if (FR_ISSKIP(passt)) {
2512 			skip = fr->fr_arg;
2513 			continue;
2514 		} else if (((passt & FR_LOGMASK) != FR_LOG) &&
2515 			   ((passt & FR_LOGMASK) != FR_DECAPSULATE)) {
2516 			pass = passt;
2517 		}
2518 
2519 		if (passt & (FR_RETICMP|FR_FAKEICMP))
2520 			fin->fin_icode = fr->fr_icode;
2521 
2522 		if (fr->fr_group != -1) {
2523 			(void) strncpy(fin->fin_group,
2524 				       FR_NAME(fr, fr_group),
2525 				       strlen(FR_NAME(fr, fr_group)));
2526 		} else {
2527 			fin->fin_group[0] = '\0';
2528 		}
2529 
2530 		FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt));
2531 
2532 		if (fr->fr_grphead != NULL) {
2533 			fin->fin_fr = fr->fr_grphead->fg_start;
2534 			FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead)));
2535 
2536 			if (FR_ISDECAPS(passt))
2537 				passt = ipf_decaps(fin, pass, fr->fr_icode);
2538 			else
2539 				passt = ipf_scanlist(fin, pass);
2540 
2541 			if (fin->fin_fr == NULL) {
2542 				fin->fin_rule = rulen;
2543 				if (fr->fr_group != -1)
2544 					(void) strncpy(fin->fin_group,
2545 						       fr->fr_names +
2546 						       fr->fr_group,
2547 						       strlen(fr->fr_names +
2548 							      fr->fr_group));
2549 				fin->fin_fr = fr;
2550 				passt = pass;
2551 			}
2552 			pass = passt;
2553 		}
2554 
2555 		if (pass & FR_QUICK) {
2556 			/*
2557 			 * Finally, if we've asked to track state for this
2558 			 * packet, set it up.  Add state for "quick" rules
2559 			 * here so that if the action fails we can consider
2560 			 * the rule to "not match" and keep on processing
2561 			 * filter rules.
2562 			 */
2563 			if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) &&
2564 			    !(fin->fin_flx & FI_STATE)) {
2565 				int out = fin->fin_out;
2566 
2567 				fin->fin_fr = fr;
2568 				if (ipf_state_add(softc, fin, NULL, 0) == 0) {
2569 					LBUMPD(ipf_stats[out], fr_ads);
2570 				} else {
2571 					LBUMPD(ipf_stats[out], fr_bads);
2572 					pass = passo;
2573 					continue;
2574 				}
2575 			}
2576 			break;
2577 		}
2578 	}
2579 	fin->fin_depth--;
2580 	return (pass);
2581 }
2582 
2583 
2584 /* ------------------------------------------------------------------------ */
2585 /* Function:    ipf_acctpkt                                                 */
2586 /* Returns:     frentry_t* - always returns NULL                            */
2587 /* Parameters:  fin(I) - pointer to packet information                      */
2588 /*              passp(IO) - pointer to current/new filter decision (unused) */
2589 /*                                                                          */
2590 /* Checks a packet against accounting rules, if there are any for the given */
2591 /* IP protocol version.                                                     */
2592 /*                                                                          */
2593 /* N.B.: this function returns NULL to match the prototype used by other    */
2594 /* functions called from the IPFilter "mainline" in ipf_check().            */
2595 /* ------------------------------------------------------------------------ */
2596 frentry_t *
ipf_acctpkt(fr_info_t * fin,u_32_t * passp)2597 ipf_acctpkt(fr_info_t *fin, u_32_t *passp)
2598 {
2599 	ipf_main_softc_t *softc = fin->fin_main_soft;
2600 	char group[FR_GROUPLEN];
2601 	frentry_t *fr, *frsave;
2602 	u_32_t pass, rulen;
2603 
2604 	passp = passp;
2605 	fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
2606 
2607 	if (fr != NULL) {
2608 		frsave = fin->fin_fr;
2609 		bcopy(fin->fin_group, group, FR_GROUPLEN);
2610 		rulen = fin->fin_rule;
2611 		fin->fin_fr = fr;
2612 		pass = ipf_scanlist(fin, FR_NOMATCH);
2613 		if (FR_ISACCOUNT(pass)) {
2614 			LBUMPD(ipf_stats[0], fr_acct);
2615 		}
2616 		fin->fin_fr = frsave;
2617 		bcopy(group, fin->fin_group, FR_GROUPLEN);
2618 		fin->fin_rule = rulen;
2619 	}
2620 	return (NULL);
2621 }
2622 
2623 
2624 /* ------------------------------------------------------------------------ */
2625 /* Function:    ipf_firewall                                                */
2626 /* Returns:     frentry_t* - returns pointer to matched rule, if no matches */
2627 /*                           were found, returns NULL.                      */
2628 /* Parameters:  fin(I) - pointer to packet information                      */
2629 /*              passp(IO) - pointer to current/new filter decision (unused) */
2630 /*                                                                          */
2631 /* Applies an appropriate set of firewall rules to the packet, to see if    */
2632 /* there are any matches.  The first check is to see if a match can be seen */
2633 /* in the cache.  If not, then search an appropriate list of rules.  Once a */
2634 /* matching rule is found, take any appropriate actions as defined by the   */
2635 /* rule - except logging.                                                   */
2636 /* ------------------------------------------------------------------------ */
2637 static frentry_t *
ipf_firewall(fr_info_t * fin,u_32_t * passp)2638 ipf_firewall(fr_info_t *fin, u_32_t *passp)
2639 {
2640 	ipf_main_softc_t *softc = fin->fin_main_soft;
2641 	frentry_t *fr;
2642 	u_32_t pass;
2643 	int out;
2644 
2645 	out = fin->fin_out;
2646 	pass = *passp;
2647 
2648 	/*
2649 	 * This rule cache will only affect packets that are not being
2650 	 * statefully filtered.
2651 	 */
2652 	fin->fin_fr = softc->ipf_rules[out][softc->ipf_active];
2653 	if (fin->fin_fr != NULL)
2654 		pass = ipf_scanlist(fin, softc->ipf_pass);
2655 
2656 	if ((pass & FR_NOMATCH)) {
2657 		LBUMPD(ipf_stats[out], fr_nom);
2658 	}
2659 	fr = fin->fin_fr;
2660 
2661 	/*
2662 	 * Apply packets per second rate-limiting to a rule as required.
2663 	 */
2664 	if ((fr != NULL) && (fr->fr_pps != 0) &&
2665 	    !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
2666 		DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr);
2667 		pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST);
2668 		pass |= FR_BLOCK;
2669 		LBUMPD(ipf_stats[out], fr_ppshit);
2670 		fin->fin_reason = FRB_PPSRATE;
2671 	}
2672 
2673 	/*
2674 	 * If we fail to add a packet to the authorization queue, then we
2675 	 * drop the packet later.  However, if it was added then pretend
2676 	 * we've dropped it already.
2677 	 */
2678 	if (FR_ISAUTH(pass)) {
2679 		if (ipf_auth_new(fin->fin_m, fin) != 0) {
2680 			DT1(frb_authnew, fr_info_t *, fin);
2681 			fin->fin_m = *fin->fin_mp = NULL;
2682 			fin->fin_reason = FRB_AUTHNEW;
2683 			fin->fin_error = 0;
2684 		} else {
2685 			IPFERROR(1);
2686 			fin->fin_error = ENOSPC;
2687 		}
2688 	}
2689 
2690 	if ((fr != NULL) && (fr->fr_func != NULL) &&
2691 	    (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW))
2692 		(void) (*fr->fr_func)(fin, &pass);
2693 
2694 	/*
2695 	 * If a rule is a pre-auth rule, check again in the list of rules
2696 	 * loaded for authenticated use.  It does not particulary matter
2697 	 * if this search fails because a "preauth" result, from a rule,
2698 	 * is treated as "not a pass", hence the packet is blocked.
2699 	 */
2700 	if (FR_ISPREAUTH(pass)) {
2701 		pass = ipf_auth_pre_scanlist(softc, fin, pass);
2702 	}
2703 
2704 	/*
2705 	 * If the rule has "keep frag" and the packet is actually a fragment,
2706 	 * then create a fragment state entry.
2707 	 */
2708 	if (pass & FR_KEEPFRAG) {
2709 		if (fin->fin_flx & FI_FRAG) {
2710 			if (ipf_frag_new(softc, fin, pass) == -1) {
2711 				LBUMP(ipf_stats[out].fr_bnfr);
2712 			} else {
2713 				LBUMP(ipf_stats[out].fr_nfr);
2714 			}
2715 		} else {
2716 			LBUMP(ipf_stats[out].fr_cfr);
2717 		}
2718 	}
2719 
2720 	fr = fin->fin_fr;
2721 	*passp = pass;
2722 
2723 	return (fr);
2724 }
2725 
2726 
2727 /* ------------------------------------------------------------------------ */
2728 /* Function:    ipf_check                                                   */
2729 /* Returns:     int -  0 == packet allowed through,                         */
2730 /*              User space:                                                 */
2731 /*                    -1 == packet blocked                                  */
2732 /*                     1 == packet not matched                              */
2733 /*                    -2 == requires authentication                         */
2734 /*              Kernel:                                                     */
2735 /*                   > 0 == filter error # for packet                       */
2736 /* Parameters: ctx(I)  - pointer to the instance context                    */
2737 /*             ip(I)   - pointer to start of IPv4/6 packet                  */
2738 /*             hlen(I) - length of header                                   */
2739 /*             ifp(I)  - pointer to interface this packet is on             */
2740 /*             out(I)  - 0 == packet going in, 1 == packet going out        */
2741 /*             mp(IO)  - pointer to caller's buffer pointer that holds this */
2742 /*                       IP packet.                                         */
2743 /* Solaris:                                                                 */
2744 /*             qpi(I)  - pointer to STREAMS queue information for this      */
2745 /*                       interface & direction.                             */
2746 /*                                                                          */
2747 /* ipf_check() is the master function for all IPFilter packet processing.   */
2748 /* It orchestrates: Network Address Translation (NAT), checking for packet  */
2749 /* authorisation (or pre-authorisation), presence of related state info.,   */
2750 /* generating log entries, IP packet accounting, routing of packets as      */
2751 /* directed by firewall rules and of course whether or not to allow the     */
2752 /* packet to be further processed by the kernel.                            */
2753 /*                                                                          */
2754 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer  */
2755 /* freed.  Packets passed may be returned with the pointer pointed to by    */
2756 /* by "mp" changed to a new buffer.                                         */
2757 /* ------------------------------------------------------------------------ */
2758 int
ipf_check(void * ctx,ip_t * ip,int hlen,struct ifnet * ifp,int out,void * qif,mb_t ** mp)2759 ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out
2760 #if defined(_KERNEL) && SOLARIS
2761 	, void* qif, mb_t **mp)
2762 #else
2763 	, mb_t **mp)
2764 #endif
2765 {
2766 	/*
2767 	 * The above really sucks, but short of writing a diff
2768 	 */
2769 	ipf_main_softc_t *softc = ctx;
2770 	fr_info_t frinfo;
2771 	fr_info_t *fin = &frinfo;
2772 	u_32_t pass = softc->ipf_pass;
2773 	frentry_t *fr = NULL;
2774 	int v = IP_V(ip);
2775 	mb_t *mc = NULL;
2776 	mb_t *m;
2777 	/*
2778 	 * The first part of ipf_check() deals with making sure that what goes
2779 	 * into the filtering engine makes some sense.  Information about the
2780 	 * the packet is distilled, collected into a fr_info_t structure and
2781 	 * the an attempt to ensure the buffer the packet is in is big enough
2782 	 * to hold all the required packet headers.
2783 	 */
2784 #ifdef	_KERNEL
2785 # if SOLARIS
2786 	qpktinfo_t *qpi = qif;
2787 
2788 #  ifdef __sparc
2789 	if ((u_int)ip & 0x3)
2790 		return (2);
2791 #  endif
2792 # else
2793 	SPL_INT(s);
2794 # endif
2795 
2796 	if (softc->ipf_running <= 0) {
2797 		return (0);
2798 	}
2799 
2800 	bzero((char *)fin, sizeof(*fin));
2801 
2802 # if SOLARIS
2803 	if (qpi->qpi_flags & QF_BROADCAST)
2804 		fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2805 	if (qpi->qpi_flags & QF_MULTICAST)
2806 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2807 	m = qpi->qpi_m;
2808 	fin->fin_qfm = m;
2809 	fin->fin_qpi = qpi;
2810 # else /* SOLARIS */
2811 
2812 	m = *mp;
2813 
2814 #  if defined(M_MCAST)
2815 	if ((m->m_flags & M_MCAST) != 0)
2816 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2817 #  endif
2818 #  if defined(M_MLOOP)
2819 	if ((m->m_flags & M_MLOOP) != 0)
2820 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2821 #  endif
2822 #  if defined(M_BCAST)
2823 	if ((m->m_flags & M_BCAST) != 0)
2824 		fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2825 #  endif
2826 #  ifdef M_CANFASTFWD
2827 	/*
2828 	 * XXX For now, IP Filter and fast-forwarding of cached flows
2829 	 * XXX are mutually exclusive.  Eventually, IP Filter should
2830 	 * XXX get a "can-fast-forward" filter rule.
2831 	 */
2832 	m->m_flags &= ~M_CANFASTFWD;
2833 #  endif /* M_CANFASTFWD */
2834 #  if defined(CSUM_DELAY_DATA) && !defined(__FreeBSD__)
2835 	/*
2836 	 * disable delayed checksums.
2837 	 */
2838 	if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
2839 		in_delayed_cksum(m);
2840 		m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
2841 	}
2842 #  endif /* CSUM_DELAY_DATA */
2843 # endif /* SOLARIS */
2844 #else
2845 	bzero((char *)fin, sizeof(*fin));
2846 	m = *mp;
2847 # if defined(M_MCAST)
2848 	if ((m->m_flags & M_MCAST) != 0)
2849 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2850 # endif
2851 # if defined(M_MLOOP)
2852 	if ((m->m_flags & M_MLOOP) != 0)
2853 		fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2854 # endif
2855 # if defined(M_BCAST)
2856 	if ((m->m_flags & M_BCAST) != 0)
2857 		fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2858 # endif
2859 #endif /* _KERNEL */
2860 
2861 	fin->fin_v = v;
2862 	fin->fin_m = m;
2863 	fin->fin_ip = ip;
2864 	fin->fin_mp = mp;
2865 	fin->fin_out = out;
2866 	fin->fin_ifp = ifp;
2867 	fin->fin_error = ENETUNREACH;
2868 	fin->fin_hlen = (u_short)hlen;
2869 	fin->fin_dp = (char *)ip + hlen;
2870 	fin->fin_main_soft = softc;
2871 
2872 	fin->fin_ipoff = (char *)ip - MTOD(m, char *);
2873 
2874 	SPL_NET(s);
2875 
2876 #ifdef	USE_INET6
2877 	if (v == 6) {
2878 		LBUMP(ipf_stats[out].fr_ipv6);
2879 		/*
2880 		 * Jumbo grams are quite likely too big for internal buffer
2881 		 * structures to handle comfortably, for now, so just drop
2882 		 * them.
2883 		 */
2884 		if (((ip6_t *)ip)->ip6_plen == 0) {
2885 			DT1(frb_jumbo, ip6_t *, (ip6_t *)ip);
2886 			pass = FR_BLOCK|FR_NOMATCH;
2887 			fin->fin_reason = FRB_JUMBO;
2888 			goto finished;
2889 		}
2890 		fin->fin_family = AF_INET6;
2891 	} else
2892 #endif
2893 	{
2894 		fin->fin_family = AF_INET;
2895 	}
2896 
2897 	if (ipf_makefrip(hlen, ip, fin) == -1) {
2898 		DT1(frb_makefrip, fr_info_t *, fin);
2899 		pass = FR_BLOCK|FR_NOMATCH;
2900 		fin->fin_reason = FRB_MAKEFRIP;
2901 		goto finished;
2902 	}
2903 
2904 	/*
2905 	 * For at least IPv6 packets, if a m_pullup() fails then this pointer
2906 	 * becomes NULL and so we have no packet to free.
2907 	 */
2908 	if (*fin->fin_mp == NULL)
2909 		goto finished;
2910 
2911 	if (!out) {
2912 		if (v == 4) {
2913 			if (softc->ipf_chksrc && !ipf_verifysrc(fin)) {
2914 				LBUMPD(ipf_stats[0], fr_v4_badsrc);
2915 				fin->fin_flx |= FI_BADSRC;
2916 			}
2917 			if (fin->fin_ip->ip_ttl < softc->ipf_minttl) {
2918 				LBUMPD(ipf_stats[0], fr_v4_badttl);
2919 				fin->fin_flx |= FI_LOWTTL;
2920 			}
2921 		}
2922 #ifdef USE_INET6
2923 		else  if (v == 6) {
2924 			if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) {
2925 				LBUMPD(ipf_stats[0], fr_v6_badttl);
2926 				fin->fin_flx |= FI_LOWTTL;
2927 			}
2928 		}
2929 #endif
2930 	}
2931 
2932 	if (fin->fin_flx & FI_SHORT) {
2933 		LBUMPD(ipf_stats[out], fr_short);
2934 	}
2935 
2936 	READ_ENTER(&softc->ipf_mutex);
2937 
2938 	if (!out) {
2939 		switch (fin->fin_v)
2940 		{
2941 		case 4 :
2942 			if (ipf_nat_checkin(fin, &pass) == -1) {
2943 				goto filterdone;
2944 			}
2945 			break;
2946 #ifdef USE_INET6
2947 		case 6 :
2948 			if (ipf_nat6_checkin(fin, &pass) == -1) {
2949 				goto filterdone;
2950 			}
2951 			break;
2952 #endif
2953 		default :
2954 			break;
2955 		}
2956 	}
2957 	/*
2958 	 * Check auth now.
2959 	 * If a packet is found in the auth table, then skip checking
2960 	 * the access lists for permission but we do need to consider
2961 	 * the result as if it were from the ACL's.  In addition, being
2962 	 * found in the auth table means it has been seen before, so do
2963 	 * not pass it through accounting (again), lest it be counted twice.
2964 	 */
2965 	fr = ipf_auth_check(fin, &pass);
2966 	if (!out && (fr == NULL))
2967 		(void) ipf_acctpkt(fin, NULL);
2968 
2969 	if (fr == NULL) {
2970 		if ((fin->fin_flx & FI_FRAG) != 0)
2971 			fr = ipf_frag_known(fin, &pass);
2972 
2973 		if (fr == NULL)
2974 			fr = ipf_state_check(fin, &pass);
2975 	}
2976 
2977 	if ((pass & FR_NOMATCH) || (fr == NULL))
2978 		fr = ipf_firewall(fin, &pass);
2979 
2980 	/*
2981 	 * If we've asked to track state for this packet, set it up.
2982 	 * Here rather than ipf_firewall because ipf_checkauth may decide
2983 	* to return a packet for "keep state"
2984 	 */
2985 	if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) &&
2986 	    !(fin->fin_flx & FI_STATE)) {
2987 		if (ipf_state_add(softc, fin, NULL, 0) == 0) {
2988 			LBUMP(ipf_stats[out].fr_ads);
2989 		} else {
2990 			LBUMP(ipf_stats[out].fr_bads);
2991 			if (FR_ISPASS(pass)) {
2992 				DT(frb_stateadd);
2993 				pass &= ~FR_CMDMASK;
2994 				pass |= FR_BLOCK;
2995 				fin->fin_reason = FRB_STATEADD;
2996 			}
2997 		}
2998 	}
2999 
3000 	fin->fin_fr = fr;
3001 	if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) {
3002 		fin->fin_dif = &fr->fr_dif;
3003 		fin->fin_tif = &fr->fr_tifs[fin->fin_rev];
3004 	}
3005 
3006 	/*
3007 	 * Only count/translate packets which will be passed on, out the
3008 	 * interface.
3009 	 */
3010 	if (out && FR_ISPASS(pass)) {
3011 		(void) ipf_acctpkt(fin, NULL);
3012 
3013 		switch (fin->fin_v)
3014 		{
3015 		case 4 :
3016 			if (ipf_nat_checkout(fin, &pass) == -1) {
3017 				;
3018 			} else if ((softc->ipf_update_ipid != 0) && (v == 4)) {
3019 				if (ipf_updateipid(fin) == -1) {
3020 					DT(frb_updateipid);
3021 					LBUMP(ipf_stats[1].fr_ipud);
3022 					pass &= ~FR_CMDMASK;
3023 					pass |= FR_BLOCK;
3024 					fin->fin_reason = FRB_UPDATEIPID;
3025 				} else {
3026 					LBUMP(ipf_stats[0].fr_ipud);
3027 				}
3028 			}
3029 			break;
3030 #ifdef USE_INET6
3031 		case 6 :
3032 			(void) ipf_nat6_checkout(fin, &pass);
3033 			break;
3034 #endif
3035 		default :
3036 			break;
3037 		}
3038 	}
3039 
3040 filterdone:
3041 #ifdef	IPFILTER_LOG
3042 	if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
3043 		(void) ipf_dolog(fin, &pass);
3044 	}
3045 #endif
3046 
3047 	/*
3048 	 * The FI_STATE flag is cleared here so that calling ipf_state_check
3049 	 * will work when called from inside of fr_fastroute.  Although
3050 	 * there is a similar flag, FI_NATED, for NAT, it does have the same
3051 	 * impact on code execution.
3052 	 */
3053 	fin->fin_flx &= ~FI_STATE;
3054 
3055 #if defined(FASTROUTE_RECURSION)
3056 	/*
3057 	 * Up the reference on fr_lock and exit ipf_mutex. The generation of
3058 	 * a packet below can sometimes cause a recursive call into IPFilter.
3059 	 * On those platforms where that does happen, we need to hang onto
3060 	 * the filter rule just in case someone decides to remove or flush it
3061 	 * in the meantime.
3062 	 */
3063 	if (fr != NULL) {
3064 		MUTEX_ENTER(&fr->fr_lock);
3065 		fr->fr_ref++;
3066 		MUTEX_EXIT(&fr->fr_lock);
3067 	}
3068 
3069 	RWLOCK_EXIT(&softc->ipf_mutex);
3070 #endif
3071 
3072 	if ((pass & FR_RETMASK) != 0) {
3073 		/*
3074 		* Should we return an ICMP packet to indicate error
3075 		 * status passing through the packet filter ?
3076 		 * WARNING: ICMP error packets AND TCP RST packets should
3077 		 * ONLY be sent in repsonse to incoming packets.  Sending
3078 		 * them in response to outbound packets can result in a
3079 		 * panic on some operating systems.
3080 		 */
3081 		if (!out) {
3082 			if (pass & FR_RETICMP) {
3083 				int dst;
3084 
3085 				if ((pass & FR_RETMASK) == FR_FAKEICMP)
3086 					dst = 1;
3087 				else
3088 					dst = 0;
3089 				(void) ipf_send_icmp_err(ICMP_UNREACH, fin,
3090 							 dst);
3091 				LBUMP(ipf_stats[0].fr_ret);
3092 			} else if (((pass & FR_RETMASK) == FR_RETRST) &&
3093 				   !(fin->fin_flx & FI_SHORT)) {
3094 				if (((fin->fin_flx & FI_OOW) != 0) ||
3095 				    (ipf_send_reset(fin) == 0)) {
3096 					LBUMP(ipf_stats[1].fr_ret);
3097 				}
3098 			}
3099 
3100 			/*
3101 			 * When using return-* with auth rules, the auth code
3102 			 * takes over disposing of this packet.
3103 			 */
3104 			if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
3105 				DT1(frb_authcapture, fr_info_t *, fin);
3106 				fin->fin_m = *fin->fin_mp = NULL;
3107 				fin->fin_reason = FRB_AUTHCAPTURE;
3108 				m = NULL;
3109 			}
3110 		} else {
3111 			if (pass & FR_RETRST) {
3112 				fin->fin_error = ECONNRESET;
3113 			}
3114 		}
3115 	}
3116 
3117 	/*
3118 	 * After the above so that ICMP unreachables and TCP RSTs get
3119 	 * created properly.
3120 	 */
3121 	if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
3122 		ipf_nat_uncreate(fin);
3123 
3124 	/*
3125 	 * If we didn't drop off the bottom of the list of rules (and thus
3126 	 * the 'current' rule fr is not NULL), then we may have some extra
3127 	 * instructions about what to do with a packet.
3128 	* Once we're finished return to our caller, freeing the packet if
3129 	 * we are dropping it.
3130 	 */
3131 	if (fr != NULL) {
3132 		frdest_t *fdp;
3133 
3134 		/*
3135 		 * Generate a duplicated packet first because ipf_fastroute
3136 		 * can lead to fin_m being free'd... not good.
3137 		 */
3138 		fdp = fin->fin_dif;
3139 		if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
3140 		    (fdp->fd_ptr != (void *)-1)) {
3141 			mc = M_COPY(fin->fin_m);
3142 			if (mc != NULL)
3143 				ipf_fastroute(mc, &mc, fin, fdp);
3144 		}
3145 
3146 		fdp = fin->fin_tif;
3147 		if (!out && (pass & FR_FASTROUTE)) {
3148 			/*
3149 			 * For fastroute rule, no destination interface defined
3150 			 * so pass NULL as the frdest_t parameter
3151 			 */
3152 			(void) ipf_fastroute(fin->fin_m, mp, fin, NULL);
3153 			m = *mp = NULL;
3154 		} else if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
3155 			   (fdp->fd_ptr != (struct ifnet *)-1)) {
3156 			/* this is for to rules: */
3157 			ipf_fastroute(fin->fin_m, mp, fin, fdp);
3158 			m = *mp = NULL;
3159 		}
3160 
3161 #if defined(FASTROUTE_RECURSION)
3162 		(void) ipf_derefrule(softc, &fr);
3163 #endif
3164 	}
3165 #if !defined(FASTROUTE_RECURSION)
3166 	RWLOCK_EXIT(&softc->ipf_mutex);
3167 #endif
3168 
3169 finished:
3170 	if (!FR_ISPASS(pass)) {
3171 		LBUMP(ipf_stats[out].fr_block);
3172 		if (*mp != NULL) {
3173 #ifdef _KERNEL
3174 			FREE_MB_T(*mp);
3175 #endif
3176 			m = *mp = NULL;
3177 		}
3178 	} else {
3179 		LBUMP(ipf_stats[out].fr_pass);
3180 	}
3181 
3182 	SPL_X(s);
3183 
3184 	if (fin->fin_m == NULL && fin->fin_flx & FI_BAD &&
3185 	    fin->fin_reason == FRB_PULLUP) {
3186 		/* m_pullup() has freed the mbuf */
3187 		LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
3188 		return (-1);
3189 	}
3190 
3191 
3192 #ifdef _KERNEL
3193 	if (FR_ISPASS(pass))
3194 		return (0);
3195 	LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
3196 	return (fin->fin_error);
3197 #else /* _KERNEL */
3198 	if (*mp != NULL)
3199 		(*mp)->mb_ifp = fin->fin_ifp;
3200 	blockreason = fin->fin_reason;
3201 	FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
3202 	/*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/
3203 		if ((pass & FR_NOMATCH) != 0)
3204 			return (1);
3205 
3206 	if ((pass & FR_RETMASK) != 0)
3207 		switch (pass & FR_RETMASK)
3208 		{
3209 		case FR_RETRST :
3210 			return (3);
3211 		case FR_RETICMP :
3212 			return (4);
3213 		case FR_FAKEICMP :
3214 			return (5);
3215 		}
3216 
3217 	switch (pass & FR_CMDMASK)
3218 	{
3219 	case FR_PASS :
3220 		return (0);
3221 	case FR_BLOCK :
3222 		return (-1);
3223 	case FR_AUTH :
3224 		return (-2);
3225 	case FR_ACCOUNT :
3226 		return (-3);
3227 	case FR_PREAUTH :
3228 		return (-4);
3229 	}
3230 	return (2);
3231 #endif /* _KERNEL */
3232 }
3233 
3234 
3235 #ifdef	IPFILTER_LOG
3236 /* ------------------------------------------------------------------------ */
3237 /* Function:    ipf_dolog                                                   */
3238 /* Returns:     frentry_t* - returns contents of fin_fr (no change made)    */
3239 /* Parameters:  fin(I) - pointer to packet information                      */
3240 /*              passp(IO) - pointer to current/new filter decision (unused) */
3241 /*                                                                          */
3242 /* Checks flags set to see how a packet should be logged, if it is to be    */
3243 /* logged.  Adjust statistics based on its success or not.                  */
3244 /* ------------------------------------------------------------------------ */
3245 frentry_t *
ipf_dolog(fr_info_t * fin,u_32_t * passp)3246 ipf_dolog(fr_info_t *fin, u_32_t *passp)
3247 {
3248 	ipf_main_softc_t *softc = fin->fin_main_soft;
3249 	u_32_t pass;
3250 	int out;
3251 
3252 	out = fin->fin_out;
3253 	pass = *passp;
3254 
3255 	if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
3256 		pass |= FF_LOGNOMATCH;
3257 		LBUMPD(ipf_stats[out], fr_npkl);
3258 		goto logit;
3259 
3260 	} else if (((pass & FR_LOGMASK) == FR_LOGP) ||
3261 	    (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) {
3262 		if ((pass & FR_LOGMASK) != FR_LOGP)
3263 			pass |= FF_LOGPASS;
3264 		LBUMPD(ipf_stats[out], fr_ppkl);
3265 		goto logit;
3266 
3267 	} else if (((pass & FR_LOGMASK) == FR_LOGB) ||
3268 		   (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) {
3269 		if ((pass & FR_LOGMASK) != FR_LOGB)
3270 			pass |= FF_LOGBLOCK;
3271 		LBUMPD(ipf_stats[out], fr_bpkl);
3272 
3273 logit:
3274 		if (ipf_log_pkt(fin, pass) == -1) {
3275 			/*
3276 			 * If the "or-block" option has been used then
3277 			 * block the packet if we failed to log it.
3278 			 */
3279 			if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) {
3280 				DT1(frb_logfail2, u_int, pass);
3281 				pass &= ~FR_CMDMASK;
3282 				pass |= FR_BLOCK;
3283 				fin->fin_reason = FRB_LOGFAIL2;
3284 			}
3285 		}
3286 		*passp = pass;
3287 	}
3288 
3289 	return (fin->fin_fr);
3290 }
3291 #endif /* IPFILTER_LOG */
3292 
3293 
3294 /* ------------------------------------------------------------------------ */
3295 /* Function:    ipf_cksum                                                   */
3296 /* Returns:     u_short - IP header checksum                                */
3297 /* Parameters:  addr(I) - pointer to start of buffer to checksum            */
3298 /*              len(I)  - length of buffer in bytes                         */
3299 /*                                                                          */
3300 /* Calculate the two's complement 16 bit checksum of the buffer passed.     */
3301 /*                                                                          */
3302 /* N.B.: addr should be 16bit aligned.                                      */
3303 /* ------------------------------------------------------------------------ */
3304 u_short
ipf_cksum(u_short * addr,int len)3305 ipf_cksum(u_short *addr, int len)
3306 {
3307 	u_32_t sum = 0;
3308 
3309 	for (sum = 0; len > 1; len -= 2)
3310 		sum += *addr++;
3311 
3312 	/* mop up an odd byte, if necessary */
3313 	if (len == 1)
3314 		sum += *(u_char *)addr;
3315 
3316 	/*
3317 	 * add back carry outs from top 16 bits to low 16 bits
3318 	 */
3319 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
3320 	sum += (sum >> 16);			/* add carry */
3321 	return (u_short)(~sum);
3322 }
3323 
3324 
3325 /* ------------------------------------------------------------------------ */
3326 /* Function:    fr_cksum                                                    */
3327 /* Returns:     u_short - layer 4 checksum                                  */
3328 /* Parameters:  fin(I)     - pointer to packet information                  */
3329 /*              ip(I)      - pointer to IP header                           */
3330 /*              l4proto(I) - protocol to caclulate checksum for             */
3331 /*              l4hdr(I)   - pointer to layer 4 header                      */
3332 /*                                                                          */
3333 /* Calculates the TCP checksum for the packet held in "m", using the data   */
3334 /* in the IP header "ip" to seed it.                                        */
3335 /*                                                                          */
3336 /* NB: This function assumes we've pullup'd enough for all of the IP header */
3337 /* and the TCP header.  We also assume that data blocks aren't allocated in */
3338 /* odd sizes.                                                               */
3339 /*                                                                          */
3340 /* Expects ip_len and ip_off to be in network byte order when called.       */
3341 /* ------------------------------------------------------------------------ */
3342 u_short
fr_cksum(fr_info_t * fin,ip_t * ip,int l4proto,void * l4hdr)3343 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr)
3344 {
3345 	u_short *sp, slen, sumsave, *csump;
3346 	u_int sum, sum2;
3347 	int hlen;
3348 	int off;
3349 #ifdef	USE_INET6
3350 	ip6_t *ip6;
3351 #endif
3352 
3353 	csump = NULL;
3354 	sumsave = 0;
3355 	sp = NULL;
3356 	slen = 0;
3357 	hlen = 0;
3358 	sum = 0;
3359 
3360 	sum = htons((u_short)l4proto);
3361 	/*
3362 	 * Add up IP Header portion
3363 	 */
3364 #ifdef	USE_INET6
3365 	if (IP_V(ip) == 4) {
3366 #endif
3367 		hlen = IP_HL(ip) << 2;
3368 		off = hlen;
3369 		sp = (u_short *)&ip->ip_src;
3370 		sum += *sp++;	/* ip_src */
3371 		sum += *sp++;
3372 		sum += *sp++;	/* ip_dst */
3373 		sum += *sp++;
3374 		slen = fin->fin_plen - off;
3375 		sum += htons(slen);
3376 #ifdef	USE_INET6
3377 	} else if (IP_V(ip) == 6) {
3378 		mb_t *m;
3379 
3380 		m = fin->fin_m;
3381 		ip6 = (ip6_t *)ip;
3382 		off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr);
3383 		int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6));
3384 		return (ipf_pcksum6(m, ip6, off, len));
3385 	} else {
3386 		return (0xffff);
3387 	}
3388 #endif
3389 
3390 	switch (l4proto)
3391 	{
3392 	case IPPROTO_UDP :
3393 		csump = &((udphdr_t *)l4hdr)->uh_sum;
3394 		break;
3395 
3396 	case IPPROTO_TCP :
3397 		csump = &((tcphdr_t *)l4hdr)->th_sum;
3398 		break;
3399 	case IPPROTO_ICMP :
3400 		csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
3401 		sum = 0;	/* Pseudo-checksum is not included */
3402 		break;
3403 #ifdef USE_INET6
3404 	case IPPROTO_ICMPV6 :
3405 		csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum;
3406 		break;
3407 #endif
3408 	default :
3409 		break;
3410 	}
3411 
3412 	if (csump != NULL) {
3413 		sumsave = *csump;
3414 		*csump = 0;
3415 	}
3416 
3417 	sum2 = ipf_pcksum(fin, off, sum);
3418 	if (csump != NULL)
3419 		*csump = sumsave;
3420 	return (sum2);
3421 }
3422 
3423 
3424 /* ------------------------------------------------------------------------ */
3425 /* Function:    ipf_findgroup                                               */
3426 /* Returns:     frgroup_t * - NULL = group not found, else pointer to group */
3427 /* Parameters:  softc(I) - pointer to soft context main structure           */
3428 /*              group(I) - group name to search for                         */
3429 /*              unit(I)  - device to which this group belongs               */
3430 /*              set(I)   - which set of rules (inactive/inactive) this is   */
3431 /*              fgpp(O)  - pointer to place to store pointer to the pointer */
3432 /*                         to where to add the next (last) group or where   */
3433 /*                         to delete group from.                            */
3434 /*                                                                          */
3435 /* Search amongst the defined groups for a particular group number.         */
3436 /* ------------------------------------------------------------------------ */
3437 frgroup_t *
ipf_findgroup(ipf_main_softc_t * softc,char * group,minor_t unit,int set,frgroup_t *** fgpp)3438 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set,
3439 	frgroup_t ***fgpp)
3440 {
3441 	frgroup_t *fg, **fgp;
3442 
3443 	/*
3444 	 * Which list of groups to search in is dependent on which list of
3445 	 * rules are being operated on.
3446 	 */
3447 	fgp = &softc->ipf_groups[unit][set];
3448 
3449 	while ((fg = *fgp) != NULL) {
3450 		if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
3451 			break;
3452 		else
3453 			fgp = &fg->fg_next;
3454 	}
3455 	if (fgpp != NULL)
3456 		*fgpp = fgp;
3457 	return (fg);
3458 }
3459 
3460 
3461 /* ------------------------------------------------------------------------ */
3462 /* Function:    ipf_group_add                                               */
3463 /* Returns:     frgroup_t * - NULL == did not create group,                 */
3464 /*                            != NULL == pointer to the group               */
3465 /* Parameters:  softc(I) - pointer to soft context main structure           */
3466 /*              num(I)   - group number to add                              */
3467 /*              head(I)  - rule pointer that is using this as the head      */
3468 /*              flags(I) - rule flags which describe the type of rule it is */
3469 /*              unit(I)  - device to which this group will belong to        */
3470 /*              set(I)   - which set of rules (inactive/inactive) this is   */
3471 /* Write Locks: ipf_mutex                                                   */
3472 /*                                                                          */
3473 /* Add a new group head, or if it already exists, increase the reference    */
3474 /* count to it.                                                             */
3475 /* ------------------------------------------------------------------------ */
3476 frgroup_t *
ipf_group_add(ipf_main_softc_t * softc,char * group,void * head,u_32_t flags,minor_t unit,int set)3477 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags,
3478 	minor_t unit, int set)
3479 {
3480 	frgroup_t *fg, **fgp;
3481 	u_32_t gflags;
3482 
3483 	if (group == NULL)
3484 		return (NULL);
3485 
3486 	if (unit == IPL_LOGIPF && *group == '\0')
3487 		return (NULL);
3488 
3489 	fgp = NULL;
3490 	gflags = flags & FR_INOUT;
3491 
3492 	fg = ipf_findgroup(softc, group, unit, set, &fgp);
3493 	if (fg != NULL) {
3494 		if (fg->fg_head == NULL && head != NULL)
3495 			fg->fg_head = head;
3496 		if (fg->fg_flags == 0)
3497 			fg->fg_flags = gflags;
3498 		else if (gflags != fg->fg_flags)
3499 			return (NULL);
3500 		fg->fg_ref++;
3501 		return (fg);
3502 	}
3503 
3504 	KMALLOC(fg, frgroup_t *);
3505 	if (fg != NULL) {
3506 		fg->fg_head = head;
3507 		fg->fg_start = NULL;
3508 		fg->fg_next = *fgp;
3509 		bcopy(group, fg->fg_name, strlen(group) + 1);
3510 		fg->fg_flags = gflags;
3511 		fg->fg_ref = 1;
3512 		fg->fg_set = &softc->ipf_groups[unit][set];
3513 		*fgp = fg;
3514 	}
3515 	return (fg);
3516 }
3517 
3518 
3519 /* ------------------------------------------------------------------------ */
3520 /* Function:    ipf_group_del                                               */
3521 /* Returns:     int      - number of rules deleted                          */
3522 /* Parameters:  softc(I) - pointer to soft context main structure           */
3523 /*              group(I) - group name to delete                             */
3524 /*              fr(I)    - filter rule from which group is referenced       */
3525 /* Write Locks: ipf_mutex                                                   */
3526 /*                                                                          */
3527 /* This function is called whenever a reference to a group is to be dropped */
3528 /* and thus its reference count needs to be lowered and the group free'd if */
3529 /* the reference count reaches zero. Passing in fr is really for the sole   */
3530 /* purpose of knowing when the head rule is being deleted.                  */
3531 /* ------------------------------------------------------------------------ */
3532 void
ipf_group_del(ipf_main_softc_t * softc,frgroup_t * group,frentry_t * fr)3533 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr)
3534 {
3535 
3536 	if (group->fg_head == fr)
3537 		group->fg_head = NULL;
3538 
3539 	group->fg_ref--;
3540 	if ((group->fg_ref == 0) && (group->fg_start == NULL))
3541 		ipf_group_free(group);
3542 }
3543 
3544 
3545 /* ------------------------------------------------------------------------ */
3546 /* Function:    ipf_group_free                                              */
3547 /* Returns:     Nil                                                         */
3548 /* Parameters:  group(I) - pointer to filter rule group                     */
3549 /*                                                                          */
3550 /* Remove the group from the list of groups and free it.                    */
3551 /* ------------------------------------------------------------------------ */
3552 static void
ipf_group_free(frgroup_t * group)3553 ipf_group_free(frgroup_t *group)
3554 {
3555 	frgroup_t **gp;
3556 
3557 	for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) {
3558 		if (*gp == group) {
3559 			*gp = group->fg_next;
3560 			break;
3561 		}
3562 	}
3563 	KFREE(group);
3564 }
3565 
3566 
3567 /* ------------------------------------------------------------------------ */
3568 /* Function:    ipf_group_flush                                             */
3569 /* Returns:     int      - number of rules flush from group                 */
3570 /* Parameters:  softc(I) - pointer to soft context main structure           */
3571 /* Parameters:  group(I) - pointer to filter rule group                     */
3572 /*                                                                          */
3573 /* Remove all of the rules that currently are listed under the given group. */
3574 /* ------------------------------------------------------------------------ */
3575 static int
ipf_group_flush(ipf_main_softc_t * softc,frgroup_t * group)3576 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group)
3577 {
3578 	int gone = 0;
3579 
3580 	(void) ipf_flushlist(softc, &gone, &group->fg_start);
3581 
3582 	return (gone);
3583 }
3584 
3585 
3586 /* ------------------------------------------------------------------------ */
3587 /* Function:    ipf_getrulen                                                */
3588 /* Returns:     frentry_t * - NULL == not found, else pointer to rule n     */
3589 /* Parameters:  softc(I) - pointer to soft context main structure           */
3590 /* Parameters:  unit(I)  - device for which to count the rule's number      */
3591 /*              flags(I) - which set of rules to find the rule in           */
3592 /*              group(I) - group name                                       */
3593 /*              n(I)     - rule number to find                              */
3594 /*                                                                          */
3595 /* Find rule # n in group # g and return a pointer to it.  Return NULl if   */
3596 /* group # g doesn't exist or there are less than n rules in the group.     */
3597 /* ------------------------------------------------------------------------ */
3598 frentry_t *
ipf_getrulen(ipf_main_softc_t * softc,int unit,char * group,u_32_t n)3599 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n)
3600 {
3601 	frentry_t *fr;
3602 	frgroup_t *fg;
3603 
3604 	fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL);
3605 	if (fg == NULL)
3606 		return (NULL);
3607 	for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--)
3608 		;
3609 	if (n != 0)
3610 		return (NULL);
3611 	return (fr);
3612 }
3613 
3614 
3615 /* ------------------------------------------------------------------------ */
3616 /* Function:    ipf_flushlist                                               */
3617 /* Returns:     int - >= 0 - number of flushed rules                        */
3618 /* Parameters:  softc(I)   - pointer to soft context main structure         */
3619 /*              nfreedp(O) - pointer to int where flush count is stored     */
3620 /*              listp(I)   - pointer to list to flush pointer               */
3621 /* Write Locks: ipf_mutex                                                   */
3622 /*                                                                          */
3623 /* Recursively flush rules from the list, descending groups as they are     */
3624 /* encountered.  if a rule is the head of a group and it has lost all its   */
3625 /* group members, then also delete the group reference.  nfreedp is needed  */
3626 /* to store the accumulating count of rules removed, whereas the returned   */
3627 /* value is just the number removed from the current list.  The latter is   */
3628 /* needed to correctly adjust reference counts on rules that define groups. */
3629 /*                                                                          */
3630 /* NOTE: Rules not loaded from user space cannot be flushed.                */
3631 /* ------------------------------------------------------------------------ */
3632 static int
ipf_flushlist(ipf_main_softc_t * softc,int * nfreedp,frentry_t ** listp)3633 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp)
3634 {
3635 	int freed = 0;
3636 	frentry_t *fp;
3637 
3638 	while ((fp = *listp) != NULL) {
3639 		if ((fp->fr_type & FR_T_BUILTIN) ||
3640 		    !(fp->fr_flags & FR_COPIED)) {
3641 			listp = &fp->fr_next;
3642 			continue;
3643 		}
3644 		*listp = fp->fr_next;
3645 		if (fp->fr_next != NULL)
3646 			fp->fr_next->fr_pnext = fp->fr_pnext;
3647 		fp->fr_pnext = NULL;
3648 
3649 		if (fp->fr_grphead != NULL) {
3650 			freed += ipf_group_flush(softc, fp->fr_grphead);
3651 			fp->fr_names[fp->fr_grhead] = '\0';
3652 		}
3653 
3654 		if (fp->fr_icmpgrp != NULL) {
3655 			freed += ipf_group_flush(softc, fp->fr_icmpgrp);
3656 			fp->fr_names[fp->fr_icmphead] = '\0';
3657 		}
3658 
3659 		if (fp->fr_srctrack.ht_max_nodes)
3660 			ipf_rb_ht_flush(&fp->fr_srctrack);
3661 
3662 		fp->fr_next = NULL;
3663 
3664 		ASSERT(fp->fr_ref > 0);
3665 		if (ipf_derefrule(softc, &fp) == 0)
3666 			freed++;
3667 	}
3668 	*nfreedp += freed;
3669 	return (freed);
3670 }
3671 
3672 
3673 /* ------------------------------------------------------------------------ */
3674 /* Function:    ipf_flush                                                   */
3675 /* Returns:     int - >= 0 - number of flushed rules                        */
3676 /* Parameters:  softc(I) - pointer to soft context main structure           */
3677 /*              unit(I)  - device for which to flush rules                  */
3678 /*              flags(I) - which set of rules to flush                      */
3679 /*                                                                          */
3680 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
3681 /* and IPv6) as defined by the value of flags.                              */
3682 /* ------------------------------------------------------------------------ */
3683 int
ipf_flush(ipf_main_softc_t * softc,minor_t unit,int flags)3684 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags)
3685 {
3686 	int flushed = 0, set;
3687 
3688 	WRITE_ENTER(&softc->ipf_mutex);
3689 
3690 	set = softc->ipf_active;
3691 	if ((flags & FR_INACTIVE) == FR_INACTIVE)
3692 		set = 1 - set;
3693 
3694 	if (flags & FR_OUTQUE) {
3695 		ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]);
3696 		ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]);
3697 	}
3698 	if (flags & FR_INQUE) {
3699 		ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]);
3700 		ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]);
3701 	}
3702 
3703 	flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set],
3704 				    flags & (FR_INQUE|FR_OUTQUE));
3705 
3706 	RWLOCK_EXIT(&softc->ipf_mutex);
3707 
3708 	if (unit == IPL_LOGIPF) {
3709 		int tmp;
3710 
3711 		tmp = ipf_flush(softc, IPL_LOGCOUNT, flags);
3712 		if (tmp >= 0)
3713 			flushed += tmp;
3714 	}
3715 	return (flushed);
3716 }
3717 
3718 
3719 /* ------------------------------------------------------------------------ */
3720 /* Function:    ipf_flush_groups                                            */
3721 /* Returns:     int - >= 0 - number of flushed rules                        */
3722 /* Parameters:  softc(I)  - soft context pointerto work with                */
3723 /*              grhead(I) - pointer to the start of the group list to flush */
3724 /*              flags(I)  - which set of rules to flush                     */
3725 /*                                                                          */
3726 /* Walk through all of the groups under the given group head and remove all */
3727 /* of those that match the flags passed in. The for loop here is bit more   */
3728 /* complicated than usual because the removal of a rule with ipf_derefrule  */
3729 /* may end up removing not only the structure pointed to by "fg" but also   */
3730 /* what is fg_next and fg_next after that. So if a filter rule is actually  */
3731 /* removed from the group then it is necessary to start again.              */
3732 /* ------------------------------------------------------------------------ */
3733 static int
ipf_flush_groups(ipf_main_softc_t * softc,frgroup_t ** grhead,int flags)3734 ipf_flush_groups(ipf_main_softc_t *softc, frgroup_t **grhead, int flags)
3735 {
3736 	frentry_t *fr, **frp;
3737 	frgroup_t *fg, **fgp;
3738 	int flushed = 0;
3739 	int removed = 0;
3740 
3741 	for (fgp = grhead; (fg = *fgp) != NULL; ) {
3742 		while ((fg != NULL) && ((fg->fg_flags & flags) == 0))
3743 			fg = fg->fg_next;
3744 		if (fg == NULL)
3745 			break;
3746 		removed = 0;
3747 		frp = &fg->fg_start;
3748 		while ((removed == 0) && ((fr = *frp) != NULL)) {
3749 			if ((fr->fr_flags & flags) == 0) {
3750 				frp = &fr->fr_next;
3751 			} else {
3752 				if (fr->fr_next != NULL)
3753 					fr->fr_next->fr_pnext = fr->fr_pnext;
3754 				*frp = fr->fr_next;
3755 				fr->fr_pnext = NULL;
3756 				fr->fr_next = NULL;
3757 				(void) ipf_derefrule(softc, &fr);
3758 				flushed++;
3759 				removed++;
3760 			}
3761 		}
3762 		if (removed == 0)
3763 			fgp = &fg->fg_next;
3764 	}
3765 	return (flushed);
3766 }
3767 
3768 
3769 /* ------------------------------------------------------------------------ */
3770 /* Function:    memstr                                                      */
3771 /* Returns:     char *  - NULL if failed, != NULL pointer to matching bytes */
3772 /* Parameters:  src(I)  - pointer to byte sequence to match                 */
3773 /*              dst(I)  - pointer to byte sequence to search                */
3774 /*              slen(I) - match length                                      */
3775 /*              dlen(I) - length available to search in                     */
3776 /*                                                                          */
3777 /* Search dst for a sequence of bytes matching those at src and extend for  */
3778 /* slen bytes.                                                              */
3779 /* ------------------------------------------------------------------------ */
3780 char *
memstr(const char * src,char * dst,size_t slen,size_t dlen)3781 memstr(const char *src, char *dst, size_t slen, size_t dlen)
3782 {
3783 	char *s = NULL;
3784 
3785 	while (dlen >= slen) {
3786 		if (bcmp(src, dst, slen) == 0) {
3787 			s = dst;
3788 			break;
3789 		}
3790 		dst++;
3791 		dlen--;
3792 	}
3793 	return (s);
3794 }
3795 /* ------------------------------------------------------------------------ */
3796 /* Function:    ipf_fixskip                                                 */
3797 /* Returns:     Nil                                                         */
3798 /* Parameters:  listp(IO)    - pointer to start of list with skip rule      */
3799 /*              rp(I)        - rule added/removed with skip in it.          */
3800 /*              addremove(I) - adjustment (-1/+1) to make to skip count,    */
3801 /*                             depending on whether a rule was just added   */
3802 /*                             or removed.                                  */
3803 /*                                                                          */
3804 /* Adjust all the rules in a list which would have skip'd past the position */
3805 /* where we are inserting to skip to the right place given the change.      */
3806 /* ------------------------------------------------------------------------ */
3807 void
ipf_fixskip(frentry_t ** listp,frentry_t * rp,int addremove)3808 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove)
3809 {
3810 	int rules, rn;
3811 	frentry_t *fp;
3812 
3813 	rules = 0;
3814 	for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next)
3815 		rules++;
3816 
3817 	if (fp == NULL)
3818 		return;
3819 
3820 	for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
3821 		if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules))
3822 			fp->fr_arg += addremove;
3823 }
3824 
3825 
3826 #ifdef	_KERNEL
3827 /* ------------------------------------------------------------------------ */
3828 /* Function:    count4bits                                                  */
3829 /* Returns:     int - >= 0 - number of consecutive bits in input            */
3830 /* Parameters:  ip(I) - 32bit IP address                                    */
3831 /*                                                                          */
3832 /* IPv4 ONLY                                                                */
3833 /* count consecutive 1's in bit mask.  If the mask generated by counting    */
3834 /* consecutive 1's is different to that passed, return -1, else return #    */
3835 /* of bits.                                                                 */
3836 /* ------------------------------------------------------------------------ */
3837 int
count4bits(u_32_t ip)3838 count4bits(u_32_t ip)
3839 {
3840 	u_32_t	ipn;
3841 	int	cnt = 0, i, j;
3842 
3843 	ip = ipn = ntohl(ip);
3844 	for (i = 32; i; i--, ipn *= 2)
3845 		if (ipn & 0x80000000)
3846 			cnt++;
3847 		else
3848 			break;
3849 	ipn = 0;
3850 	for (i = 32, j = cnt; i; i--, j--) {
3851 		ipn *= 2;
3852 		if (j > 0)
3853 			ipn++;
3854 	}
3855 	if (ipn == ip)
3856 		return (cnt);
3857 	return (-1);
3858 }
3859 
3860 
3861 /* ------------------------------------------------------------------------ */
3862 /* Function:    count6bits                                                  */
3863 /* Returns:     int - >= 0 - number of consecutive bits in input            */
3864 /* Parameters:  msk(I) - pointer to start of IPv6 bitmask                   */
3865 /*                                                                          */
3866 /* IPv6 ONLY                                                                */
3867 /* count consecutive 1's in bit mask.                                       */
3868 /* ------------------------------------------------------------------------ */
3869 # ifdef USE_INET6
3870 int
count6bits(u_32_t * msk)3871 count6bits(u_32_t *msk)
3872 {
3873 	int i = 0, k;
3874 	u_32_t j;
3875 
3876 	for (k = 3; k >= 0; k--)
3877 		if (msk[k] == 0xffffffff)
3878 			i += 32;
3879 		else {
3880 			for (j = msk[k]; j; j <<= 1)
3881 				if (j & 0x80000000)
3882 					i++;
3883 		}
3884 	return (i);
3885 }
3886 # endif
3887 #endif /* _KERNEL */
3888 
3889 
3890 /* ------------------------------------------------------------------------ */
3891 /* Function:    ipf_synclist                                                */
3892 /* Returns:     int    - 0 = no failures, else indication of first failure  */
3893 /* Parameters:  fr(I)  - start of filter list to sync interface names for   */
3894 /*              ifp(I) - interface pointer for limiting sync lookups        */
3895 /* Write Locks: ipf_mutex                                                   */
3896 /*                                                                          */
3897 /* Walk through a list of filter rules and resolve any interface names into */
3898 /* pointers.  Where dynamic addresses are used, also update the IP address  */
3899 /* used in the rule.  The interface pointer is used to limit the lookups to */
3900 /* a specific set of matching names if it is non-NULL.                      */
3901 /* Errors can occur when resolving the destination name of to/dup-to fields */
3902 /* when the name points to a pool and that pool doest not exist. If this    */
3903 /* does happen then it is necessary to check if there are any lookup refs   */
3904 /* that need to be dropped before returning with an error.                  */
3905 /* ------------------------------------------------------------------------ */
3906 static int
ipf_synclist(ipf_main_softc_t * softc,frentry_t * fr,void * ifp)3907 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp)
3908 {
3909 	frentry_t *frt, *start = fr;
3910 	frdest_t *fdp;
3911 	char *name;
3912 	int error;
3913 	void *ifa;
3914 	int v, i;
3915 
3916 	error = 0;
3917 
3918 	for (; fr; fr = fr->fr_next) {
3919 		if (fr->fr_family == AF_INET)
3920 			v = 4;
3921 		else if (fr->fr_family == AF_INET6)
3922 			v = 6;
3923 		else
3924 			v = 0;
3925 
3926 		/*
3927 		 * Lookup all the interface names that are part of the rule.
3928 		 */
3929 		for (i = 0; i < FR_NUM(fr->fr_ifas); i++) {
3930 			if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
3931 				continue;
3932 			if (fr->fr_ifnames[i] == -1)
3933 				continue;
3934 			name = FR_NAME(fr, fr_ifnames[i]);
3935 			fr->fr_ifas[i] = ipf_resolvenic(softc, name, v);
3936 		}
3937 
3938 		if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
3939 			if (fr->fr_satype != FRI_NORMAL &&
3940 			    fr->fr_satype != FRI_LOOKUP) {
3941 				ifa = ipf_resolvenic(softc, fr->fr_names +
3942 						     fr->fr_sifpidx, v);
3943 				ipf_ifpaddr(softc, v, fr->fr_satype, ifa,
3944 					    &fr->fr_src6, &fr->fr_smsk6);
3945 			}
3946 			if (fr->fr_datype != FRI_NORMAL &&
3947 			    fr->fr_datype != FRI_LOOKUP) {
3948 				ifa = ipf_resolvenic(softc, fr->fr_names +
3949 						     fr->fr_sifpidx, v);
3950 				ipf_ifpaddr(softc, v, fr->fr_datype, ifa,
3951 					    &fr->fr_dst6, &fr->fr_dmsk6);
3952 			}
3953 		}
3954 
3955 		fdp = &fr->fr_tifs[0];
3956 		if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
3957 			error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
3958 			if (error != 0)
3959 				goto unwind;
3960 		}
3961 
3962 		fdp = &fr->fr_tifs[1];
3963 		if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
3964 			error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
3965 			if (error != 0)
3966 				goto unwind;
3967 		}
3968 
3969 		fdp = &fr->fr_dif;
3970 		if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
3971 			error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
3972 			if (error != 0)
3973 				goto unwind;
3974 		}
3975 
3976 		if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
3977 		    (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) {
3978 			fr->fr_srcptr = ipf_lookup_res_num(softc,
3979 							   fr->fr_srctype,
3980 							   IPL_LOGIPF,
3981 							   fr->fr_srcnum,
3982 							   &fr->fr_srcfunc);
3983 		}
3984 		if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
3985 		    (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) {
3986 			fr->fr_dstptr = ipf_lookup_res_num(softc,
3987 							   fr->fr_dsttype,
3988 							   IPL_LOGIPF,
3989 							   fr->fr_dstnum,
3990 							   &fr->fr_dstfunc);
3991 		}
3992 	}
3993 	return (0);
3994 
3995 unwind:
3996 	for (frt = start; frt != fr; fr = fr->fr_next) {
3997 		if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
3998 		    (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL))
3999 				ipf_lookup_deref(softc, frt->fr_srctype,
4000 						 frt->fr_srcptr);
4001 		if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4002 		    (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL))
4003 				ipf_lookup_deref(softc, frt->fr_dsttype,
4004 						 frt->fr_dstptr);
4005 	}
4006 	return (error);
4007 }
4008 
4009 
4010 /* ------------------------------------------------------------------------ */
4011 /* Function:    ipf_sync                                                    */
4012 /* Returns:     void                                                        */
4013 /* Parameters:  Nil                                                         */
4014 /*                                                                          */
4015 /* ipf_sync() is called when we suspect that the interface list or          */
4016 /* information about interfaces (like IP#) has changed.  Go through all     */
4017 /* filter rules, NAT entries and the state table and check if anything      */
4018 /* needs to be changed/updated.                                             */
4019 /* ------------------------------------------------------------------------ */
4020 int
ipf_sync(ipf_main_softc_t * softc,void * ifp)4021 ipf_sync(ipf_main_softc_t *softc, void *ifp)
4022 {
4023 	int i;
4024 
4025 #if !SOLARIS
4026 	ipf_nat_sync(softc, ifp);
4027 	ipf_state_sync(softc, ifp);
4028 	ipf_lookup_sync(softc, ifp);
4029 #endif
4030 
4031 	WRITE_ENTER(&softc->ipf_mutex);
4032 	(void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp);
4033 	(void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp);
4034 	(void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp);
4035 	(void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp);
4036 
4037 	for (i = 0; i < IPL_LOGSIZE; i++) {
4038 		frgroup_t *g;
4039 
4040 		for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next)
4041 			(void) ipf_synclist(softc, g->fg_start, ifp);
4042 		for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next)
4043 			(void) ipf_synclist(softc, g->fg_start, ifp);
4044 	}
4045 	RWLOCK_EXIT(&softc->ipf_mutex);
4046 
4047 	return (0);
4048 }
4049 
4050 
4051 /*
4052  * In the functions below, bcopy() is called because the pointer being
4053  * copied _from_ in this instance is a pointer to a char buf (which could
4054  * end up being unaligned) and on the kernel's local stack.
4055  */
4056 /* ------------------------------------------------------------------------ */
4057 /* Function:    copyinptr                                                   */
4058 /* Returns:     int - 0 = success, else failure                             */
4059 /* Parameters:  src(I)  - pointer to the source address                     */
4060 /*              dst(I)  - destination address                               */
4061 /*              size(I) - number of bytes to copy                           */
4062 /*                                                                          */
4063 /* Copy a block of data in from user space, given a pointer to the pointer  */
4064 /* to start copying from (src) and a pointer to where to store it (dst).    */
4065 /* NB: src - pointer to user space pointer, dst - kernel space pointer      */
4066 /* ------------------------------------------------------------------------ */
4067 int
copyinptr(ipf_main_softc_t * softc,void * src,void * dst,size_t size)4068 copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size)
4069 {
4070 	caddr_t ca;
4071 	int error;
4072 
4073 #if SOLARIS
4074 	error = COPYIN(src, &ca, sizeof(ca));
4075 	if (error != 0)
4076 		return (error);
4077 #else
4078 	bcopy(src, (caddr_t)&ca, sizeof(ca));
4079 #endif
4080 	error = COPYIN(ca, dst, size);
4081 	if (error != 0) {
4082 		IPFERROR(3);
4083 		error = EFAULT;
4084 	}
4085 	return (error);
4086 }
4087 
4088 
4089 /* ------------------------------------------------------------------------ */
4090 /* Function:    copyoutptr                                                  */
4091 /* Returns:     int - 0 = success, else failure                             */
4092 /* Parameters:  src(I)  - pointer to the source address                     */
4093 /*              dst(I)  - destination address                               */
4094 /*              size(I) - number of bytes to copy                           */
4095 /*                                                                          */
4096 /* Copy a block of data out to user space, given a pointer to the pointer   */
4097 /* to start copying from (src) and a pointer to where to store it (dst).    */
4098 /* NB: src - kernel space pointer, dst - pointer to user space pointer.     */
4099 /* ------------------------------------------------------------------------ */
4100 int
copyoutptr(ipf_main_softc_t * softc,void * src,void * dst,size_t size)4101 copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size)
4102 {
4103 	caddr_t ca;
4104 	int error;
4105 
4106 	bcopy(dst, (caddr_t)&ca, sizeof(ca));
4107 	error = COPYOUT(src, ca, size);
4108 	if (error != 0) {
4109 		IPFERROR(4);
4110 		error = EFAULT;
4111 	}
4112 	return (error);
4113 }
4114 
4115 
4116 /* ------------------------------------------------------------------------ */
4117 /* Function:    ipf_lock                                                    */
4118 /* Returns:     int      - 0 = success, else error                          */
4119 /* Parameters:  data(I)  - pointer to lock value to set                     */
4120 /*              lockp(O) - pointer to location to store old lock value      */
4121 /*                                                                          */
4122 /* Get the new value for the lock integer, set it and return the old value  */
4123 /* in *lockp.                                                               */
4124 /* ------------------------------------------------------------------------ */
4125 int
ipf_lock(caddr_t data,int * lockp)4126 ipf_lock(caddr_t data, int *lockp)
4127 {
4128 	int arg, err;
4129 
4130 	err = BCOPYIN(data, &arg, sizeof(arg));
4131 	if (err != 0)
4132 		return (EFAULT);
4133 	err = BCOPYOUT(lockp, data, sizeof(*lockp));
4134 	if (err != 0)
4135 		return (EFAULT);
4136 	*lockp = arg;
4137 	return (0);
4138 }
4139 
4140 
4141 /* ------------------------------------------------------------------------ */
4142 /* Function:    ipf_getstat                                                 */
4143 /* Returns:     Nil                                                         */
4144 /* Parameters:  softc(I) - pointer to soft context main structure           */
4145 /*              fiop(I)  - pointer to ipfilter stats structure              */
4146 /*              rev(I)   - version claim by program doing ioctl             */
4147 /*                                                                          */
4148 /* Stores a copy of current pointers, counters, etc, in the friostat        */
4149 /* structure.                                                               */
4150 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the    */
4151 /* program is looking for. This ensure that validation of the version it    */
4152 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will      */
4153 /* allow older binaries to work but kernels without it will not.            */
4154 /* ------------------------------------------------------------------------ */
4155 /*ARGSUSED*/
4156 static void
ipf_getstat(ipf_main_softc_t * softc,friostat_t * fiop,int rev)4157 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev)
4158 {
4159 	int i;
4160 
4161 	bcopy((char *)softc->ipf_stats, (char *)fiop->f_st,
4162 	      sizeof(ipf_statistics_t) * 2);
4163 	fiop->f_locks[IPL_LOGSTATE] = -1;
4164 	fiop->f_locks[IPL_LOGNAT] = -1;
4165 	fiop->f_locks[IPL_LOGIPF] = -1;
4166 	fiop->f_locks[IPL_LOGAUTH] = -1;
4167 
4168 	fiop->f_ipf[0][0] = softc->ipf_rules[0][0];
4169 	fiop->f_acct[0][0] = softc->ipf_acct[0][0];
4170 	fiop->f_ipf[0][1] = softc->ipf_rules[0][1];
4171 	fiop->f_acct[0][1] = softc->ipf_acct[0][1];
4172 	fiop->f_ipf[1][0] = softc->ipf_rules[1][0];
4173 	fiop->f_acct[1][0] = softc->ipf_acct[1][0];
4174 	fiop->f_ipf[1][1] = softc->ipf_rules[1][1];
4175 	fiop->f_acct[1][1] = softc->ipf_acct[1][1];
4176 
4177 	fiop->f_ticks = softc->ipf_ticks;
4178 	fiop->f_active = softc->ipf_active;
4179 	fiop->f_froute[0] = softc->ipf_frouteok[0];
4180 	fiop->f_froute[1] = softc->ipf_frouteok[1];
4181 	fiop->f_rb_no_mem = softc->ipf_rb_no_mem;
4182 	fiop->f_rb_node_max = softc->ipf_rb_node_max;
4183 
4184 	fiop->f_running = softc->ipf_running;
4185 	for (i = 0; i < IPL_LOGSIZE; i++) {
4186 		fiop->f_groups[i][0] = softc->ipf_groups[i][0];
4187 		fiop->f_groups[i][1] = softc->ipf_groups[i][1];
4188 	}
4189 #ifdef  IPFILTER_LOG
4190 	fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF);
4191 	fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF);
4192 	fiop->f_logging = 1;
4193 #else
4194 	fiop->f_log_ok = 0;
4195 	fiop->f_log_fail = 0;
4196 	fiop->f_logging = 0;
4197 #endif
4198 	fiop->f_defpass = softc->ipf_pass;
4199 	fiop->f_features = ipf_features;
4200 
4201 #ifdef IPFILTER_COMPAT
4202 	snprintf(fiop->f_version, sizeof(friostat.f_version), "IP Filter: v%d.%d.%d",
4203 		(rev / 1000000) % 100,
4204 		(rev / 10000) % 100,
4205 		(rev / 100) % 100);
4206 #else
4207 	rev = rev;
4208 	(void) strncpy(fiop->f_version, ipfilter_version,
4209 		       sizeof(fiop->f_version));
4210 #endif
4211 }
4212 
4213 
4214 #ifdef	USE_INET6
4215 int icmptoicmp6types[ICMP_MAXTYPE+1] = {
4216 	ICMP6_ECHO_REPLY,	/* 0: ICMP_ECHOREPLY */
4217 	-1,			/* 1: UNUSED */
4218 	-1,			/* 2: UNUSED */
4219 	ICMP6_DST_UNREACH,	/* 3: ICMP_UNREACH */
4220 	-1,			/* 4: ICMP_SOURCEQUENCH */
4221 	ND_REDIRECT,		/* 5: ICMP_REDIRECT */
4222 	-1,			/* 6: UNUSED */
4223 	-1,			/* 7: UNUSED */
4224 	ICMP6_ECHO_REQUEST,	/* 8: ICMP_ECHO */
4225 	-1,			/* 9: UNUSED */
4226 	-1,			/* 10: UNUSED */
4227 	ICMP6_TIME_EXCEEDED,	/* 11: ICMP_TIMXCEED */
4228 	ICMP6_PARAM_PROB,	/* 12: ICMP_PARAMPROB */
4229 	-1,			/* 13: ICMP_TSTAMP */
4230 	-1,			/* 14: ICMP_TSTAMPREPLY */
4231 	-1,			/* 15: ICMP_IREQ */
4232 	-1,			/* 16: ICMP_IREQREPLY */
4233 	-1,			/* 17: ICMP_MASKREQ */
4234 	-1,			/* 18: ICMP_MASKREPLY */
4235 };
4236 
4237 
4238 int	icmptoicmp6unreach[ICMP_MAX_UNREACH] = {
4239 	ICMP6_DST_UNREACH_ADDR,		/* 0: ICMP_UNREACH_NET */
4240 	ICMP6_DST_UNREACH_ADDR,		/* 1: ICMP_UNREACH_HOST */
4241 	-1,				/* 2: ICMP_UNREACH_PROTOCOL */
4242 	ICMP6_DST_UNREACH_NOPORT,	/* 3: ICMP_UNREACH_PORT */
4243 	-1,				/* 4: ICMP_UNREACH_NEEDFRAG */
4244 	ICMP6_DST_UNREACH_NOTNEIGHBOR,	/* 5: ICMP_UNREACH_SRCFAIL */
4245 	ICMP6_DST_UNREACH_ADDR,		/* 6: ICMP_UNREACH_NET_UNKNOWN */
4246 	ICMP6_DST_UNREACH_ADDR,		/* 7: ICMP_UNREACH_HOST_UNKNOWN */
4247 	-1,				/* 8: ICMP_UNREACH_ISOLATED */
4248 	ICMP6_DST_UNREACH_ADMIN,	/* 9: ICMP_UNREACH_NET_PROHIB */
4249 	ICMP6_DST_UNREACH_ADMIN,	/* 10: ICMP_UNREACH_HOST_PROHIB */
4250 	-1,				/* 11: ICMP_UNREACH_TOSNET */
4251 	-1,				/* 12: ICMP_UNREACH_TOSHOST */
4252 	ICMP6_DST_UNREACH_ADMIN,	/* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
4253 };
4254 int	icmpreplytype6[ICMP6_MAXTYPE + 1];
4255 #endif
4256 
4257 int	icmpreplytype4[ICMP_MAXTYPE + 1];
4258 
4259 
4260 /* ------------------------------------------------------------------------ */
4261 /* Function:    ipf_matchicmpqueryreply                                     */
4262 /* Returns:     int - 1 if "icmp" is a valid reply to "ic" else 0.          */
4263 /* Parameters:  v(I)    - IP protocol version (4 or 6)                      */
4264 /*              ic(I)   - ICMP information                                  */
4265 /*              icmp(I) - ICMP packet header                                */
4266 /*              rev(I)  - direction (0 = forward/1 = reverse) of packet     */
4267 /*                                                                          */
4268 /* Check if the ICMP packet defined by the header pointed to by icmp is a   */
4269 /* reply to one as described by what's in ic.  If it is a match, return 1,  */
4270 /* else return 0 for no match.                                              */
4271 /* ------------------------------------------------------------------------ */
4272 int
ipf_matchicmpqueryreply(int v,icmpinfo_t * ic,icmphdr_t * icmp,int rev)4273 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev)
4274 {
4275 	int ictype;
4276 
4277 	ictype = ic->ici_type;
4278 
4279 	if (v == 4) {
4280 		/*
4281 		 * If we matched its type on the way in, then when going out
4282 		 * it will still be the same type.
4283 		 */
4284 		if ((!rev && (icmp->icmp_type == ictype)) ||
4285 		    (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) {
4286 			if (icmp->icmp_type != ICMP_ECHOREPLY)
4287 				return (1);
4288 			if (icmp->icmp_id == ic->ici_id)
4289 				return (1);
4290 		}
4291 	}
4292 #ifdef	USE_INET6
4293 	else if (v == 6) {
4294 		if ((!rev && (icmp->icmp_type == ictype)) ||
4295 		    (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) {
4296 			if (icmp->icmp_type != ICMP6_ECHO_REPLY)
4297 				return (1);
4298 			if (icmp->icmp_id == ic->ici_id)
4299 				return (1);
4300 		}
4301 	}
4302 #endif
4303 	return (0);
4304 }
4305 
4306 
4307 /*
4308  * IFNAMES are located in the variable length field starting at
4309  * frentry.fr_names. As pointers within the struct cannot be passed
4310  * to the kernel from ipf(8), an offset is used. An offset of -1 means it
4311  * is unused (invalid). If it is used (valid) it is an offset to the
4312  * character string of an interface name or a comment. The following
4313  * macros will assist those who follow to understand the code.
4314  */
4315 #define IPF_IFNAME_VALID(_a)	(_a != -1)
4316 #define IPF_IFNAME_INVALID(_a)	(_a == -1)
4317 #define IPF_IFNAMES_DIFFERENT(_a)	\
4318 	!((IPF_IFNAME_INVALID(fr1->_a) &&	\
4319 	IPF_IFNAME_INVALID(fr2->_a)) ||	\
4320 	(IPF_IFNAME_VALID(fr1->_a) &&	\
4321 	IPF_IFNAME_VALID(fr2->_a) &&	\
4322 	!strcmp(FR_NAME(fr1, _a), FR_NAME(fr2, _a))))
4323 #define IPF_FRDEST_DIFFERENT(_a)	\
4324 	(memcmp(&fr1->_a.fd_addr, &fr2->_a.fd_addr,	\
4325 	offsetof(frdest_t, fd_name) - offsetof(frdest_t, fd_addr)) ||	\
4326 	IPF_IFNAMES_DIFFERENT(_a.fd_name))
4327 
4328 
4329 /* ------------------------------------------------------------------------ */
4330 /* Function:    ipf_rule_compare                                            */
4331 /* Parameters:  fr1(I) - first rule structure to compare                    */
4332 /*              fr2(I) - second rule structure to compare                   */
4333 /* Returns:     int    - 0 == rules are the same, else mismatch             */
4334 /*                                                                          */
4335 /* Compare two rules and return 0 if they match or a number indicating      */
4336 /* which of the individual checks failed.                                   */
4337 /* ------------------------------------------------------------------------ */
4338 static int
ipf_rule_compare(frentry_t * fr1,frentry_t * fr2)4339 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2)
4340 {
4341 	int i;
4342 
4343 	if (fr1->fr_cksum != fr2->fr_cksum)
4344 		return (1);
4345 	if (fr1->fr_size != fr2->fr_size)
4346 		return (2);
4347 	if (fr1->fr_dsize != fr2->fr_dsize)
4348 		return (3);
4349 	if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func, FR_CMPSIZ)
4350 	    != 0)
4351 		return (4);
4352 	/*
4353 	 * XXX:	There is still a bug here as different rules with the
4354 	 *	the same interfaces but in a different order will compare
4355 	 *	differently. But since multiple interfaces in a rule doesn't
4356 	 *	work anyway a simple straightforward compare is performed
4357 	 *	here. Ultimately frentry_t creation will need to be
4358 	 *	revisited in ipf_y.y. While the other issue, recognition
4359 	 *	of only the first interface in a list of interfaces will
4360 	 *	need to be separately addressed along with why only four.
4361 	 */
4362 	for (i = 0; i < FR_NUM(fr1->fr_ifnames); i++) {
4363 		/*
4364 		 * XXX:	It's either the same index or uninitialized.
4365 		 * 	We assume this because multiple interfaces
4366 		 *	referenced by the same rule doesn't work anyway.
4367 		 */
4368 		if (IPF_IFNAMES_DIFFERENT(fr_ifnames[i]))
4369 			return (5);
4370 	}
4371 
4372 	if (IPF_FRDEST_DIFFERENT(fr_tif))
4373 		return (6);
4374 	if (IPF_FRDEST_DIFFERENT(fr_rif))
4375 		return (7);
4376 	if (IPF_FRDEST_DIFFERENT(fr_dif))
4377 		return (8);
4378 	if (!fr1->fr_data && !fr2->fr_data)
4379 		return (0);	/* move along, nothing to see here */
4380 	if (fr1->fr_data && fr2->fr_data) {
4381 		if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize) == 0)
4382 			return (0);	/* same */
4383 	}
4384 	return (9);
4385 }
4386 
4387 
4388 /* ------------------------------------------------------------------------ */
4389 /* Function:    frrequest                                                   */
4390 /* Returns:     int - 0 == success, > 0 == errno value                      */
4391 /* Parameters:  unit(I)     - device for which this is for                  */
4392 /*              req(I)      - ioctl command (SIOC*)                         */
4393 /*              data(I)     - pointr to ioctl data                          */
4394 /*              set(I)      - 1 or 0 (filter set)                           */
4395 /*              makecopy(I) - flag indicating whether data points to a rule */
4396 /*                            in kernel space & hence doesn't need copying. */
4397 /*                                                                          */
4398 /* This function handles all the requests which operate on the list of      */
4399 /* filter rules.  This includes adding, deleting, insertion.  It is also    */
4400 /* responsible for creating groups when a "head" rule is loaded.  Interface */
4401 /* names are resolved here and other sanity checks are made on the content  */
4402 /* of the rule structure being loaded.  If a rule has user defined timeouts */
4403 /* then make sure they are created and initialised before exiting.          */
4404 /* ------------------------------------------------------------------------ */
4405 int
frrequest(ipf_main_softc_t * softc,int unit,ioctlcmd_t req,caddr_t data,int set,int makecopy)4406 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data,
4407 	int set, int makecopy)
4408 {
4409 	int error = 0, in, family, need_free = 0;
4410 	enum {	OP_ADD,		/* add rule */
4411 		OP_REM,		/* remove rule */
4412 		OP_ZERO 	/* zero statistics and counters */ }
4413 		addrem = OP_ADD;
4414 	frentry_t frd, *fp, *f, **fprev, **ftail;
4415 	void *ptr, *uptr, *cptr;
4416 	u_int *p, *pp;
4417 	frgroup_t *fg;
4418 	char *group;
4419 
4420 	ptr = NULL;
4421 	cptr = NULL;
4422 	fg = NULL;
4423 	fp = &frd;
4424 	if (makecopy != 0) {
4425 		bzero(fp, sizeof(frd));
4426 		error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY);
4427 		if (error) {
4428 			return (error);
4429 		}
4430 		if ((fp->fr_type & FR_T_BUILTIN) != 0) {
4431 			IPFERROR(6);
4432 			return (EINVAL);
4433 		}
4434 		KMALLOCS(f, frentry_t *, fp->fr_size);
4435 		if (f == NULL) {
4436 			IPFERROR(131);
4437 			return (ENOMEM);
4438 		}
4439 		bzero(f, fp->fr_size);
4440 		error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY,
4441 				    fp->fr_size);
4442 		if (error) {
4443 			KFREES(f, fp->fr_size);
4444 			return (error);
4445 		}
4446 
4447 		fp = f;
4448 		f = NULL;
4449 		fp->fr_next = NULL;
4450 		fp->fr_dnext = NULL;
4451 		fp->fr_pnext = NULL;
4452 		fp->fr_pdnext = NULL;
4453 		fp->fr_grp = NULL;
4454 		fp->fr_grphead = NULL;
4455 		fp->fr_icmpgrp = NULL;
4456 		fp->fr_isc = (void *)-1;
4457 		fp->fr_ptr = NULL;
4458 		fp->fr_ref = 0;
4459 		fp->fr_flags |= FR_COPIED;
4460 	} else {
4461 		fp = (frentry_t *)data;
4462 		if ((fp->fr_type & FR_T_BUILTIN) == 0) {
4463 			IPFERROR(7);
4464 			return (EINVAL);
4465 		}
4466 		fp->fr_flags &= ~FR_COPIED;
4467 	}
4468 
4469 	if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
4470 	    ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) {
4471 		IPFERROR(8);
4472 		error = EINVAL;
4473 		goto donenolock;
4474 	}
4475 
4476 	family = fp->fr_family;
4477 	uptr = fp->fr_data;
4478 
4479 	if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR ||
4480 	    req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR)
4481 		addrem = OP_ADD;	/* Add rule */
4482 	else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR)
4483 		addrem = OP_REM;		/* Remove rule */
4484 	else if (req == (ioctlcmd_t)SIOCZRLST)
4485 		addrem = OP_ZERO;	/* Zero statistics and counters */
4486 	else {
4487 		IPFERROR(9);
4488 		error = EINVAL;
4489 		goto donenolock;
4490 	}
4491 
4492 	/*
4493 	 * Only filter rules for IPv4 or IPv6 are accepted.
4494 	 */
4495 	if (family == AF_INET) {
4496 		/*EMPTY*/;
4497 #ifdef	USE_INET6
4498 	} else if (family == AF_INET6) {
4499 		/*EMPTY*/;
4500 #endif
4501 	} else if (family != 0) {
4502 		IPFERROR(10);
4503 		error = EINVAL;
4504 		goto donenolock;
4505 	}
4506 
4507 	/*
4508 	 * If the rule is being loaded from user space, i.e. we had to copy it
4509 	 * into kernel space, then do not trust the function pointer in the
4510 	 * rule.
4511 	 */
4512 	if ((makecopy == 1) && (fp->fr_func != NULL)) {
4513 		if (ipf_findfunc(fp->fr_func) == NULL) {
4514 			IPFERROR(11);
4515 			error = ESRCH;
4516 			goto donenolock;
4517 		}
4518 
4519 		if (addrem == OP_ADD) {
4520 			error = ipf_funcinit(softc, fp);
4521 			if (error != 0)
4522 				goto donenolock;
4523 		}
4524 	}
4525 	if ((fp->fr_flags & FR_CALLNOW) &&
4526 	    ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
4527 		IPFERROR(142);
4528 		error = ESRCH;
4529 		goto donenolock;
4530 	}
4531 	if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) &&
4532 	    ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
4533 		IPFERROR(143);
4534 		error = ESRCH;
4535 		goto donenolock;
4536 	}
4537 
4538 	ptr = NULL;
4539 	cptr = NULL;
4540 
4541 	if (FR_ISACCOUNT(fp->fr_flags))
4542 		unit = IPL_LOGCOUNT;
4543 
4544 	/*
4545 	 * Check that each group name in the rule has a start index that
4546 	 * is valid.
4547 	 */
4548 	if (fp->fr_icmphead != -1) {
4549 		if ((fp->fr_icmphead < 0) ||
4550 		    (fp->fr_icmphead >= fp->fr_namelen)) {
4551 			IPFERROR(136);
4552 			error = EINVAL;
4553 			goto donenolock;
4554 		}
4555 		if (!strcmp(FR_NAME(fp, fr_icmphead), "0"))
4556 			fp->fr_names[fp->fr_icmphead] = '\0';
4557 	}
4558 
4559 	if (fp->fr_grhead != -1) {
4560 		if ((fp->fr_grhead < 0) ||
4561 		    (fp->fr_grhead >= fp->fr_namelen)) {
4562 			IPFERROR(137);
4563 			error = EINVAL;
4564 			goto donenolock;
4565 		}
4566 		if (!strcmp(FR_NAME(fp, fr_grhead), "0"))
4567 			fp->fr_names[fp->fr_grhead] = '\0';
4568 	}
4569 
4570 	if (fp->fr_group != -1) {
4571 		if ((fp->fr_group < 0) ||
4572 		    (fp->fr_group >= fp->fr_namelen)) {
4573 			IPFERROR(138);
4574 			error = EINVAL;
4575 			goto donenolock;
4576 		}
4577 		if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) {
4578 			/*
4579 			 * Allow loading rules that are in groups to cause
4580 			 * them to be created if they don't already exit.
4581 			 */
4582 			group = FR_NAME(fp, fr_group);
4583 			if (addrem == OP_ADD) {
4584 				fg = ipf_group_add(softc, group, NULL,
4585 						   fp->fr_flags, unit, set);
4586 				fp->fr_grp = fg;
4587 			} else {
4588 				fg = ipf_findgroup(softc, group, unit,
4589 						   set, NULL);
4590 				if (fg == NULL) {
4591 					IPFERROR(12);
4592 					error = ESRCH;
4593 					goto donenolock;
4594 				}
4595 			}
4596 
4597 			if (fg->fg_flags == 0) {
4598 				fg->fg_flags = fp->fr_flags & FR_INOUT;
4599 			} else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) {
4600 				IPFERROR(13);
4601 				error = ESRCH;
4602 				goto donenolock;
4603 			}
4604 		}
4605 	} else {
4606 		/*
4607 		 * If a rule is going to be part of a group then it does
4608 		 * not matter whether it is an in or out rule, but if it
4609 		 * isn't in a group, then it does...
4610 		 */
4611 		if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) {
4612 			IPFERROR(14);
4613 			error = EINVAL;
4614 			goto donenolock;
4615 		}
4616 	}
4617 	in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
4618 
4619 	/*
4620 	 * Work out which rule list this change is being applied to.
4621 	 */
4622 	ftail = NULL;
4623 	fprev = NULL;
4624 	if (unit == IPL_LOGAUTH) {
4625 		if ((fp->fr_tifs[0].fd_ptr != NULL) ||
4626 		    (fp->fr_tifs[1].fd_ptr != NULL) ||
4627 		    (fp->fr_dif.fd_ptr != NULL) ||
4628 		    (fp->fr_flags & FR_FASTROUTE)) {
4629 			softc->ipf_interror = 145;
4630 			error = EINVAL;
4631 			goto donenolock;
4632 		}
4633 		fprev = ipf_auth_rulehead(softc);
4634 	} else {
4635 		if (FR_ISACCOUNT(fp->fr_flags))
4636 			fprev = &softc->ipf_acct[in][set];
4637 		else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
4638 			fprev = &softc->ipf_rules[in][set];
4639 	}
4640 	if (fprev == NULL) {
4641 		IPFERROR(15);
4642 		error = ESRCH;
4643 		goto donenolock;
4644 	}
4645 
4646 	if (fg != NULL)
4647 		fprev = &fg->fg_start;
4648 
4649 	/*
4650 	 * Copy in extra data for the rule.
4651 	 */
4652 	if (fp->fr_dsize != 0) {
4653 		if (makecopy != 0) {
4654 			KMALLOCS(ptr, void *, fp->fr_dsize);
4655 			if (ptr == NULL) {
4656 				IPFERROR(16);
4657 				error = ENOMEM;
4658 				goto donenolock;
4659 			}
4660 
4661 			/*
4662 			 * The bcopy case is for when the data is appended
4663 			 * to the rule by ipf_in_compat().
4664 			 */
4665 			if (uptr >= (void *)fp &&
4666 			    uptr < (void *)((char *)fp + fp->fr_size)) {
4667 				bcopy(uptr, ptr, fp->fr_dsize);
4668 				error = 0;
4669 			} else {
4670 				error = COPYIN(uptr, ptr, fp->fr_dsize);
4671 				if (error != 0) {
4672 					IPFERROR(17);
4673 					error = EFAULT;
4674 					goto donenolock;
4675 				}
4676 			}
4677 		} else {
4678 			ptr = uptr;
4679 		}
4680 		fp->fr_data = ptr;
4681 	} else {
4682 		fp->fr_data = NULL;
4683 	}
4684 
4685 	/*
4686 	 * Perform per-rule type sanity checks of their members.
4687 	 * All code after this needs to be aware that allocated memory
4688 	 * may need to be free'd before exiting.
4689 	 */
4690 	switch (fp->fr_type & ~FR_T_BUILTIN)
4691 	{
4692 #if defined(IPFILTER_BPF)
4693 	case FR_T_BPFOPC :
4694 		if (fp->fr_dsize == 0) {
4695 			IPFERROR(19);
4696 			error = EINVAL;
4697 			break;
4698 		}
4699 		if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
4700 			IPFERROR(20);
4701 			error = EINVAL;
4702 			break;
4703 		}
4704 		break;
4705 #endif
4706 	case FR_T_IPF :
4707 		/*
4708 		 * Preparation for error case at the bottom of this function.
4709 		 */
4710 		if (fp->fr_datype == FRI_LOOKUP)
4711 			fp->fr_dstptr = NULL;
4712 		if (fp->fr_satype == FRI_LOOKUP)
4713 			fp->fr_srcptr = NULL;
4714 
4715 		if (fp->fr_dsize != sizeof(fripf_t)) {
4716 			IPFERROR(21);
4717 			error = EINVAL;
4718 			break;
4719 		}
4720 
4721 		/*
4722 		 * Allowing a rule with both "keep state" and "with oow" is
4723 		 * pointless because adding a state entry to the table will
4724 		 * fail with the out of window (oow) flag set.
4725 		 */
4726 		if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) {
4727 			IPFERROR(22);
4728 			error = EINVAL;
4729 			break;
4730 		}
4731 
4732 		switch (fp->fr_satype)
4733 		{
4734 		case FRI_BROADCAST :
4735 		case FRI_DYNAMIC :
4736 		case FRI_NETWORK :
4737 		case FRI_NETMASKED :
4738 		case FRI_PEERADDR :
4739 			if (fp->fr_sifpidx < 0) {
4740 				IPFERROR(23);
4741 				error = EINVAL;
4742 			}
4743 			break;
4744 		case FRI_LOOKUP :
4745 			fp->fr_srcptr = ipf_findlookup(softc, unit, fp,
4746 						       &fp->fr_src6,
4747 						       &fp->fr_smsk6);
4748 			if (fp->fr_srcfunc == NULL) {
4749 				IPFERROR(132);
4750 				error = ESRCH;
4751 				break;
4752 			}
4753 			break;
4754 		case FRI_NORMAL :
4755 			break;
4756 		default :
4757 			IPFERROR(133);
4758 			error = EINVAL;
4759 			break;
4760 		}
4761 		if (error != 0)
4762 			break;
4763 
4764 		switch (fp->fr_datype)
4765 		{
4766 		case FRI_BROADCAST :
4767 		case FRI_DYNAMIC :
4768 		case FRI_NETWORK :
4769 		case FRI_NETMASKED :
4770 		case FRI_PEERADDR :
4771 			if (fp->fr_difpidx < 0) {
4772 				IPFERROR(24);
4773 				error = EINVAL;
4774 			}
4775 			break;
4776 		case FRI_LOOKUP :
4777 			fp->fr_dstptr = ipf_findlookup(softc, unit, fp,
4778 						       &fp->fr_dst6,
4779 						       &fp->fr_dmsk6);
4780 			if (fp->fr_dstfunc == NULL) {
4781 				IPFERROR(134);
4782 				error = ESRCH;
4783 			}
4784 			break;
4785 		case FRI_NORMAL :
4786 			break;
4787 		default :
4788 			IPFERROR(135);
4789 			error = EINVAL;
4790 		}
4791 		break;
4792 
4793 	case FR_T_NONE :
4794 	case FR_T_CALLFUNC :
4795 	case FR_T_COMPIPF :
4796 		break;
4797 
4798 	case FR_T_IPFEXPR :
4799 		if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) {
4800 			IPFERROR(25);
4801 			error = EINVAL;
4802 		}
4803 		break;
4804 
4805 	default :
4806 		IPFERROR(26);
4807 		error = EINVAL;
4808 		break;
4809 	}
4810 	if (error != 0)
4811 		goto donenolock;
4812 
4813 	if (fp->fr_tif.fd_name != -1) {
4814 		if ((fp->fr_tif.fd_name < 0) ||
4815 		    (fp->fr_tif.fd_name >= fp->fr_namelen)) {
4816 			IPFERROR(139);
4817 			error = EINVAL;
4818 			goto donenolock;
4819 		}
4820 	}
4821 
4822 	if (fp->fr_dif.fd_name != -1) {
4823 		if ((fp->fr_dif.fd_name < 0) ||
4824 		    (fp->fr_dif.fd_name >= fp->fr_namelen)) {
4825 			IPFERROR(140);
4826 			error = EINVAL;
4827 			goto donenolock;
4828 		}
4829 	}
4830 
4831 	if (fp->fr_rif.fd_name != -1) {
4832 		if ((fp->fr_rif.fd_name < 0) ||
4833 		    (fp->fr_rif.fd_name >= fp->fr_namelen)) {
4834 			IPFERROR(141);
4835 			error = EINVAL;
4836 			goto donenolock;
4837 		}
4838 	}
4839 
4840 	/*
4841 	 * Lookup all the interface names that are part of the rule.
4842 	 */
4843 	error = ipf_synclist(softc, fp, NULL);
4844 	if (error != 0)
4845 		goto donenolock;
4846 	fp->fr_statecnt = 0;
4847 	if (fp->fr_srctrack.ht_max_nodes != 0)
4848 		ipf_rb_ht_init(&fp->fr_srctrack);
4849 
4850 	/*
4851 	 * Look for an existing matching filter rule, but don't include the
4852 	 * next or interface pointer in the comparison (fr_next, fr_ifa).
4853 	 * This elminates rules which are indentical being loaded.  Checksum
4854 	 * the constant part of the filter rule to make comparisons quicker
4855 	 * (this meaning no pointers are included).
4856 	 */
4857 	pp = (u_int *)(fp->fr_caddr + fp->fr_dsize);
4858 	for (fp->fr_cksum = 0, p = (u_int *)fp->fr_data; p < pp; p++)
4859 		fp->fr_cksum += *p;
4860 
4861 	WRITE_ENTER(&softc->ipf_mutex);
4862 
4863 	/*
4864 	 * Now that the filter rule lists are locked, we can walk the
4865 	 * chain of them without fear.
4866 	 */
4867 	ftail = fprev;
4868 	for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) {
4869 		if (fp->fr_collect <= f->fr_collect) {
4870 			ftail = fprev;
4871 			f = NULL;
4872 			break;
4873 		}
4874 		fprev = ftail;
4875 	}
4876 
4877 	for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
4878 		if (ipf_rule_compare(fp, f) == 0)
4879 			break;
4880 	}
4881 
4882 	/*
4883 	 * If zero'ing statistics, copy current to caller and zero.
4884 	 */
4885 	if (addrem == OP_ZERO) {
4886 		if (f == NULL) {
4887 			IPFERROR(27);
4888 			error = ESRCH;
4889 		} else {
4890 			/*
4891 			 * Copy and reduce lock because of impending copyout.
4892 			 * Well we should, but if we do then the atomicity of
4893 			 * this call and the correctness of fr_hits and
4894 			 * fr_bytes cannot be guaranteed.  As it is, this code
4895 			 * only resets them to 0 if they are successfully
4896 			 * copied out into user space.
4897 			 */
4898 			bcopy((char *)f, (char *)fp, f->fr_size);
4899 			/* MUTEX_DOWNGRADE(&softc->ipf_mutex); */
4900 
4901 			/*
4902 			 * When we copy this rule back out, set the data
4903 			 * pointer to be what it was in user space.
4904 			 */
4905 			fp->fr_data = uptr;
4906 			error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY);
4907 
4908 			if (error == 0) {
4909 				if ((f->fr_dsize != 0) && (uptr != NULL)) {
4910 					error = COPYOUT(f->fr_data, uptr,
4911 							f->fr_dsize);
4912 					if (error == 0) {
4913 						f->fr_hits = 0;
4914 						f->fr_bytes = 0;
4915 					} else {
4916 						IPFERROR(28);
4917 						error = EFAULT;
4918 					}
4919 				}
4920 			}
4921 		}
4922 
4923 		if (makecopy != 0) {
4924 			if (ptr != NULL) {
4925 				KFREES(ptr, fp->fr_dsize);
4926 			}
4927 			KFREES(fp, fp->fr_size);
4928 		}
4929 		RWLOCK_EXIT(&softc->ipf_mutex);
4930 		return (error);
4931 	}
4932 
4933 	if (f == NULL) {
4934 		/*
4935 		 * At the end of this, ftail must point to the place where the
4936 		 * new rule is to be saved/inserted/added.
4937 		 * For SIOCAD*FR, this should be the last rule in the group of
4938 		 * rules that have equal fr_collect fields.
4939 		 * For SIOCIN*FR, ...
4940 		 */
4941 		if (req == (ioctlcmd_t)SIOCADAFR ||
4942 		    req == (ioctlcmd_t)SIOCADIFR) {
4943 
4944 			for (ftail = fprev; (f = *ftail) != NULL; ) {
4945 				if (f->fr_collect > fp->fr_collect)
4946 					break;
4947 				ftail = &f->fr_next;
4948 				fprev = ftail;
4949 			}
4950 			ftail = fprev;
4951 			f = NULL;
4952 			ptr = NULL;
4953 		} else if (req == (ioctlcmd_t)SIOCINAFR ||
4954 			   req == (ioctlcmd_t)SIOCINIFR) {
4955 			while ((f = *fprev) != NULL) {
4956 				if (f->fr_collect >= fp->fr_collect)
4957 					break;
4958 				fprev = &f->fr_next;
4959 			}
4960   			ftail = fprev;
4961   			if (fp->fr_hits != 0) {
4962 				while (fp->fr_hits && (f = *ftail)) {
4963 					if (f->fr_collect != fp->fr_collect)
4964 						break;
4965 					fprev = ftail;
4966   					ftail = &f->fr_next;
4967 					fp->fr_hits--;
4968 				}
4969   			}
4970   			f = NULL;
4971   			ptr = NULL;
4972 		}
4973 	}
4974 
4975 	/*
4976 	 * Request to remove a rule.
4977 	 */
4978 	if (addrem == OP_REM) {
4979 		if (f == NULL) {
4980 			IPFERROR(29);
4981 			error = ESRCH;
4982 		} else {
4983 			/*
4984 			 * Do not allow activity from user space to interfere
4985 			 * with rules not loaded that way.
4986 			 */
4987 			if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
4988 				IPFERROR(30);
4989 				error = EPERM;
4990 				goto done;
4991 			}
4992 
4993 			/*
4994 			 * Return EBUSY if the rule is being reference by
4995 			 * something else (eg state information.)
4996 			 */
4997 			if (f->fr_ref > 1) {
4998 				IPFERROR(31);
4999 				error = EBUSY;
5000 				goto done;
5001 			}
5002 #ifdef	IPFILTER_SCAN
5003 			if (f->fr_isctag != -1 &&
5004 			    (f->fr_isc != (struct ipscan *)-1))
5005 				ipf_scan_detachfr(f);
5006 #endif
5007 
5008 			if (unit == IPL_LOGAUTH) {
5009 				error = ipf_auth_precmd(softc, req, f, ftail);
5010 				goto done;
5011 			}
5012 
5013 			ipf_rule_delete(softc, f, unit, set);
5014 
5015 			need_free = makecopy;
5016 		}
5017 	} else {
5018 		/*
5019 		 * Not removing, so we must be adding/inserting a rule.
5020 		 */
5021 		if (f != NULL) {
5022 			IPFERROR(32);
5023 			error = EEXIST;
5024 			goto done;
5025 		}
5026 		if (unit == IPL_LOGAUTH) {
5027 			error = ipf_auth_precmd(softc, req, fp, ftail);
5028 			goto done;
5029 		}
5030 
5031 		MUTEX_NUKE(&fp->fr_lock);
5032 		MUTEX_INIT(&fp->fr_lock, "filter rule lock");
5033 		if (fp->fr_die != 0)
5034 			ipf_rule_expire_insert(softc, fp, set);
5035 
5036 		fp->fr_hits = 0;
5037 		if (makecopy != 0)
5038 			fp->fr_ref = 1;
5039 		fp->fr_pnext = ftail;
5040 		fp->fr_next = *ftail;
5041 		if (fp->fr_next != NULL)
5042 			fp->fr_next->fr_pnext = &fp->fr_next;
5043 		*ftail = fp;
5044 		ipf_fixskip(ftail, fp, 1);
5045 
5046 		fp->fr_icmpgrp = NULL;
5047 		if (fp->fr_icmphead != -1) {
5048 			group = FR_NAME(fp, fr_icmphead);
5049 			fg = ipf_group_add(softc, group, fp, 0, unit, set);
5050 			fp->fr_icmpgrp = fg;
5051 		}
5052 
5053 		fp->fr_grphead = NULL;
5054 		if (fp->fr_grhead != -1) {
5055 			group = FR_NAME(fp, fr_grhead);
5056 			fg = ipf_group_add(softc, group, fp, fp->fr_flags,
5057 					   unit, set);
5058 			fp->fr_grphead = fg;
5059 		}
5060 	}
5061 done:
5062 	RWLOCK_EXIT(&softc->ipf_mutex);
5063 donenolock:
5064 	if (need_free || (error != 0)) {
5065 		if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
5066 			if ((fp->fr_satype == FRI_LOOKUP) &&
5067 			    (fp->fr_srcptr != NULL))
5068 				ipf_lookup_deref(softc, fp->fr_srctype,
5069 						 fp->fr_srcptr);
5070 			if ((fp->fr_datype == FRI_LOOKUP) &&
5071 			    (fp->fr_dstptr != NULL))
5072 				ipf_lookup_deref(softc, fp->fr_dsttype,
5073 						 fp->fr_dstptr);
5074 		}
5075 		if (fp->fr_grp != NULL) {
5076 			WRITE_ENTER(&softc->ipf_mutex);
5077 			ipf_group_del(softc, fp->fr_grp, fp);
5078 			RWLOCK_EXIT(&softc->ipf_mutex);
5079 		}
5080 		if ((ptr != NULL) && (makecopy != 0)) {
5081 			KFREES(ptr, fp->fr_dsize);
5082 		}
5083 		KFREES(fp, fp->fr_size);
5084 	}
5085 	return (error);
5086 }
5087 
5088 
5089 /* ------------------------------------------------------------------------ */
5090 /* Function:   ipf_rule_delete                                              */
5091 /* Returns:    Nil                                                          */
5092 /* Parameters: softc(I) - pointer to soft context main structure            */
5093 /*             f(I)     - pointer to the rule being deleted                 */
5094 /*             ftail(I) - pointer to the pointer to f                       */
5095 /*             unit(I)  - device for which this is for                      */
5096 /*             set(I)   - 1 or 0 (filter set)                               */
5097 /*                                                                          */
5098 /* This function attempts to do what it can to delete a filter rule: remove */
5099 /* it from any linked lists and remove any groups it is responsible for.    */
5100 /* But in the end, removing a rule can only drop the reference count - we   */
5101 /* must use that as the guide for whether or not it can be freed.           */
5102 /* ------------------------------------------------------------------------ */
5103 static void
ipf_rule_delete(ipf_main_softc_t * softc,frentry_t * f,int unit,int set)5104 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set)
5105 {
5106 
5107 	/*
5108 	 * If fr_pdnext is set, then the rule is on the expire list, so
5109 	 * remove it from there.
5110 	 */
5111 	if (f->fr_pdnext != NULL) {
5112 		*f->fr_pdnext = f->fr_dnext;
5113 		if (f->fr_dnext != NULL)
5114 			f->fr_dnext->fr_pdnext = f->fr_pdnext;
5115 		f->fr_pdnext = NULL;
5116 		f->fr_dnext = NULL;
5117 	}
5118 
5119 	ipf_fixskip(f->fr_pnext, f, -1);
5120 	if (f->fr_pnext != NULL)
5121 		*f->fr_pnext = f->fr_next;
5122 	if (f->fr_next != NULL)
5123 		f->fr_next->fr_pnext = f->fr_pnext;
5124 	f->fr_pnext = NULL;
5125 	f->fr_next = NULL;
5126 
5127 	(void) ipf_derefrule(softc, &f);
5128 }
5129 
5130 /* ------------------------------------------------------------------------ */
5131 /* Function:   ipf_rule_expire_insert                                       */
5132 /* Returns:    Nil                                                          */
5133 /* Parameters: softc(I) - pointer to soft context main structure            */
5134 /*             f(I)     - pointer to rule to be added to expire list        */
5135 /*             set(I)   - 1 or 0 (filter set)                               */
5136 /*                                                                          */
5137 /* If the new rule has a given expiration time, insert it into the list of  */
5138 /* expiring rules with the ones to be removed first added to the front of   */
5139 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */
5140 /* expiration interval checks.                                              */
5141 /* ------------------------------------------------------------------------ */
5142 static void
ipf_rule_expire_insert(ipf_main_softc_t * softc,frentry_t * f,int set)5143 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set)
5144 {
5145 	frentry_t *fr;
5146 
5147 	/*
5148 	 */
5149 
5150 	f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die);
5151 	for (fr = softc->ipf_rule_explist[set]; fr != NULL;
5152 	     fr = fr->fr_dnext) {
5153 		if (f->fr_die < fr->fr_die)
5154 			break;
5155 		if (fr->fr_dnext == NULL) {
5156 			/*
5157 			 * We've got to the last rule and everything
5158 			 * wanted to be expired before this new node,
5159 			 * so we have to tack it on the end...
5160 			 */
5161 			fr->fr_dnext = f;
5162 			f->fr_pdnext = &fr->fr_dnext;
5163 			fr = NULL;
5164 			break;
5165 		}
5166 	}
5167 
5168 	if (softc->ipf_rule_explist[set] == NULL) {
5169 		softc->ipf_rule_explist[set] = f;
5170 		f->fr_pdnext = &softc->ipf_rule_explist[set];
5171 	} else if (fr != NULL) {
5172 		f->fr_dnext = fr;
5173 		f->fr_pdnext = fr->fr_pdnext;
5174 		fr->fr_pdnext = &f->fr_dnext;
5175 	}
5176 }
5177 
5178 
5179 /* ------------------------------------------------------------------------ */
5180 /* Function:   ipf_findlookup                                               */
5181 /* Returns:    NULL = failure, else success                                 */
5182 /* Parameters: softc(I) - pointer to soft context main structure            */
5183 /*             unit(I)  - ipf device we want to find match for              */
5184 /*             fp(I)    - rule for which lookup is for                      */
5185 /*             addrp(I) - pointer to lookup information in address struct   */
5186 /*             maskp(O) - pointer to lookup information for storage         */
5187 /*                                                                          */
5188 /* When using pools and hash tables to store addresses for matching in      */
5189 /* rules, it is necessary to resolve both the object referred to by the     */
5190 /* name or address (and return that pointer) and also provide the means by  */
5191 /* which to determine if an address belongs to that object to make the      */
5192 /* packet matching quicker.                                                 */
5193 /* ------------------------------------------------------------------------ */
5194 static void *
ipf_findlookup(ipf_main_softc_t * softc,int unit,frentry_t * fr,i6addr_t * addrp,i6addr_t * maskp)5195 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr,
5196 	i6addr_t *addrp, i6addr_t *maskp)
5197 {
5198 	void *ptr = NULL;
5199 
5200 	switch (addrp->iplookupsubtype)
5201 	{
5202 	case 0 :
5203 		ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype,
5204 					 addrp->iplookupnum,
5205 					 &maskp->iplookupfunc);
5206 		break;
5207 	case 1 :
5208 		if (addrp->iplookupname < 0)
5209 			break;
5210 		if (addrp->iplookupname >= fr->fr_namelen)
5211 			break;
5212 		ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype,
5213 					  fr->fr_names + addrp->iplookupname,
5214 					  &maskp->iplookupfunc);
5215 		break;
5216 	default :
5217 		break;
5218 	}
5219 
5220 	return (ptr);
5221 }
5222 
5223 
5224 /* ------------------------------------------------------------------------ */
5225 /* Function:    ipf_funcinit                                                */
5226 /* Returns:     int - 0 == success, else ESRCH: cannot resolve rule details */
5227 /* Parameters:  softc(I) - pointer to soft context main structure           */
5228 /*              fr(I)    - pointer to filter rule                           */
5229 /*                                                                          */
5230 /* If a rule is a call rule, then check if the function it points to needs  */
5231 /* an init function to be called now the rule has been loaded.              */
5232 /* ------------------------------------------------------------------------ */
5233 static int
ipf_funcinit(ipf_main_softc_t * softc,frentry_t * fr)5234 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr)
5235 {
5236 	ipfunc_resolve_t *ft;
5237 	int err;
5238 
5239 	IPFERROR(34);
5240 	err = ESRCH;
5241 
5242 	for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5243 		if (ft->ipfu_addr == fr->fr_func) {
5244 			err = 0;
5245 			if (ft->ipfu_init != NULL)
5246 				err = (*ft->ipfu_init)(softc, fr);
5247 			break;
5248 		}
5249 	return (err);
5250 }
5251 
5252 
5253 /* ------------------------------------------------------------------------ */
5254 /* Function:    ipf_funcfini                                                */
5255 /* Returns:     Nil                                                         */
5256 /* Parameters:  softc(I) - pointer to soft context main structure           */
5257 /*              fr(I)    - pointer to filter rule                           */
5258 /*                                                                          */
5259 /* For a given filter rule, call the matching "fini" function if the rule   */
5260 /* is using a known function that would have resulted in the "init" being   */
5261 /* called for ealier.                                                       */
5262 /* ------------------------------------------------------------------------ */
5263 static void
ipf_funcfini(ipf_main_softc_t * softc,frentry_t * fr)5264 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr)
5265 {
5266 	ipfunc_resolve_t *ft;
5267 
5268 	for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5269 		if (ft->ipfu_addr == fr->fr_func) {
5270 			if (ft->ipfu_fini != NULL)
5271 				(void) (*ft->ipfu_fini)(softc, fr);
5272 			break;
5273 		}
5274 }
5275 
5276 
5277 /* ------------------------------------------------------------------------ */
5278 /* Function:    ipf_findfunc                                                */
5279 /* Returns:     ipfunc_t - pointer to function if found, else NULL          */
5280 /* Parameters:  funcptr(I) - function pointer to lookup                     */
5281 /*                                                                          */
5282 /* Look for a function in the table of known functions.                     */
5283 /* ------------------------------------------------------------------------ */
5284 static ipfunc_t
ipf_findfunc(ipfunc_t funcptr)5285 ipf_findfunc(ipfunc_t funcptr)
5286 {
5287 	ipfunc_resolve_t *ft;
5288 
5289 	for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5290 		if (ft->ipfu_addr == funcptr)
5291 			return (funcptr);
5292 	return (NULL);
5293 }
5294 
5295 
5296 /* ------------------------------------------------------------------------ */
5297 /* Function:    ipf_resolvefunc                                             */
5298 /* Returns:     int - 0 == success, else error                              */
5299 /* Parameters:  data(IO) - ioctl data pointer to ipfunc_resolve_t struct    */
5300 /*                                                                          */
5301 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */
5302 /* This will either be the function name (if the pointer is set) or the     */
5303 /* function pointer if the name is set.  When found, fill in the other one  */
5304 /* so that the entire, complete, structure can be copied back to user space.*/
5305 /* ------------------------------------------------------------------------ */
5306 int
ipf_resolvefunc(ipf_main_softc_t * softc,void * data)5307 ipf_resolvefunc(ipf_main_softc_t *softc, void *data)
5308 {
5309 	ipfunc_resolve_t res, *ft;
5310 	int error;
5311 
5312 	error = BCOPYIN(data, &res, sizeof(res));
5313 	if (error != 0) {
5314 		IPFERROR(123);
5315 		return (EFAULT);
5316 	}
5317 
5318 	if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
5319 		for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5320 			if (strncmp(res.ipfu_name, ft->ipfu_name,
5321 				    sizeof(res.ipfu_name)) == 0) {
5322 				res.ipfu_addr = ft->ipfu_addr;
5323 				res.ipfu_init = ft->ipfu_init;
5324 				if (COPYOUT(&res, data, sizeof(res)) != 0) {
5325 					IPFERROR(35);
5326 					return (EFAULT);
5327 				}
5328 				return (0);
5329 			}
5330 	}
5331 	if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
5332 		for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5333 			if (ft->ipfu_addr == res.ipfu_addr) {
5334 				(void) strncpy(res.ipfu_name, ft->ipfu_name,
5335 					       sizeof(res.ipfu_name));
5336 				res.ipfu_init = ft->ipfu_init;
5337 				if (COPYOUT(&res, data, sizeof(res)) != 0) {
5338 					IPFERROR(36);
5339 					return (EFAULT);
5340 				}
5341 				return (0);
5342 			}
5343 	}
5344 	IPFERROR(37);
5345 	return (ESRCH);
5346 }
5347 
5348 
5349 #if !defined(_KERNEL) || SOLARIS
5350 /*
5351  * From: NetBSD
5352  * ppsratecheck(): packets (or events) per second limitation.
5353  */
5354 int
ppsratecheck(struct timeval * lasttime,int * curpps,int maxpps)5355 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
5356 	/* maxpps: maximum pps allowed */
5357 {
5358 	struct timeval tv, delta;
5359 	int rv;
5360 
5361 	GETKTIME(&tv);
5362 
5363 	delta.tv_sec = tv.tv_sec - lasttime->tv_sec;
5364 	delta.tv_usec = tv.tv_usec - lasttime->tv_usec;
5365 	if (delta.tv_usec < 0) {
5366 		delta.tv_sec--;
5367 		delta.tv_usec += 1000000;
5368 	}
5369 
5370 	/*
5371 	 * check for 0,0 is so that the message will be seen at least once.
5372 	 * if more than one second have passed since the last update of
5373 	 * lasttime, reset the counter.
5374 	 *
5375 	 * we do increment *curpps even in *curpps < maxpps case, as some may
5376 	 * try to use *curpps for stat purposes as well.
5377 	 */
5378 	if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
5379 	    delta.tv_sec >= 1) {
5380 		*lasttime = tv;
5381 		*curpps = 0;
5382 		rv = 1;
5383 	} else if (maxpps < 0)
5384 		rv = 1;
5385 	else if (*curpps < maxpps)
5386 		rv = 1;
5387 	else
5388 		rv = 0;
5389 	*curpps = *curpps + 1;
5390 
5391 	return (rv);
5392 }
5393 #endif
5394 
5395 
5396 /* ------------------------------------------------------------------------ */
5397 /* Function:    ipf_derefrule                                               */
5398 /* Returns:     int   - 0 == rule freed up, else rule not freed             */
5399 /* Parameters:  fr(I) - pointer to filter rule                              */
5400 /*                                                                          */
5401 /* Decrement the reference counter to a rule by one.  If it reaches zero,   */
5402 /* free it and any associated storage space being used by it.               */
5403 /* ------------------------------------------------------------------------ */
5404 int
ipf_derefrule(ipf_main_softc_t * softc,frentry_t ** frp)5405 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp)
5406 {
5407 	frentry_t *fr;
5408 	frdest_t *fdp;
5409 
5410 	fr = *frp;
5411 	*frp = NULL;
5412 
5413 	MUTEX_ENTER(&fr->fr_lock);
5414 	fr->fr_ref--;
5415 	if (fr->fr_ref == 0) {
5416 		MUTEX_EXIT(&fr->fr_lock);
5417 		MUTEX_DESTROY(&fr->fr_lock);
5418 
5419 		ipf_funcfini(softc, fr);
5420 
5421 		fdp = &fr->fr_tif;
5422 		if (fdp->fd_type == FRD_DSTLIST)
5423 			ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5424 
5425 		fdp = &fr->fr_rif;
5426 		if (fdp->fd_type == FRD_DSTLIST)
5427 			ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5428 
5429 		fdp = &fr->fr_dif;
5430 		if (fdp->fd_type == FRD_DSTLIST)
5431 			ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5432 
5433 		if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
5434 		    fr->fr_satype == FRI_LOOKUP)
5435 			ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr);
5436 		if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
5437 		    fr->fr_datype == FRI_LOOKUP)
5438 			ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr);
5439 
5440 		if (fr->fr_grp != NULL)
5441 			ipf_group_del(softc, fr->fr_grp, fr);
5442 
5443 		if (fr->fr_grphead != NULL)
5444 			ipf_group_del(softc, fr->fr_grphead, fr);
5445 
5446 		if (fr->fr_icmpgrp != NULL)
5447 			ipf_group_del(softc, fr->fr_icmpgrp, fr);
5448 
5449 		if ((fr->fr_flags & FR_COPIED) != 0) {
5450 			if (fr->fr_dsize) {
5451 				KFREES(fr->fr_data, fr->fr_dsize);
5452 			}
5453 			KFREES(fr, fr->fr_size);
5454 			return (0);
5455 		}
5456 		return (1);
5457 	} else {
5458 		MUTEX_EXIT(&fr->fr_lock);
5459 	}
5460 	return (-1);
5461 }
5462 
5463 
5464 /* ------------------------------------------------------------------------ */
5465 /* Function:    ipf_grpmapinit                                              */
5466 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
5467 /* Parameters:  fr(I) - pointer to rule to find hash table for              */
5468 /*                                                                          */
5469 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr.  */
5470 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap.                 */
5471 /* ------------------------------------------------------------------------ */
5472 static int
ipf_grpmapinit(ipf_main_softc_t * softc,frentry_t * fr)5473 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr)
5474 {
5475 	char name[FR_GROUPLEN];
5476 	iphtable_t *iph;
5477 
5478 	(void) snprintf(name, sizeof(name), "%d", fr->fr_arg);
5479 	iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name);
5480 	if (iph == NULL) {
5481 		IPFERROR(38);
5482 		return (ESRCH);
5483 	}
5484 	if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) {
5485 		IPFERROR(39);
5486 		return (ESRCH);
5487 	}
5488 	iph->iph_ref++;
5489 	fr->fr_ptr = iph;
5490 	return (0);
5491 }
5492 
5493 
5494 /* ------------------------------------------------------------------------ */
5495 /* Function:    ipf_grpmapfini                                              */
5496 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
5497 /* Parameters:  softc(I) - pointer to soft context main structure           */
5498 /*              fr(I)    - pointer to rule to release hash table for        */
5499 /*                                                                          */
5500 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */
5501 /* be called to undo what ipf_grpmapinit caused to be done.                 */
5502 /* ------------------------------------------------------------------------ */
5503 static int
ipf_grpmapfini(ipf_main_softc_t * softc,frentry_t * fr)5504 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr)
5505 {
5506 	iphtable_t *iph;
5507 	iph = fr->fr_ptr;
5508 	if (iph != NULL)
5509 		ipf_lookup_deref(softc, IPLT_HASH, iph);
5510 	return (0);
5511 }
5512 
5513 
5514 /* ------------------------------------------------------------------------ */
5515 /* Function:    ipf_srcgrpmap                                               */
5516 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
5517 /* Parameters:  fin(I)    - pointer to packet information                   */
5518 /*              passp(IO) - pointer to current/new filter decision (unused) */
5519 /*                                                                          */
5520 /* Look for a rule group head in a hash table, using the source address as  */
5521 /* the key, and descend into that group and continue matching rules against */
5522 /* the packet.                                                              */
5523 /* ------------------------------------------------------------------------ */
5524 frentry_t *
ipf_srcgrpmap(fr_info_t * fin,u_32_t * passp)5525 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp)
5526 {
5527 	frgroup_t *fg;
5528 	void *rval;
5529 
5530 	rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
5531 				 &fin->fin_src);
5532 	if (rval == NULL)
5533 		return (NULL);
5534 
5535 	fg = rval;
5536 	fin->fin_fr = fg->fg_start;
5537 	(void) ipf_scanlist(fin, *passp);
5538 	return (fin->fin_fr);
5539 }
5540 
5541 
5542 /* ------------------------------------------------------------------------ */
5543 /* Function:    ipf_dstgrpmap                                               */
5544 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
5545 /* Parameters:  fin(I)    - pointer to packet information                   */
5546 /*              passp(IO) - pointer to current/new filter decision (unused) */
5547 /*                                                                          */
5548 /* Look for a rule group head in a hash table, using the destination        */
5549 /* address as the key, and descend into that group and continue matching    */
5550 /* rules against  the packet.                                               */
5551 /* ------------------------------------------------------------------------ */
5552 frentry_t *
ipf_dstgrpmap(fr_info_t * fin,u_32_t * passp)5553 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp)
5554 {
5555 	frgroup_t *fg;
5556 	void *rval;
5557 
5558 	rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
5559 				 &fin->fin_dst);
5560 	if (rval == NULL)
5561 		return (NULL);
5562 
5563 	fg = rval;
5564 	fin->fin_fr = fg->fg_start;
5565 	(void) ipf_scanlist(fin, *passp);
5566 	return (fin->fin_fr);
5567 }
5568 
5569 /*
5570  * Queue functions
5571  * ===============
5572  * These functions manage objects on queues for efficient timeouts.  There
5573  * are a number of system defined queues as well as user defined timeouts.
5574  * It is expected that a lock is held in the domain in which the queue
5575  * belongs (i.e. either state or NAT) when calling any of these functions
5576  * that prevents ipf_freetimeoutqueue() from being called at the same time
5577  * as any other.
5578  */
5579 
5580 
5581 /* ------------------------------------------------------------------------ */
5582 /* Function:    ipf_addtimeoutqueue                                         */
5583 /* Returns:     struct ifqtq * - NULL if malloc fails, else pointer to      */
5584 /*                               timeout queue with given interval.         */
5585 /* Parameters:  parent(I)  - pointer to pointer to parent node of this list */
5586 /*                           of interface queues.                           */
5587 /*              seconds(I) - timeout value in seconds for this queue.       */
5588 /*                                                                          */
5589 /* This routine first looks for a timeout queue that matches the interval   */
5590 /* being requested.  If it finds one, increments the reference counter and  */
5591 /* returns a pointer to it.  If none are found, it allocates a new one and  */
5592 /* inserts it at the top of the list.                                       */
5593 /*                                                                          */
5594 /* Locking.                                                                 */
5595 /* It is assumed that the caller of this function has an appropriate lock   */
5596 /* held (exclusively) in the domain that encompases 'parent'.               */
5597 /* ------------------------------------------------------------------------ */
5598 ipftq_t *
ipf_addtimeoutqueue(ipf_main_softc_t * softc,ipftq_t ** parent,u_int seconds)5599 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds)
5600 {
5601 	ipftq_t *ifq;
5602 	u_int period;
5603 
5604 	period = seconds * IPF_HZ_DIVIDE;
5605 
5606 	MUTEX_ENTER(&softc->ipf_timeoutlock);
5607 	for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
5608 		if (ifq->ifq_ttl == period) {
5609 			/*
5610 			 * Reset the delete flag, if set, so the structure
5611 			 * gets reused rather than freed and reallocated.
5612 			 */
5613 			MUTEX_ENTER(&ifq->ifq_lock);
5614 			ifq->ifq_flags &= ~IFQF_DELETE;
5615 			ifq->ifq_ref++;
5616 			MUTEX_EXIT(&ifq->ifq_lock);
5617 			MUTEX_EXIT(&softc->ipf_timeoutlock);
5618 
5619 			return (ifq);
5620 		}
5621 	}
5622 
5623 	KMALLOC(ifq, ipftq_t *);
5624 	if (ifq != NULL) {
5625 		MUTEX_NUKE(&ifq->ifq_lock);
5626 		IPFTQ_INIT(ifq, period, "ipftq mutex");
5627 		ifq->ifq_next = *parent;
5628 		ifq->ifq_pnext = parent;
5629 		ifq->ifq_flags = IFQF_USER;
5630 		ifq->ifq_ref++;
5631 		*parent = ifq;
5632 		softc->ipf_userifqs++;
5633 	}
5634 	MUTEX_EXIT(&softc->ipf_timeoutlock);
5635 	return (ifq);
5636 }
5637 
5638 
5639 /* ------------------------------------------------------------------------ */
5640 /* Function:    ipf_deletetimeoutqueue                                      */
5641 /* Returns:     int    - new reference count value of the timeout queue     */
5642 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
5643 /* Locks:       ifq->ifq_lock                                               */
5644 /*                                                                          */
5645 /* This routine must be called when we're discarding a pointer to a timeout */
5646 /* queue object, taking care of the reference counter.                      */
5647 /*                                                                          */
5648 /* Now that this just sets a DELETE flag, it requires the expire code to    */
5649 /* check the list of user defined timeout queues and call the free function */
5650 /* below (currently commented out) to stop memory leaking.  It is done this */
5651 /* way because the locking may not be sufficient to safely do a free when   */
5652 /* this function is called.                                                 */
5653 /* ------------------------------------------------------------------------ */
5654 int
ipf_deletetimeoutqueue(ipftq_t * ifq)5655 ipf_deletetimeoutqueue(ipftq_t *ifq)
5656 {
5657 
5658 	ifq->ifq_ref--;
5659 	if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) {
5660 		ifq->ifq_flags |= IFQF_DELETE;
5661 	}
5662 
5663 	return (ifq->ifq_ref);
5664 }
5665 
5666 
5667 /* ------------------------------------------------------------------------ */
5668 /* Function:    ipf_freetimeoutqueue                                        */
5669 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
5670 /* Returns:     Nil                                                         */
5671 /*                                                                          */
5672 /* Locking:                                                                 */
5673 /* It is assumed that the caller of this function has an appropriate lock   */
5674 /* held (exclusively) in the domain that encompases the callers "domain".   */
5675 /* The ifq_lock for this structure should not be held.                      */
5676 /*                                                                          */
5677 /* Remove a user defined timeout queue from the list of queues it is in and */
5678 /* tidy up after this is done.                                              */
5679 /* ------------------------------------------------------------------------ */
5680 void
ipf_freetimeoutqueue(ipf_main_softc_t * softc,ipftq_t * ifq)5681 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq)
5682 {
5683 
5684 	if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
5685 	    ((ifq->ifq_flags & IFQF_USER) == 0)) {
5686 		printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
5687 		       (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
5688 		       ifq->ifq_ref);
5689 		return;
5690 	}
5691 
5692 	/*
5693 	 * Remove from its position in the list.
5694 	 */
5695 	*ifq->ifq_pnext = ifq->ifq_next;
5696 	if (ifq->ifq_next != NULL)
5697 		ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
5698 	ifq->ifq_next = NULL;
5699 	ifq->ifq_pnext = NULL;
5700 
5701 	MUTEX_DESTROY(&ifq->ifq_lock);
5702 	ATOMIC_DEC(softc->ipf_userifqs);
5703 	KFREE(ifq);
5704 }
5705 
5706 
5707 /* ------------------------------------------------------------------------ */
5708 /* Function:    ipf_deletequeueentry                                        */
5709 /* Returns:     Nil                                                         */
5710 /* Parameters:  tqe(I) - timeout queue entry to delete                      */
5711 /*                                                                          */
5712 /* Remove a tail queue entry from its queue and make it an orphan.          */
5713 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */
5714 /* queue is correct.  We can't, however, call ipf_freetimeoutqueue because  */
5715 /* the correct lock(s) may not be held that would make it safe to do so.    */
5716 /* ------------------------------------------------------------------------ */
5717 void
ipf_deletequeueentry(ipftqent_t * tqe)5718 ipf_deletequeueentry(ipftqent_t *tqe)
5719 {
5720 	ipftq_t *ifq;
5721 
5722 	ifq = tqe->tqe_ifq;
5723 
5724 	MUTEX_ENTER(&ifq->ifq_lock);
5725 
5726 	if (tqe->tqe_pnext != NULL) {
5727 		*tqe->tqe_pnext = tqe->tqe_next;
5728 		if (tqe->tqe_next != NULL)
5729 			tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5730 		else    /* we must be the tail anyway */
5731 			ifq->ifq_tail = tqe->tqe_pnext;
5732 
5733 		tqe->tqe_pnext = NULL;
5734 		tqe->tqe_ifq = NULL;
5735 	}
5736 
5737 	(void) ipf_deletetimeoutqueue(ifq);
5738 	ASSERT(ifq->ifq_ref > 0);
5739 
5740 	MUTEX_EXIT(&ifq->ifq_lock);
5741 }
5742 
5743 
5744 /* ------------------------------------------------------------------------ */
5745 /* Function:    ipf_queuefront                                              */
5746 /* Returns:     Nil                                                         */
5747 /* Parameters:  tqe(I) - pointer to timeout queue entry                     */
5748 /*                                                                          */
5749 /* Move a queue entry to the front of the queue, if it isn't already there. */
5750 /* ------------------------------------------------------------------------ */
5751 void
ipf_queuefront(ipftqent_t * tqe)5752 ipf_queuefront(ipftqent_t *tqe)
5753 {
5754 	ipftq_t *ifq;
5755 
5756 	ifq = tqe->tqe_ifq;
5757 	if (ifq == NULL)
5758 		return;
5759 
5760 	MUTEX_ENTER(&ifq->ifq_lock);
5761 	if (ifq->ifq_head != tqe) {
5762 		*tqe->tqe_pnext = tqe->tqe_next;
5763 		if (tqe->tqe_next)
5764 			tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5765 		else
5766 			ifq->ifq_tail = tqe->tqe_pnext;
5767 
5768 		tqe->tqe_next = ifq->ifq_head;
5769 		ifq->ifq_head->tqe_pnext = &tqe->tqe_next;
5770 		ifq->ifq_head = tqe;
5771 		tqe->tqe_pnext = &ifq->ifq_head;
5772 	}
5773 	MUTEX_EXIT(&ifq->ifq_lock);
5774 }
5775 
5776 
5777 /* ------------------------------------------------------------------------ */
5778 /* Function:    ipf_queueback                                               */
5779 /* Returns:     Nil                                                         */
5780 /* Parameters:  ticks(I) - ipf tick time to use with this call              */
5781 /*              tqe(I)   - pointer to timeout queue entry                   */
5782 /*                                                                          */
5783 /* Move a queue entry to the back of the queue, if it isn't already there.  */
5784 /* We use use ticks to calculate the expiration and mark for when we last   */
5785 /* touched the structure.                                                   */
5786 /* ------------------------------------------------------------------------ */
5787 void
ipf_queueback(u_long ticks,ipftqent_t * tqe)5788 ipf_queueback(u_long ticks, ipftqent_t *tqe)
5789 {
5790 	ipftq_t *ifq;
5791 
5792 	ifq = tqe->tqe_ifq;
5793 	if (ifq == NULL)
5794 		return;
5795 	tqe->tqe_die = ticks + ifq->ifq_ttl;
5796 	tqe->tqe_touched = ticks;
5797 
5798 	MUTEX_ENTER(&ifq->ifq_lock);
5799 	if (tqe->tqe_next != NULL) {		/* at the end already ? */
5800 		/*
5801 		 * Remove from list
5802 		 */
5803 		*tqe->tqe_pnext = tqe->tqe_next;
5804 		tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5805 
5806 		/*
5807 		 * Make it the last entry.
5808 		 */
5809 		tqe->tqe_next = NULL;
5810 		tqe->tqe_pnext = ifq->ifq_tail;
5811 		*ifq->ifq_tail = tqe;
5812 		ifq->ifq_tail = &tqe->tqe_next;
5813 	}
5814 	MUTEX_EXIT(&ifq->ifq_lock);
5815 }
5816 
5817 
5818 /* ------------------------------------------------------------------------ */
5819 /* Function:    ipf_queueappend                                             */
5820 /* Returns:     Nil                                                         */
5821 /* Parameters:  ticks(I)  - ipf tick time to use with this call             */
5822 /*              tqe(I)    - pointer to timeout queue entry                  */
5823 /*              ifq(I)    - pointer to timeout queue                        */
5824 /*              parent(I) - owing object pointer                            */
5825 /*                                                                          */
5826 /* Add a new item to this queue and put it on the very end.                 */
5827 /* We use use ticks to calculate the expiration and mark for when we last   */
5828 /* touched the structure.                                                   */
5829 /* ------------------------------------------------------------------------ */
5830 void
ipf_queueappend(u_long ticks,ipftqent_t * tqe,ipftq_t * ifq,void * parent)5831 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent)
5832 {
5833 
5834 	MUTEX_ENTER(&ifq->ifq_lock);
5835 	tqe->tqe_parent = parent;
5836 	tqe->tqe_pnext = ifq->ifq_tail;
5837 	*ifq->ifq_tail = tqe;
5838 	ifq->ifq_tail = &tqe->tqe_next;
5839 	tqe->tqe_next = NULL;
5840 	tqe->tqe_ifq = ifq;
5841 	tqe->tqe_die = ticks + ifq->ifq_ttl;
5842 	tqe->tqe_touched = ticks;
5843 	ifq->ifq_ref++;
5844 	MUTEX_EXIT(&ifq->ifq_lock);
5845 }
5846 
5847 
5848 /* ------------------------------------------------------------------------ */
5849 /* Function:    ipf_movequeue                                               */
5850 /* Returns:     Nil                                                         */
5851 /* Parameters:  tq(I)   - pointer to timeout queue information              */
5852 /*              oifp(I) - old timeout queue entry was on                    */
5853 /*              nifp(I) - new timeout queue to put entry on                 */
5854 /*                                                                          */
5855 /* Move a queue entry from one timeout queue to another timeout queue.      */
5856 /* If it notices that the current entry is already last and does not need   */
5857 /* to move queue, the return.                                               */
5858 /* ------------------------------------------------------------------------ */
5859 void
ipf_movequeue(u_long ticks,ipftqent_t * tqe,ipftq_t * oifq,ipftq_t * nifq)5860 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq)
5861 {
5862 
5863 	/*
5864 	 * If the queue hasn't changed and we last touched this entry at the
5865 	 * same ipf time, then we're not going to achieve anything by either
5866 	 * changing the ttl or moving it on the queue.
5867 	 */
5868 	if (oifq == nifq && tqe->tqe_touched == ticks)
5869 		return;
5870 
5871 	/*
5872 	 * For any of this to be outside the lock, there is a risk that two
5873 	 * packets entering simultaneously, with one changing to a different
5874 	 * queue and one not, could end up with things in a bizarre state.
5875 	 */
5876 	MUTEX_ENTER(&oifq->ifq_lock);
5877 
5878 	tqe->tqe_touched = ticks;
5879 	tqe->tqe_die = ticks + nifq->ifq_ttl;
5880 	/*
5881 	 * Is the operation here going to be a no-op ?
5882 	 */
5883 	if (oifq == nifq) {
5884 		if ((tqe->tqe_next == NULL) ||
5885 		    (tqe->tqe_next->tqe_die == tqe->tqe_die)) {
5886 			MUTEX_EXIT(&oifq->ifq_lock);
5887 			return;
5888 		}
5889 	}
5890 
5891 	/*
5892 	 * Remove from the old queue
5893 	 */
5894 	*tqe->tqe_pnext = tqe->tqe_next;
5895 	if (tqe->tqe_next)
5896 		tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5897 	else
5898 		oifq->ifq_tail = tqe->tqe_pnext;
5899 	tqe->tqe_next = NULL;
5900 
5901 	/*
5902 	 * If we're moving from one queue to another, release the
5903 	 * lock on the old queue and get a lock on the new queue.
5904 	 * For user defined queues, if we're moving off it, call
5905 	 * delete in case it can now be freed.
5906 	 */
5907 	if (oifq != nifq) {
5908 		tqe->tqe_ifq = NULL;
5909 
5910 		(void) ipf_deletetimeoutqueue(oifq);
5911 
5912 		MUTEX_EXIT(&oifq->ifq_lock);
5913 
5914 		MUTEX_ENTER(&nifq->ifq_lock);
5915 
5916 		tqe->tqe_ifq = nifq;
5917 		nifq->ifq_ref++;
5918 	}
5919 
5920 	/*
5921 	 * Add to the bottom of the new queue
5922 	 */
5923 	tqe->tqe_pnext = nifq->ifq_tail;
5924 	*nifq->ifq_tail = tqe;
5925 	nifq->ifq_tail = &tqe->tqe_next;
5926 	MUTEX_EXIT(&nifq->ifq_lock);
5927 }
5928 
5929 
5930 /* ------------------------------------------------------------------------ */
5931 /* Function:    ipf_updateipid                                              */
5932 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
5933 /* Parameters:  fin(I) - pointer to packet information                      */
5934 /*                                                                          */
5935 /* When we are doing NAT, change the IP of every packet to represent a      */
5936 /* single sequence of packets coming from the host, hiding any host         */
5937 /* specific sequencing that might otherwise be revealed.  If the packet is  */
5938 /* a fragment, then store the 'new' IPid in the fragment cache and look up  */
5939 /* the fragment cache for non-leading fragments.  If a non-leading fragment */
5940 /* has no match in the cache, return an error.                              */
5941 /* ------------------------------------------------------------------------ */
5942 static int
ipf_updateipid(fr_info_t * fin)5943 ipf_updateipid(fr_info_t *fin)
5944 {
5945 	u_short id, ido, sums;
5946 	u_32_t sumd, sum;
5947 	ip_t *ip;
5948 
5949 	ip = fin->fin_ip;
5950 	ido = ntohs(ip->ip_id);
5951 	if (fin->fin_off != 0) {
5952 		sum = ipf_frag_ipidknown(fin);
5953 		if (sum == 0xffffffff)
5954 			return (-1);
5955 		sum &= 0xffff;
5956 		id = (u_short)sum;
5957 		ip->ip_id = htons(id);
5958 	} else {
5959 		ip_fillid(ip);
5960 		id = ntohs(ip->ip_id);
5961 		if ((fin->fin_flx & FI_FRAG) != 0)
5962 			(void) ipf_frag_ipidnew(fin, (u_32_t)id);
5963 	}
5964 
5965 	if (id == ido)
5966 		return (0);
5967 	CALC_SUMD(ido, id, sumd);	/* DESTRUCTIVE MACRO! id,ido change */
5968 	sum = (~ntohs(ip->ip_sum)) & 0xffff;
5969 	sum += sumd;
5970 	sum = (sum >> 16) + (sum & 0xffff);
5971 	sum = (sum >> 16) + (sum & 0xffff);
5972 	sums = ~(u_short)sum;
5973 	ip->ip_sum = htons(sums);
5974 	return (0);
5975 }
5976 
5977 
5978 #ifdef	NEED_FRGETIFNAME
5979 /* ------------------------------------------------------------------------ */
5980 /* Function:    ipf_getifname                                               */
5981 /* Returns:     char *    - pointer to interface name                       */
5982 /* Parameters:  ifp(I)    - pointer to network interface                    */
5983 /*              buffer(O) - pointer to where to store interface name        */
5984 /*                                                                          */
5985 /* Constructs an interface name in the buffer passed.  The buffer passed is */
5986 /* expected to be at least LIFNAMSIZ in bytes big.  If buffer is passed in  */
5987 /* as a NULL pointer then return a pointer to a static array.               */
5988 /* ------------------------------------------------------------------------ */
5989 char *
ipf_getifname(struct ifnet * ifp,char * buffer)5990 ipf_getifname(struct ifnet *ifp, char *buffer)
5991 {
5992 	static char namebuf[LIFNAMSIZ];
5993 # if SOLARIS || defined(__FreeBSD__)
5994 	int unit, space;
5995 	char temp[20];
5996 	char *s;
5997 # endif
5998 
5999 	if (buffer == NULL)
6000 		buffer = namebuf;
6001 	(void) strncpy(buffer, ifp->if_name, LIFNAMSIZ);
6002 	buffer[LIFNAMSIZ - 1] = '\0';
6003 # if SOLARIS || defined(__FreeBSD__)
6004 	for (s = buffer; *s; s++)
6005 		;
6006 	unit = ifp->if_unit;
6007 	space = LIFNAMSIZ - (s - buffer);
6008 	if ((space > 0) && (unit >= 0)) {
6009 		(void) snprintf(temp, sizeof(name), "%d", unit);
6010 		(void) strncpy(s, temp, space);
6011 	}
6012 # endif
6013 	return (buffer);
6014 }
6015 #endif
6016 
6017 
6018 /* ------------------------------------------------------------------------ */
6019 /* Function:    ipf_ioctlswitch                                             */
6020 /* Returns:     int     - -1 continue processing, else ioctl return value   */
6021 /* Parameters:  unit(I) - device unit opened                                */
6022 /*              data(I) - pointer to ioctl data                             */
6023 /*              cmd(I)  - ioctl command                                     */
6024 /*              mode(I) - mode value                                        */
6025 /*              uid(I)  - uid making the ioctl call                         */
6026 /*              ctx(I)  - pointer to context data                           */
6027 /*                                                                          */
6028 /* Based on the value of unit, call the appropriate ioctl handler or return */
6029 /* EIO if ipfilter is not running.   Also checks if write perms are req'd   */
6030 /* for the device in order to execute the ioctl.  A special case is made    */
6031 /* SIOCIPFINTERROR so that the same code isn't required in every handler.   */
6032 /* The context data pointer is passed through as this is used as the key    */
6033 /* for locating a matching token for continued access for walking lists,    */
6034 /* etc.                                                                     */
6035 /* ------------------------------------------------------------------------ */
6036 int
ipf_ioctlswitch(ipf_main_softc_t * softc,int unit,void * data,ioctlcmd_t cmd,int mode,int uid,void * ctx)6037 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd,
6038 	int mode, int uid, void *ctx)
6039 {
6040 	int error = 0;
6041 
6042 	switch (cmd)
6043 	{
6044 	case SIOCIPFINTERROR :
6045 		error = BCOPYOUT(&softc->ipf_interror, data,
6046 				 sizeof(softc->ipf_interror));
6047 		if (error != 0) {
6048 			IPFERROR(40);
6049 			error = EFAULT;
6050 		}
6051 		return (error);
6052 	default :
6053 		break;
6054 	}
6055 
6056 	switch (unit)
6057 	{
6058 	case IPL_LOGIPF :
6059 		error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx);
6060 		break;
6061 	case IPL_LOGNAT :
6062 		if (softc->ipf_running > 0) {
6063 			error = ipf_nat_ioctl(softc, data, cmd, mode,
6064 					      uid, ctx);
6065 		} else {
6066 			IPFERROR(42);
6067 			error = EIO;
6068 		}
6069 		break;
6070 	case IPL_LOGSTATE :
6071 		if (softc->ipf_running > 0) {
6072 			error = ipf_state_ioctl(softc, data, cmd, mode,
6073 						uid, ctx);
6074 		} else {
6075 			IPFERROR(43);
6076 			error = EIO;
6077 		}
6078 		break;
6079 	case IPL_LOGAUTH :
6080 		if (softc->ipf_running > 0) {
6081 			error = ipf_auth_ioctl(softc, data, cmd, mode,
6082 					       uid, ctx);
6083 		} else {
6084 			IPFERROR(44);
6085 			error = EIO;
6086 		}
6087 		break;
6088 	case IPL_LOGSYNC :
6089 		if (softc->ipf_running > 0) {
6090 			error = ipf_sync_ioctl(softc, data, cmd, mode,
6091 					       uid, ctx);
6092 		} else {
6093 			error = EIO;
6094 			IPFERROR(45);
6095 		}
6096 		break;
6097 	case IPL_LOGSCAN :
6098 #ifdef IPFILTER_SCAN
6099 		if (softc->ipf_running > 0)
6100 			error = ipf_scan_ioctl(softc, data, cmd, mode,
6101 					       uid, ctx);
6102 		else
6103 #endif
6104 		{
6105 			error = EIO;
6106 			IPFERROR(46);
6107 		}
6108 		break;
6109 	case IPL_LOGLOOKUP :
6110 		if (softc->ipf_running > 0) {
6111 			error = ipf_lookup_ioctl(softc, data, cmd, mode,
6112 						 uid, ctx);
6113 		} else {
6114 			error = EIO;
6115 			IPFERROR(47);
6116 		}
6117 		break;
6118 	default :
6119 		IPFERROR(48);
6120 		error = EIO;
6121 		break;
6122 	}
6123 
6124 	return (error);
6125 }
6126 
6127 
6128 /*
6129  * This array defines the expected size of objects coming into the kernel
6130  * for the various recognised object types. The first column is flags (see
6131  * below), 2nd column is current size, 3rd column is the version number of
6132  * when the current size became current.
6133  * Flags:
6134  * 1 = minimum size, not absolute size
6135  */
6136 static const int	ipf_objbytes[IPFOBJ_COUNT][3] = {
6137 	{ 1,	sizeof(struct frentry),		5010000 },	/* 0 */
6138 	{ 1,	sizeof(struct friostat),	5010000 },
6139 	{ 0,	sizeof(struct fr_info),		5010000 },
6140 	{ 0,	sizeof(struct ipf_authstat),	4010100 },
6141 	{ 0,	sizeof(struct ipfrstat),	5010000 },
6142 	{ 1,	sizeof(struct ipnat),		5010000 },	/* 5 */
6143 	{ 0,	sizeof(struct natstat),		5010000 },
6144 	{ 0,	sizeof(struct ipstate_save),	5010000 },
6145 	{ 1,	sizeof(struct nat_save),	5010000 },
6146 	{ 0,	sizeof(struct natlookup),	5010000 },
6147 	{ 1,	sizeof(struct ipstate),		5010000 },	/* 10 */
6148 	{ 0,	sizeof(struct ips_stat),	5010000 },
6149 	{ 0,	sizeof(struct frauth),		5010000 },
6150 	{ 0,	sizeof(struct ipftune),		4010100 },
6151 	{ 0,	sizeof(struct nat),		5010000 },
6152 	{ 0,	sizeof(struct ipfruleiter),	4011400 },	/* 15 */
6153 	{ 0,	sizeof(struct ipfgeniter),	4011400 },
6154 	{ 0,	sizeof(struct ipftable),	4011400 },
6155 	{ 0,	sizeof(struct ipflookupiter),	4011400 },
6156 	{ 0,	sizeof(struct ipftq) * IPF_TCP_NSTATES },
6157 	{ 1,	0,				0	}, /* IPFEXPR */
6158 	{ 0,	0,				0	}, /* PROXYCTL */
6159 	{ 0,	sizeof (struct fripf),		5010000	}
6160 };
6161 
6162 
6163 /* ------------------------------------------------------------------------ */
6164 /* Function:    ipf_inobj                                                   */
6165 /* Returns:     int     - 0 = success, else failure                         */
6166 /* Parameters:  softc(I) - soft context pointerto work with                 */
6167 /*              data(I)  - pointer to ioctl data                            */
6168 /*              objp(O)  - where to store ipfobj structure                  */
6169 /*              ptr(I)   - pointer to data to copy out                      */
6170 /*              type(I)  - type of structure being moved                    */
6171 /*                                                                          */
6172 /* Copy in the contents of what the ipfobj_t points to.  In future, we      */
6173 /* add things to check for version numbers, sizes, etc, to make it backward */
6174 /* compatible at the ABI for user land.                                     */
6175 /* If objp is not NULL then we assume that the caller wants to see what is  */
6176 /* in the ipfobj_t structure being copied in. As an example, this can tell  */
6177 /* the caller what version of ipfilter the ioctl program was written to.    */
6178 /* ------------------------------------------------------------------------ */
6179 int
ipf_inobj(ipf_main_softc_t * softc,void * data,ipfobj_t * objp,void * ptr,int type)6180 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr,
6181 	int type)
6182 {
6183 	ipfobj_t obj;
6184 	int error;
6185 	int size;
6186 
6187 	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6188 		IPFERROR(49);
6189 		return (EINVAL);
6190 	}
6191 
6192 	if (objp == NULL)
6193 		objp = &obj;
6194 	error = BCOPYIN(data, objp, sizeof(*objp));
6195 	if (error != 0) {
6196 		IPFERROR(124);
6197 		return (EFAULT);
6198 	}
6199 
6200 	if (objp->ipfo_type != type) {
6201 		IPFERROR(50);
6202 		return (EINVAL);
6203 	}
6204 
6205 	if (objp->ipfo_rev >= ipf_objbytes[type][2]) {
6206 		if ((ipf_objbytes[type][0] & 1) != 0) {
6207 			if (objp->ipfo_size < ipf_objbytes[type][1]) {
6208 				IPFERROR(51);
6209 				return (EINVAL);
6210 			}
6211 			size =  ipf_objbytes[type][1];
6212 		} else if (objp->ipfo_size == ipf_objbytes[type][1]) {
6213 			size =  objp->ipfo_size;
6214 		} else {
6215 			IPFERROR(52);
6216 			return (EINVAL);
6217 		}
6218 		error = COPYIN(objp->ipfo_ptr, ptr, size);
6219 		if (error != 0) {
6220 			IPFERROR(55);
6221 			error = EFAULT;
6222 		}
6223 	} else {
6224 #ifdef  IPFILTER_COMPAT
6225 		error = ipf_in_compat(softc, objp, ptr, 0);
6226 #else
6227 		IPFERROR(54);
6228 		error = EINVAL;
6229 #endif
6230 	}
6231 	return (error);
6232 }
6233 
6234 
6235 /* ------------------------------------------------------------------------ */
6236 /* Function:    ipf_inobjsz                                                 */
6237 /* Returns:     int     - 0 = success, else failure                         */
6238 /* Parameters:  softc(I) - soft context pointerto work with                 */
6239 /*              data(I)  - pointer to ioctl data                            */
6240 /*              ptr(I)   - pointer to store real data in                    */
6241 /*              type(I)  - type of structure being moved                    */
6242 /*              sz(I)    - size of data to copy                             */
6243 /*                                                                          */
6244 /* As per ipf_inobj, except the size of the object to copy in is passed in  */
6245 /* but it must not be smaller than the size defined for the type and the    */
6246 /* type must allow for varied sized objects.  The extra requirement here is */
6247 /* that sz must match the size of the object being passed in - this is not  */
6248 /* not possible nor required in ipf_inobj().                                */
6249 /* ------------------------------------------------------------------------ */
6250 int
ipf_inobjsz(ipf_main_softc_t * softc,void * data,void * ptr,int type,int sz)6251 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz)
6252 {
6253 	ipfobj_t obj;
6254 	int error;
6255 
6256 	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6257 		IPFERROR(56);
6258 		return (EINVAL);
6259 	}
6260 
6261 	error = BCOPYIN(data, &obj, sizeof(obj));
6262 	if (error != 0) {
6263 		IPFERROR(125);
6264 		return (EFAULT);
6265 	}
6266 
6267 	if (obj.ipfo_type != type) {
6268 		IPFERROR(58);
6269 		return (EINVAL);
6270 	}
6271 
6272 	if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6273 		if (((ipf_objbytes[type][0] & 1) == 0) ||
6274 		    (sz < ipf_objbytes[type][1])) {
6275 			IPFERROR(57);
6276 			return (EINVAL);
6277 		}
6278 		error = COPYIN(obj.ipfo_ptr, ptr, sz);
6279 		if (error != 0) {
6280 			IPFERROR(61);
6281 			error = EFAULT;
6282 		}
6283 	} else {
6284 #ifdef	IPFILTER_COMPAT
6285 		error = ipf_in_compat(softc, &obj, ptr, sz);
6286 #else
6287 		IPFERROR(60);
6288 		error = EINVAL;
6289 #endif
6290 	}
6291 	return (error);
6292 }
6293 
6294 
6295 /* ------------------------------------------------------------------------ */
6296 /* Function:    ipf_outobjsz                                                */
6297 /* Returns:     int     - 0 = success, else failure                         */
6298 /* Parameters:  data(I) - pointer to ioctl data                             */
6299 /*              ptr(I)  - pointer to store real data in                     */
6300 /*              type(I) - type of structure being moved                     */
6301 /*              sz(I)   - size of data to copy                              */
6302 /*                                                                          */
6303 /* As per ipf_outobj, except the size of the object to copy out is passed in*/
6304 /* but it must not be smaller than the size defined for the type and the    */
6305 /* type must allow for varied sized objects.  The extra requirement here is */
6306 /* that sz must match the size of the object being passed in - this is not  */
6307 /* not possible nor required in ipf_outobj().                               */
6308 /* ------------------------------------------------------------------------ */
6309 int
ipf_outobjsz(ipf_main_softc_t * softc,void * data,void * ptr,int type,int sz)6310 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz)
6311 {
6312 	ipfobj_t obj;
6313 	int error;
6314 
6315 	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6316 		IPFERROR(62);
6317 		return (EINVAL);
6318 	}
6319 
6320 	error = BCOPYIN(data, &obj, sizeof(obj));
6321 	if (error != 0) {
6322 		IPFERROR(127);
6323 		return (EFAULT);
6324 	}
6325 
6326 	if (obj.ipfo_type != type) {
6327 		IPFERROR(63);
6328 		return (EINVAL);
6329 	}
6330 
6331 	if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6332 		if (((ipf_objbytes[type][0] & 1) == 0) ||
6333 		    (sz < ipf_objbytes[type][1])) {
6334 			IPFERROR(146);
6335 			return (EINVAL);
6336 		}
6337 		error = COPYOUT(ptr, obj.ipfo_ptr, sz);
6338 		if (error != 0) {
6339 			IPFERROR(66);
6340 			error = EFAULT;
6341 		}
6342 	} else {
6343 #ifdef	IPFILTER_COMPAT
6344 		error = ipf_out_compat(softc, &obj, ptr);
6345 #else
6346 		IPFERROR(65);
6347 		error = EINVAL;
6348 #endif
6349 	}
6350 	return (error);
6351 }
6352 
6353 
6354 /* ------------------------------------------------------------------------ */
6355 /* Function:    ipf_outobj                                                  */
6356 /* Returns:     int     - 0 = success, else failure                         */
6357 /* Parameters:  data(I) - pointer to ioctl data                             */
6358 /*              ptr(I)  - pointer to store real data in                     */
6359 /*              type(I) - type of structure being moved                     */
6360 /*                                                                          */
6361 /* Copy out the contents of what ptr is to where ipfobj points to.  In      */
6362 /* future, we add things to check for version numbers, sizes, etc, to make  */
6363 /* it backward  compatible at the ABI for user land.                        */
6364 /* ------------------------------------------------------------------------ */
6365 int
ipf_outobj(ipf_main_softc_t * softc,void * data,void * ptr,int type)6366 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type)
6367 {
6368 	ipfobj_t obj;
6369 	int error;
6370 
6371 	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6372 		IPFERROR(67);
6373 		return (EINVAL);
6374 	}
6375 
6376 	error = BCOPYIN(data, &obj, sizeof(obj));
6377 	if (error != 0) {
6378 		IPFERROR(126);
6379 		return (EFAULT);
6380 	}
6381 
6382 	if (obj.ipfo_type != type) {
6383 		IPFERROR(68);
6384 		return (EINVAL);
6385 	}
6386 
6387 	if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6388 		if ((ipf_objbytes[type][0] & 1) != 0) {
6389 			if (obj.ipfo_size < ipf_objbytes[type][1]) {
6390 				IPFERROR(69);
6391 				return (EINVAL);
6392 			}
6393 		} else if (obj.ipfo_size != ipf_objbytes[type][1]) {
6394 			IPFERROR(70);
6395 			return (EINVAL);
6396 		}
6397 
6398 		error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
6399 		if (error != 0) {
6400 			IPFERROR(73);
6401 			error = EFAULT;
6402 		}
6403 	} else {
6404 #ifdef	IPFILTER_COMPAT
6405 		error = ipf_out_compat(softc, &obj, ptr);
6406 #else
6407 		IPFERROR(72);
6408 		error = EINVAL;
6409 #endif
6410 	}
6411 	return (error);
6412 }
6413 
6414 
6415 /* ------------------------------------------------------------------------ */
6416 /* Function:    ipf_outobjk                                                 */
6417 /* Returns:     int     - 0 = success, else failure                         */
6418 /* Parameters:  obj(I)  - pointer to data description structure             */
6419 /*              ptr(I)  - pointer to kernel data to copy out                */
6420 /*                                                                          */
6421 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/
6422 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */
6423 /* already populated with information and now we just need to use it.       */
6424 /* There is no need for this function to have a "type" parameter as there   */
6425 /* is no point in validating information that comes from the kernel with    */
6426 /* itself.                                                                  */
6427 /* ------------------------------------------------------------------------ */
6428 int
ipf_outobjk(ipf_main_softc_t * softc,ipfobj_t * obj,void * ptr)6429 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr)
6430 {
6431 	int type = obj->ipfo_type;
6432 	int error;
6433 
6434 	if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6435 		IPFERROR(147);
6436 		return (EINVAL);
6437 	}
6438 
6439 	if (obj->ipfo_rev >= ipf_objbytes[type][2]) {
6440 		if ((ipf_objbytes[type][0] & 1) != 0) {
6441 			if (obj->ipfo_size < ipf_objbytes[type][1]) {
6442 				IPFERROR(148);
6443 				return (EINVAL);
6444 			}
6445 
6446 		} else if (obj->ipfo_size != ipf_objbytes[type][1]) {
6447 			IPFERROR(149);
6448 			return (EINVAL);
6449 		}
6450 
6451 		error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size);
6452 		if (error != 0) {
6453 			IPFERROR(150);
6454 			error = EFAULT;
6455 		}
6456 	} else {
6457 #ifdef  IPFILTER_COMPAT
6458 		error = ipf_out_compat(softc, obj, ptr);
6459 #else
6460 		IPFERROR(151);
6461 		error = EINVAL;
6462 #endif
6463 	}
6464 	return (error);
6465 }
6466 
6467 
6468 /* ------------------------------------------------------------------------ */
6469 /* Function:    ipf_checkl4sum                                              */
6470 /* Returns:     int     - 0 = good, -1 = bad, 1 = cannot check              */
6471 /* Parameters:  fin(I) - pointer to packet information                      */
6472 /*                                                                          */
6473 /* If possible, calculate the layer 4 checksum for the packet.  If this is  */
6474 /* not possible, return without indicating a failure or success but in a    */
6475 /* way that is ditinguishable. This function should only be called by the   */
6476 /* ipf_checkv6sum() for each platform.                                      */
6477 /* ------------------------------------------------------------------------ */
6478 inline int
ipf_checkl4sum(fr_info_t * fin)6479 ipf_checkl4sum(fr_info_t *fin)
6480 {
6481 	u_short sum, hdrsum, *csump;
6482 	udphdr_t *udp;
6483 	int dosum;
6484 
6485 	/*
6486 	 * If the TCP packet isn't a fragment, isn't too short and otherwise
6487 	 * isn't already considered "bad", then validate the checksum.  If
6488 	 * this check fails then considered the packet to be "bad".
6489 	 */
6490 	if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0)
6491 		return (1);
6492 
6493 	DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p);
6494 	if (fin->fin_out == 1) {
6495 		fin->fin_cksum = FI_CK_SUMOK;
6496 		return (0);
6497 	}
6498 
6499 	csump = NULL;
6500 	hdrsum = 0;
6501 	dosum = 0;
6502 	sum = 0;
6503 
6504 	switch (fin->fin_p)
6505 	{
6506 	case IPPROTO_TCP :
6507 		csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
6508 		dosum = 1;
6509 		break;
6510 
6511 	case IPPROTO_UDP :
6512 		udp = fin->fin_dp;
6513 		if (udp->uh_sum != 0) {
6514 			csump = &udp->uh_sum;
6515 			dosum = 1;
6516 		}
6517 		break;
6518 
6519 #ifdef USE_INET6
6520 	case IPPROTO_ICMPV6 :
6521 		csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum;
6522 		dosum = 1;
6523 		break;
6524 #endif
6525 
6526 	case IPPROTO_ICMP :
6527 		csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
6528 		dosum = 1;
6529 		break;
6530 
6531 	default :
6532 		return (1);
6533 		/*NOTREACHED*/
6534 	}
6535 
6536 	if (csump != NULL) {
6537 		hdrsum = *csump;
6538 		if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff)
6539 			hdrsum = 0x0000;
6540 	}
6541 
6542 	if (dosum) {
6543 		sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp);
6544 	}
6545 #if !defined(_KERNEL)
6546 	if (sum == hdrsum) {
6547 		FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
6548 	} else {
6549 		FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
6550 	}
6551 #endif
6552 	DT3(l4sums, u_short, hdrsum, u_short, sum, fr_info_t *, fin);
6553 #ifdef USE_INET6
6554 	if (hdrsum == sum || (sum == 0 && IP_V(fin->fin_ip) == 6)) {
6555 #else
6556 	if (hdrsum == sum) {
6557 #endif
6558 		fin->fin_cksum = FI_CK_SUMOK;
6559 		return (0);
6560 	}
6561 	fin->fin_cksum = FI_CK_BAD;
6562 	return (-1);
6563 }
6564 
6565 
6566 /* ------------------------------------------------------------------------ */
6567 /* Function:    ipf_ifpfillv4addr                                           */
6568 /* Returns:     int     - 0 = address update, -1 = address not updated      */
6569 /* Parameters:  atype(I)   - type of network address update to perform      */
6570 /*              sin(I)     - pointer to source of address information       */
6571 /*              mask(I)    - pointer to source of netmask information       */
6572 /*              inp(I)     - pointer to destination address store           */
6573 /*              inpmask(I) - pointer to destination netmask store           */
6574 /*                                                                          */
6575 /* Given a type of network address update (atype) to perform, copy          */
6576 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
6577 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
6578 /* which case the operation fails.  For all values of atype other than      */
6579 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
6580 /* value.                                                                   */
6581 /* ------------------------------------------------------------------------ */
6582 int
6583 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask,
6584 	struct in_addr *inp, struct in_addr *inpmask)
6585 {
6586 	if (inpmask != NULL && atype != FRI_NETMASKED)
6587 		inpmask->s_addr = 0xffffffff;
6588 
6589 	if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
6590 		if (atype == FRI_NETMASKED) {
6591 			if (inpmask == NULL)
6592 				return (-1);
6593 			inpmask->s_addr = mask->sin_addr.s_addr;
6594 		}
6595 		inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr;
6596 	} else {
6597 		inp->s_addr = sin->sin_addr.s_addr;
6598 	}
6599 	return (0);
6600 }
6601 
6602 
6603 #ifdef	USE_INET6
6604 /* ------------------------------------------------------------------------ */
6605 /* Function:    ipf_ifpfillv6addr                                           */
6606 /* Returns:     int     - 0 = address update, -1 = address not updated      */
6607 /* Parameters:  atype(I)   - type of network address update to perform      */
6608 /*              sin(I)     - pointer to source of address information       */
6609 /*              mask(I)    - pointer to source of netmask information       */
6610 /*              inp(I)     - pointer to destination address store           */
6611 /*              inpmask(I) - pointer to destination netmask store           */
6612 /*                                                                          */
6613 /* Given a type of network address update (atype) to perform, copy          */
6614 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
6615 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
6616 /* which case the operation fails.  For all values of atype other than      */
6617 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
6618 /* value.                                                                   */
6619 /* ------------------------------------------------------------------------ */
6620 int
6621 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin,
6622 	struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask)
6623 {
6624 	i6addr_t *src, *and;
6625 
6626 	src = (i6addr_t *)&sin->sin6_addr;
6627 	and = (i6addr_t *)&mask->sin6_addr;
6628 
6629 	if (inpmask != NULL && atype != FRI_NETMASKED) {
6630 		inpmask->i6[0] = 0xffffffff;
6631 		inpmask->i6[1] = 0xffffffff;
6632 		inpmask->i6[2] = 0xffffffff;
6633 		inpmask->i6[3] = 0xffffffff;
6634 	}
6635 
6636 	if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
6637 		if (atype == FRI_NETMASKED) {
6638 			if (inpmask == NULL)
6639 				return (-1);
6640 			inpmask->i6[0] = and->i6[0];
6641 			inpmask->i6[1] = and->i6[1];
6642 			inpmask->i6[2] = and->i6[2];
6643 			inpmask->i6[3] = and->i6[3];
6644 		}
6645 
6646 		inp->i6[0] = src->i6[0] & and->i6[0];
6647 		inp->i6[1] = src->i6[1] & and->i6[1];
6648 		inp->i6[2] = src->i6[2] & and->i6[2];
6649 		inp->i6[3] = src->i6[3] & and->i6[3];
6650 	} else {
6651 		inp->i6[0] = src->i6[0];
6652 		inp->i6[1] = src->i6[1];
6653 		inp->i6[2] = src->i6[2];
6654 		inp->i6[3] = src->i6[3];
6655 	}
6656 	return (0);
6657 }
6658 #endif
6659 
6660 
6661 /* ------------------------------------------------------------------------ */
6662 /* Function:    ipf_matchtag                                                */
6663 /* Returns:     0 == mismatch, 1 == match.                                  */
6664 /* Parameters:  tag1(I) - pointer to first tag to compare                   */
6665 /*              tag2(I) - pointer to second tag to compare                  */
6666 /*                                                                          */
6667 /* Returns true (non-zero) or false(0) if the two tag structures can be     */
6668 /* considered to be a match or not match, respectively.  The tag is 16      */
6669 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so    */
6670 /* compare the ints instead, for speed. tag1 is the master of the           */
6671 /* comparison.  This function should only be called with both tag1 and tag2 */
6672 /* as non-NULL pointers.                                                    */
6673 /* ------------------------------------------------------------------------ */
6674 int
6675 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2)
6676 {
6677 	if (tag1 == tag2)
6678 		return (1);
6679 
6680 	if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0))
6681 		return (1);
6682 
6683 	if ((tag1->ipt_num[0] == tag2->ipt_num[0]) &&
6684 	    (tag1->ipt_num[1] == tag2->ipt_num[1]) &&
6685 	    (tag1->ipt_num[2] == tag2->ipt_num[2]) &&
6686 	    (tag1->ipt_num[3] == tag2->ipt_num[3]))
6687 		return (1);
6688 	return (0);
6689 }
6690 
6691 
6692 /* ------------------------------------------------------------------------ */
6693 /* Function:    ipf_coalesce                                                */
6694 /* Returns:     1 == success, -1 == failure, 0 == no change                 */
6695 /* Parameters:  fin(I) - pointer to packet information                      */
6696 /*                                                                          */
6697 /* Attempt to get all of the packet data into a single, contiguous buffer.  */
6698 /* If this call returns a failure then the buffers have also been freed.    */
6699 /* ------------------------------------------------------------------------ */
6700 int
6701 ipf_coalesce(fr_info_t *fin)
6702 {
6703 
6704 	if ((fin->fin_flx & FI_COALESCE) != 0)
6705 		return (1);
6706 
6707 	/*
6708 	 * If the mbuf pointers indicate that there is no mbuf to work with,
6709 	* return but do not indicate success or failure.
6710 	 */
6711 	if (fin->fin_m == NULL || fin->fin_mp == NULL)
6712 		return (0);
6713 
6714 #if defined(_KERNEL)
6715 	if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
6716 		ipf_main_softc_t *softc = fin->fin_main_soft;
6717 
6718 		DT1(frb_coalesce, fr_info_t *, fin);
6719 		LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces);
6720 # if SOLARIS
6721 		FREE_MB_T(*fin->fin_mp);
6722 # endif
6723 		fin->fin_reason = FRB_COALESCE;
6724 		*fin->fin_mp = NULL;
6725 		fin->fin_m = NULL;
6726 		return (-1);
6727 	}
6728 #else
6729 	fin = fin;	/* LINT */
6730 #endif
6731 	return (1);
6732 }
6733 
6734 
6735 /*
6736  * The following table lists all of the tunable variables that can be
6737  * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt.  The format of each row
6738  * in the table below is as follows:
6739  *
6740  * pointer to value, name of value, minimum, maximum, size of the value's
6741  *     container, value attribute flags
6742  *
6743  * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED
6744  * means the value can only be written to when IPFilter is loaded but disabled.
6745  * The obvious implication is if neither of these are set then the value can be
6746  * changed at any time without harm.
6747  */
6748 
6749 
6750 /* ------------------------------------------------------------------------ */
6751 /* Function:    ipf_tune_findbycookie                                       */
6752 /* Returns:     NULL = search failed, else pointer to tune struct           */
6753 /* Parameters:  cookie(I) - cookie value to search for amongst tuneables    */
6754 /*              next(O)   - pointer to place to store the cookie for the    */
6755 /*                          "next" tuneable, if it is desired.              */
6756 /*                                                                          */
6757 /* This function is used to walk through all of the existing tunables with  */
6758 /* successive calls.  It searches the known tunables for the one which has  */
6759 /* a matching value for "cookie" - ie its address.  When returning a match, */
6760 /* the next one to be found may be returned inside next.                    */
6761 /* ------------------------------------------------------------------------ */
6762 static ipftuneable_t *
6763 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next)
6764 {
6765 	ipftuneable_t *ta, **tap;
6766 
6767 	for (ta = *ptop; ta->ipft_name != NULL; ta++)
6768 		if (ta == cookie) {
6769 			if (next != NULL) {
6770 				/*
6771 				 * If the next entry in the array has a name
6772 				* present, then return a pointer to it for
6773 				* where to go next, else return a pointer to
6774 				 * the dynaminc list as a key to search there
6775 				 * next.  This facilitates a weak linking of
6776 				 * the two "lists" together.
6777 				 */
6778 				if ((ta + 1)->ipft_name != NULL)
6779 					*next = ta + 1;
6780 				else
6781 					*next = ptop;
6782 			}
6783 			return (ta);
6784 		}
6785 
6786 	for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next)
6787 		if (tap == cookie) {
6788 			if (next != NULL)
6789 				*next = &ta->ipft_next;
6790 			return (ta);
6791 		}
6792 
6793 	if (next != NULL)
6794 		*next = NULL;
6795 	return (NULL);
6796 }
6797 
6798 
6799 /* ------------------------------------------------------------------------ */
6800 /* Function:    ipf_tune_findbyname                                         */
6801 /* Returns:     NULL = search failed, else pointer to tune struct           */
6802 /* Parameters:  name(I) - name of the tuneable entry to find.               */
6803 /*                                                                          */
6804 /* Search the static array of tuneables and the list of dynamic tuneables   */
6805 /* for an entry with a matching name.  If we can find one, return a pointer */
6806 /* to the matching structure.                                               */
6807 /* ------------------------------------------------------------------------ */
6808 static ipftuneable_t *
6809 ipf_tune_findbyname(ipftuneable_t *top, const char *name)
6810 {
6811 	ipftuneable_t *ta;
6812 
6813 	for (ta = top; ta != NULL; ta = ta->ipft_next)
6814 		if (!strcmp(ta->ipft_name, name)) {
6815 			return (ta);
6816 		}
6817 
6818 	return (NULL);
6819 }
6820 
6821 
6822 /* ------------------------------------------------------------------------ */
6823 /* Function:    ipf_tune_add_array                                          */
6824 /* Returns:     int - 0 == success, else failure                            */
6825 /* Parameters:  newtune - pointer to new tune array to add to tuneables     */
6826 /*                                                                          */
6827 /* Appends tune structures from the array passed in (newtune) to the end of */
6828 /* the current list of "dynamic" tuneable parameters.                       */
6829 /* If any entry to be added is already present (by name) then the operation */
6830 /* is aborted - entries that have been added are removed before returning.  */
6831 /* An entry with no name (NULL) is used as the indication that the end of   */
6832 /* the array has been reached.                                              */
6833 /* ------------------------------------------------------------------------ */
6834 int
6835 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune)
6836 {
6837 	ipftuneable_t *nt, *dt;
6838 	int error = 0;
6839 
6840 	for (nt = newtune; nt->ipft_name != NULL; nt++) {
6841 		error = ipf_tune_add(softc, nt);
6842 		if (error != 0) {
6843 			for (dt = newtune; dt != nt; dt++) {
6844 				(void) ipf_tune_del(softc, dt);
6845 			}
6846 		}
6847 	}
6848 
6849 	return (error);
6850 }
6851 
6852 
6853 /* ------------------------------------------------------------------------ */
6854 /* Function:    ipf_tune_array_link                                         */
6855 /* Returns:     0 == success, -1 == failure                                 */
6856 /* Parameters:  softc(I) - soft context pointerto work with                 */
6857 /*              array(I) - pointer to an array of tuneables                 */
6858 /*                                                                          */
6859 /* Given an array of tunables (array), append them to the current list of   */
6860 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the  */
6861 /* the array for being appended to the list, initialise all of the next     */
6862 /* pointers so we don't need to walk parts of it with ++ and others with    */
6863 /* next. The array is expected to have an entry with a NULL name as the     */
6864 /* terminator. Trying to add an array with no non-NULL names will return as */
6865 /* a failure.                                                               */
6866 /* ------------------------------------------------------------------------ */
6867 int
6868 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array)
6869 {
6870 	ipftuneable_t *t, **p;
6871 
6872 	t = array;
6873 	if (t->ipft_name == NULL)
6874 		return (-1);
6875 
6876 	for (; t[1].ipft_name != NULL; t++)
6877 		t[0].ipft_next = &t[1];
6878 	t->ipft_next = NULL;
6879 
6880 	/*
6881 	 * Since a pointer to the last entry isn't kept, we need to find it
6882 	 * each time we want to add new variables to the list.
6883 	 */
6884 	for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
6885 		if (t->ipft_name == NULL)
6886 			break;
6887 	*p = array;
6888 
6889 	return (0);
6890 }
6891 
6892 
6893 /* ------------------------------------------------------------------------ */
6894 /* Function:    ipf_tune_array_unlink                                       */
6895 /* Returns:     0 == success, -1 == failure                                 */
6896 /* Parameters:  softc(I) - soft context pointerto work with                 */
6897 /*              array(I) - pointer to an array of tuneables                 */
6898 /*                                                                          */
6899 /* ------------------------------------------------------------------------ */
6900 int
6901 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array)
6902 {
6903 	ipftuneable_t *t, **p;
6904 
6905 	for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
6906 		if (t == array)
6907 			break;
6908 	if (t == NULL)
6909 		return (-1);
6910 
6911 	for (; t[1].ipft_name != NULL; t++)
6912 		;
6913 
6914 	*p = t->ipft_next;
6915 
6916 	return (0);
6917 }
6918 
6919 
6920 /* ------------------------------------------------------------------------ */
6921 /* Function:   ipf_tune_array_copy                                          */
6922 /* Returns:    NULL = failure, else pointer to new array                    */
6923 /* Parameters: base(I)     - pointer to structure base                      */
6924 /*             size(I)     - size of the array at template                  */
6925 /*             template(I) - original array to copy                         */
6926 /*                                                                          */
6927 /* Allocate memory for a new set of tuneable values and copy everything     */
6928 /* from template into the new region of memory.  The new region is full of  */
6929 /* uninitialised pointers (ipft_next) so set them up.  Now, ipftp_offset... */
6930 /*                                                                          */
6931 /* NOTE: the following assumes that sizeof(long) == sizeof(void *)          */
6932 /* In the array template, ipftp_offset is the offset (in bytes) of the      */
6933 /* location of the tuneable value inside the structure pointed to by base.  */
6934 /* As ipftp_offset is a union over the pointers to the tuneable values, if  */
6935 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in   */
6936 /* ipftp_void that points to the stored value.                              */
6937 /* ------------------------------------------------------------------------ */
6938 ipftuneable_t *
6939 ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template)
6940 {
6941 	ipftuneable_t *copy;
6942 	int i;
6943 
6944 
6945 	KMALLOCS(copy, ipftuneable_t *, size);
6946 	if (copy == NULL) {
6947 		return (NULL);
6948 	}
6949 	bcopy(template, copy, size);
6950 
6951 	for (i = 0; copy[i].ipft_name; i++) {
6952 		copy[i].ipft_una.ipftp_offset += (u_long)base;
6953 		copy[i].ipft_next = copy + i + 1;
6954 	}
6955 
6956 	return (copy);
6957 }
6958 
6959 
6960 /* ------------------------------------------------------------------------ */
6961 /* Function:    ipf_tune_add                                                */
6962 /* Returns:     int - 0 == success, else failure                            */
6963 /* Parameters:  newtune - pointer to new tune entry to add to tuneables     */
6964 /*                                                                          */
6965 /* Appends tune structures from the array passed in (newtune) to the end of */
6966 /* the current list of "dynamic" tuneable parameters.  Once added, the      */
6967 /* owner of the object is not expected to ever change "ipft_next".          */
6968 /* ------------------------------------------------------------------------ */
6969 int
6970 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune)
6971 {
6972 	ipftuneable_t *ta, **tap;
6973 
6974 	ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name);
6975 	if (ta != NULL) {
6976 		IPFERROR(74);
6977 		return (EEXIST);
6978 	}
6979 
6980 	for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next)
6981 		;
6982 
6983 	newtune->ipft_next = NULL;
6984 	*tap = newtune;
6985 	return (0);
6986 }
6987 
6988 
6989 /* ------------------------------------------------------------------------ */
6990 /* Function:    ipf_tune_del                                                */
6991 /* Returns:     int - 0 == success, else failure                            */
6992 /* Parameters:  oldtune - pointer to tune entry to remove from the list of  */
6993 /*                        current dynamic tuneables                         */
6994 /*                                                                          */
6995 /* Search for the tune structure, by pointer, in the list of those that are */
6996 /* dynamically added at run time.  If found, adjust the list so that this   */
6997 /* structure is no longer part of it.                                       */
6998 /* ------------------------------------------------------------------------ */
6999 int
7000 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune)
7001 {
7002 	ipftuneable_t *ta, **tap;
7003 	int error = 0;
7004 
7005 	for (tap = &softc->ipf_tuners; (ta = *tap) != NULL;
7006 	     tap = &ta->ipft_next) {
7007 		if (ta == oldtune) {
7008 			*tap = oldtune->ipft_next;
7009 			oldtune->ipft_next = NULL;
7010 			break;
7011 		}
7012 	}
7013 
7014 	if (ta == NULL) {
7015 		error = ESRCH;
7016 		IPFERROR(75);
7017 	}
7018 	return (error);
7019 }
7020 
7021 
7022 /* ------------------------------------------------------------------------ */
7023 /* Function:    ipf_tune_del_array                                          */
7024 /* Returns:     int - 0 == success, else failure                            */
7025 /* Parameters:  oldtune - pointer to tuneables array                        */
7026 /*                                                                          */
7027 /* Remove each tuneable entry in the array from the list of "dynamic"       */
7028 /* tunables.  If one entry should fail to be found, an error will be        */
7029 /* returned and no further ones removed.                                    */
7030 /* An entry with a NULL name is used as the indicator of the last entry in  */
7031 /* the array.                                                               */
7032 /* ------------------------------------------------------------------------ */
7033 int
7034 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune)
7035 {
7036 	ipftuneable_t *ot;
7037 	int error = 0;
7038 
7039 	for (ot = oldtune; ot->ipft_name != NULL; ot++) {
7040 		error = ipf_tune_del(softc, ot);
7041 		if (error != 0)
7042 			break;
7043 	}
7044 
7045 	return (error);
7046 
7047 }
7048 
7049 
7050 /* ------------------------------------------------------------------------ */
7051 /* Function:    ipf_tune                                                    */
7052 /* Returns:     int - 0 == success, else failure                            */
7053 /* Parameters:  cmd(I)  - ioctl command number                              */
7054 /*              data(I) - pointer to ioctl data structure                   */
7055 /*                                                                          */
7056 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET.  These  */
7057 /* three ioctls provide the means to access and control global variables    */
7058 /* within IPFilter, allowing (for example) timeouts and table sizes to be   */
7059 /* changed without rebooting, reloading or recompiling.  The initialisation */
7060 /* and 'destruction' routines of the various components of ipfilter are all */
7061 /* each responsible for handling their own values being too big.            */
7062 /* ------------------------------------------------------------------------ */
7063 int
7064 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data)
7065 {
7066 	ipftuneable_t *ta;
7067 	ipftune_t tu;
7068 	void *cookie;
7069 	int error;
7070 
7071 	error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE);
7072 	if (error != 0)
7073 		return (error);
7074 
7075 	tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
7076 	cookie = tu.ipft_cookie;
7077 	ta = NULL;
7078 
7079 	switch (cmd)
7080 	{
7081 	case SIOCIPFGETNEXT :
7082 		/*
7083 		 * If cookie is non-NULL, assume it to be a pointer to the last
7084 		* entry we looked at, so find it (if possible) and return a
7085 		 * pointer to the next one after it.  The last entry in the
7086 		 * the table is a NULL entry, so when we get to it, set cookie
7087 		* to NULL and return that, indicating end of list, erstwhile
7088 		 * if we come in with cookie set to NULL, we are starting anew
7089 		 * at the front of the list.
7090 		 */
7091 		if (cookie != NULL) {
7092 			ta = ipf_tune_findbycookie(&softc->ipf_tuners,
7093 						   cookie, &tu.ipft_cookie);
7094 		} else {
7095 			ta = softc->ipf_tuners;
7096 			tu.ipft_cookie = ta + 1;
7097 		}
7098 		if (ta != NULL) {
7099 			/*
7100 			 * Entry found, but does the data pointed to by that
7101 			 * row fit in what we can return?
7102 			 */
7103 			if (ta->ipft_sz > sizeof(tu.ipft_un)) {
7104 				IPFERROR(76);
7105 				return (EINVAL);
7106 			}
7107 
7108 			tu.ipft_vlong = 0;
7109 			if (ta->ipft_sz == sizeof(u_long))
7110 				tu.ipft_vlong = *ta->ipft_plong;
7111 			else if (ta->ipft_sz == sizeof(u_int))
7112 				tu.ipft_vint = *ta->ipft_pint;
7113 			else if (ta->ipft_sz == sizeof(u_short))
7114 				tu.ipft_vshort = *ta->ipft_pshort;
7115 			else if (ta->ipft_sz == sizeof(u_char))
7116 				tu.ipft_vchar = *ta->ipft_pchar;
7117 
7118 			tu.ipft_sz = ta->ipft_sz;
7119 			tu.ipft_min = ta->ipft_min;
7120 			tu.ipft_max = ta->ipft_max;
7121 			tu.ipft_flags = ta->ipft_flags;
7122 			bcopy(ta->ipft_name, tu.ipft_name,
7123 			      MIN(sizeof(tu.ipft_name),
7124 				  strlen(ta->ipft_name) + 1));
7125 		}
7126 		error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7127 		break;
7128 
7129 	case SIOCIPFGET :
7130 	case SIOCIPFSET :
7131 		/*
7132 		 * Search by name or by cookie value for a particular entry
7133 		 * in the tuning parameter table.
7134 		 */
7135 		IPFERROR(77);
7136 		error = ESRCH;
7137 		if (cookie != NULL) {
7138 			ta = ipf_tune_findbycookie(&softc->ipf_tuners,
7139 						   cookie, NULL);
7140 			if (ta != NULL)
7141 				error = 0;
7142 		} else if (tu.ipft_name[0] != '\0') {
7143 			ta = ipf_tune_findbyname(softc->ipf_tuners,
7144 						 tu.ipft_name);
7145 			if (ta != NULL)
7146 				error = 0;
7147 		}
7148 		if (error != 0)
7149 			break;
7150 
7151 		if (cmd == (ioctlcmd_t)SIOCIPFGET) {
7152 			/*
7153 			 * Fetch the tuning parameters for a particular value
7154 			 */
7155 			tu.ipft_vlong = 0;
7156 			if (ta->ipft_sz == sizeof(u_long))
7157 				tu.ipft_vlong = *ta->ipft_plong;
7158 			else if (ta->ipft_sz == sizeof(u_int))
7159 				tu.ipft_vint = *ta->ipft_pint;
7160 			else if (ta->ipft_sz == sizeof(u_short))
7161 				tu.ipft_vshort = *ta->ipft_pshort;
7162 			else if (ta->ipft_sz == sizeof(u_char))
7163 				tu.ipft_vchar = *ta->ipft_pchar;
7164 			tu.ipft_cookie = ta;
7165 			tu.ipft_sz = ta->ipft_sz;
7166 			tu.ipft_min = ta->ipft_min;
7167 			tu.ipft_max = ta->ipft_max;
7168 			tu.ipft_flags = ta->ipft_flags;
7169 			error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7170 
7171 		} else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
7172 			/*
7173 			 * Set an internal parameter.  The hard part here is
7174 			 * getting the new value safely and correctly out of
7175 			 * the kernel (given we only know its size, not type.)
7176 			 */
7177 			u_long in;
7178 
7179 			if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
7180 			    (softc->ipf_running > 0)) {
7181 				IPFERROR(78);
7182 				error = EBUSY;
7183 				break;
7184 			}
7185 
7186 			in = tu.ipft_vlong;
7187 			if (in < ta->ipft_min || in > ta->ipft_max) {
7188 				IPFERROR(79);
7189 				error = EINVAL;
7190 				break;
7191 			}
7192 
7193 			if (ta->ipft_func != NULL) {
7194 				SPL_INT(s);
7195 
7196 				SPL_NET(s);
7197 				error = (*ta->ipft_func)(softc, ta,
7198 							 &tu.ipft_un);
7199 				SPL_X(s);
7200 
7201 			} else if (ta->ipft_sz == sizeof(u_long)) {
7202 				tu.ipft_vlong = *ta->ipft_plong;
7203 				*ta->ipft_plong = in;
7204 
7205 			} else if (ta->ipft_sz == sizeof(u_int)) {
7206 				tu.ipft_vint = *ta->ipft_pint;
7207 				*ta->ipft_pint = (u_int)(in & 0xffffffff);
7208 
7209 			} else if (ta->ipft_sz == sizeof(u_short)) {
7210 				tu.ipft_vshort = *ta->ipft_pshort;
7211 				*ta->ipft_pshort = (u_short)(in & 0xffff);
7212 
7213 			} else if (ta->ipft_sz == sizeof(u_char)) {
7214 				tu.ipft_vchar = *ta->ipft_pchar;
7215 				*ta->ipft_pchar = (u_char)(in & 0xff);
7216 			}
7217 			error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7218 		}
7219 		break;
7220 
7221 	default :
7222 		IPFERROR(80);
7223 		error = EINVAL;
7224 		break;
7225 	}
7226 
7227 	return (error);
7228 }
7229 
7230 
7231 /* ------------------------------------------------------------------------ */
7232 /* Function:    ipf_zerostats                                               */
7233 /* Returns:     int - 0 = success, else failure                             */
7234 /* Parameters:  data(O) - pointer to pointer for copying data back to       */
7235 /*                                                                          */
7236 /* Copies the current statistics out to userspace and then zero's the       */
7237 /* current ones in the kernel. The lock is only held across the bzero() as  */
7238 /* the copyout may result in paging (ie network activity.)                  */
7239 /* ------------------------------------------------------------------------ */
7240 int
7241 ipf_zerostats(ipf_main_softc_t *softc, caddr_t data)
7242 {
7243 	friostat_t fio;
7244 	ipfobj_t obj;
7245 	int error;
7246 
7247 	error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT);
7248 	if (error != 0)
7249 		return (error);
7250 	ipf_getstat(softc, &fio, obj.ipfo_rev);
7251 	error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT);
7252 	if (error != 0)
7253 		return (error);
7254 
7255 	WRITE_ENTER(&softc->ipf_mutex);
7256 	bzero(&softc->ipf_stats, sizeof(softc->ipf_stats));
7257 	RWLOCK_EXIT(&softc->ipf_mutex);
7258 
7259 	return (0);
7260 }
7261 
7262 
7263 /* ------------------------------------------------------------------------ */
7264 /* Function:    ipf_resolvedest                                             */
7265 /* Returns:     Nil                                                         */
7266 /* Parameters:  softc(I) - pointer to soft context main structure           */
7267 /*              base(I)  - where strings are stored                         */
7268 /*              fdp(IO)  - pointer to destination information to resolve    */
7269 /*              v(I)     - IP protocol version to match                     */
7270 /*                                                                          */
7271 /* Looks up an interface name in the frdest structure pointed to by fdp and */
7272 /* if a matching name can be found for the particular IP protocol version   */
7273 /* then store the interface pointer in the frdest struct.  If no match is   */
7274 /* found, then set the interface pointer to be -1 as NULL is considered to  */
7275 /* indicate there is no information at all in the structure.                */
7276 /* ------------------------------------------------------------------------ */
7277 int
7278 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v)
7279 {
7280 	int errval = 0;
7281 	void *ifp;
7282 
7283 	ifp = NULL;
7284 
7285 	if (fdp->fd_name != -1) {
7286 		if (fdp->fd_type == FRD_DSTLIST) {
7287 			ifp = ipf_lookup_res_name(softc, IPL_LOGIPF,
7288 						  IPLT_DSTLIST,
7289 						  base + fdp->fd_name,
7290 						  NULL);
7291 			if (ifp == NULL) {
7292 				IPFERROR(144);
7293 				errval = ESRCH;
7294 			}
7295 		} else {
7296 			ifp = GETIFP(base + fdp->fd_name, v);
7297 			if (ifp == NULL)
7298 				ifp = (void *)-1;
7299 		}
7300 	}
7301 	fdp->fd_ptr = ifp;
7302 
7303 	return (errval);
7304 }
7305 
7306 
7307 /* ------------------------------------------------------------------------ */
7308 /* Function:    ipf_resolvenic                                              */
7309 /* Returns:     void* - NULL = wildcard name, -1 = failed to find NIC, else */
7310 /*                      pointer to interface structure for NIC              */
7311 /* Parameters:  softc(I)- pointer to soft context main structure            */
7312 /*              name(I) - complete interface name                           */
7313 /*              v(I)    - IP protocol version                               */
7314 /*                                                                          */
7315 /* Look for a network interface structure that firstly has a matching name  */
7316 /* to that passed in and that is also being used for that IP protocol       */
7317 /* version (necessary on some platforms where there are separate listings   */
7318 /* for both IPv4 and IPv6 on the same physical NIC.                         */
7319 /* ------------------------------------------------------------------------ */
7320 void *
7321 ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v)
7322 {
7323 	void *nic;
7324 
7325 	softc = softc;	/* gcc -Wextra */
7326 	if (name[0] == '\0')
7327 		return (NULL);
7328 
7329 	if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) {
7330 		return (NULL);
7331 	}
7332 
7333 	nic = GETIFP(name, v);
7334 	if (nic == NULL)
7335 		nic = (void *)-1;
7336 	return (nic);
7337 }
7338 
7339 
7340 /* ------------------------------------------------------------------------ */
7341 /* Function:    ipf_token_expire                                            */
7342 /* Returns:     None.                                                       */
7343 /* Parameters:  softc(I) - pointer to soft context main structure           */
7344 /*                                                                          */
7345 /* This function is run every ipf tick to see if there are any tokens that  */
7346 /* have been held for too long and need to be freed up.                     */
7347 /* ------------------------------------------------------------------------ */
7348 void
7349 ipf_token_expire(ipf_main_softc_t *softc)
7350 {
7351 	ipftoken_t *it;
7352 
7353 	WRITE_ENTER(&softc->ipf_tokens);
7354 	while ((it = softc->ipf_token_head) != NULL) {
7355 		if (it->ipt_die > softc->ipf_ticks)
7356 			break;
7357 
7358 		ipf_token_deref(softc, it);
7359 	}
7360 	RWLOCK_EXIT(&softc->ipf_tokens);
7361 }
7362 
7363 
7364 /* ------------------------------------------------------------------------ */
7365 /* Function:    ipf_token_flush                                             */
7366 /* Returns:     None.                                                       */
7367 /* Parameters:  softc(I) - pointer to soft context main structure           */
7368 /*                                                                          */
7369 /* Loop through all of the existing tokens and call deref to see if they    */
7370 /* can be freed. Normally a function like this might just loop on           */
7371 /* ipf_token_head but there is a chance that a token might have a ref count */
7372 /* of greater than one and in that case the reference would drop twice      */
7373 /* by code that is only entitled to drop it once.                           */
7374 /* ------------------------------------------------------------------------ */
7375 static void
7376 ipf_token_flush(ipf_main_softc_t *softc)
7377 {
7378 	ipftoken_t *it, *next;
7379 
7380 	WRITE_ENTER(&softc->ipf_tokens);
7381 	for (it = softc->ipf_token_head; it != NULL; it = next) {
7382 		next = it->ipt_next;
7383 		(void) ipf_token_deref(softc, it);
7384 	}
7385 	RWLOCK_EXIT(&softc->ipf_tokens);
7386 }
7387 
7388 
7389 /* ------------------------------------------------------------------------ */
7390 /* Function:    ipf_token_del                                               */
7391 /* Returns:     int     - 0 = success, else error                           */
7392 /* Parameters:  softc(I)- pointer to soft context main structure            */
7393 /*              type(I) - the token type to match                           */
7394 /*              uid(I)  - uid owning the token                              */
7395 /*              ptr(I)  - context pointer for the token                     */
7396 /*                                                                          */
7397 /* This function looks for a token in the current list that matches up      */
7398 /* the fields (type, uid, ptr).  If none is found, ESRCH is returned, else  */
7399 /* call ipf_token_dewref() to remove it from the list. In the event that    */
7400 /* the token has a reference held elsewhere, setting ipt_complete to 2      */
7401 /* enables debugging to distinguish between the two paths that ultimately   */
7402 /* lead to a token to be deleted.                                           */
7403 /* ------------------------------------------------------------------------ */
7404 int
7405 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr)
7406 {
7407 	ipftoken_t *it;
7408 	int error;
7409 
7410 	IPFERROR(82);
7411 	error = ESRCH;
7412 
7413 	WRITE_ENTER(&softc->ipf_tokens);
7414 	for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
7415 		if (ptr == it->ipt_ctx && type == it->ipt_type &&
7416 		    uid == it->ipt_uid) {
7417 			it->ipt_complete = 2;
7418 			ipf_token_deref(softc, it);
7419 			error = 0;
7420 			break;
7421 		}
7422 	}
7423 	RWLOCK_EXIT(&softc->ipf_tokens);
7424 
7425 	return (error);
7426 }
7427 
7428 
7429 /* ------------------------------------------------------------------------ */
7430 /* Function:    ipf_token_mark_complete                                     */
7431 /* Returns:     None.                                                       */
7432 /* Parameters:  token(I) - pointer to token structure                       */
7433 /*                                                                          */
7434 /* Mark a token as being ineligable for being found with ipf_token_find.    */
7435 /* ------------------------------------------------------------------------ */
7436 void
7437 ipf_token_mark_complete(ipftoken_t *token)
7438 {
7439 	if (token->ipt_complete == 0)
7440 		token->ipt_complete = 1;
7441 }
7442 
7443 
7444 /* ------------------------------------------------------------------------ */
7445 /* Function:    ipf_token_find                                               */
7446 /* Returns:     ipftoken_t * - NULL if no memory, else pointer to token     */
7447 /* Parameters:  softc(I)- pointer to soft context main structure            */
7448 /*              type(I) - the token type to match                           */
7449 /*              uid(I)  - uid owning the token                              */
7450 /*              ptr(I)  - context pointer for the token                     */
7451 /*                                                                          */
7452 /* This function looks for a live token in the list of current tokens that  */
7453 /* matches the tuple (type, uid, ptr).  If one cannot be found then one is  */
7454 /* allocated.  If one is found then it is moved to the top of the list of   */
7455 /* currently active tokens.                                                 */
7456 /* ------------------------------------------------------------------------ */
7457 ipftoken_t *
7458 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr)
7459 {
7460 	ipftoken_t *it, *new;
7461 
7462 	WRITE_ENTER(&softc->ipf_tokens);
7463 	for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
7464 		if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
7465 		    (uid == it->ipt_uid) && (it->ipt_complete < 2))
7466 			break;
7467 	}
7468 
7469 	if (it == NULL) {
7470 		KMALLOC(new, ipftoken_t *);
7471 		if (new != NULL)
7472 			bzero((char *)new, sizeof(*new));
7473 
7474 		it = new;
7475 		new = NULL;
7476 		if (it == NULL) {
7477 			RWLOCK_EXIT(&softc->ipf_tokens);
7478 			return (NULL);
7479 		}
7480 		it->ipt_ctx = ptr;
7481 		it->ipt_uid = uid;
7482 		it->ipt_type = type;
7483 		it->ipt_ref = 1;
7484 	} else {
7485 		if (it->ipt_complete > 0)
7486 			it = NULL;
7487 		else
7488 			ipf_token_unlink(softc, it);
7489 	}
7490 
7491 	if (it != NULL) {
7492 		it->ipt_pnext = softc->ipf_token_tail;
7493 		*softc->ipf_token_tail = it;
7494 		softc->ipf_token_tail = &it->ipt_next;
7495 		it->ipt_next = NULL;
7496 		it->ipt_ref++;
7497 
7498 		it->ipt_die = softc->ipf_ticks + 20;
7499 	}
7500 
7501 	RWLOCK_EXIT(&softc->ipf_tokens);
7502 
7503 	return (it);
7504 }
7505 
7506 
7507 /* ------------------------------------------------------------------------ */
7508 /* Function:    ipf_token_unlink                                            */
7509 /* Returns:     None.                                                       */
7510 /* Parameters:  softc(I) - pointer to soft context main structure           */
7511 /*              token(I) - pointer to token structure                       */
7512 /* Write Locks: ipf_tokens                                                  */
7513 /*                                                                          */
7514 /* This function unlinks a token structure from the linked list of tokens   */
7515 /* that "own" it.  The head pointer never needs to be explicitly adjusted   */
7516 /* but the tail does due to the linked list implementation.                 */
7517 /* ------------------------------------------------------------------------ */
7518 static void
7519 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token)
7520 {
7521 
7522 	if (softc->ipf_token_tail == &token->ipt_next)
7523 		softc->ipf_token_tail = token->ipt_pnext;
7524 
7525 	*token->ipt_pnext = token->ipt_next;
7526 	if (token->ipt_next != NULL)
7527 		token->ipt_next->ipt_pnext = token->ipt_pnext;
7528 	token->ipt_next = NULL;
7529 	token->ipt_pnext = NULL;
7530 }
7531 
7532 
7533 /* ------------------------------------------------------------------------ */
7534 /* Function:    ipf_token_deref                                             */
7535 /* Returns:     int      - 0 == token freed, else reference count           */
7536 /* Parameters:  softc(I) - pointer to soft context main structure           */
7537 /*              token(I) - pointer to token structure                       */
7538 /* Write Locks: ipf_tokens                                                  */
7539 /*                                                                          */
7540 /* Drop the reference count on the token structure and if it drops to zero, */
7541 /* call the dereference function for the token type because it is then      */
7542 /* possible to free the token data structure.                               */
7543 /* ------------------------------------------------------------------------ */
7544 int
7545 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token)
7546 {
7547 	void *data, **datap;
7548 
7549 	ASSERT(token->ipt_ref > 0);
7550 	token->ipt_ref--;
7551 	if (token->ipt_ref > 0)
7552 		return (token->ipt_ref);
7553 
7554 	data = token->ipt_data;
7555 	datap = &data;
7556 
7557 	if ((data != NULL) && (data != (void *)-1)) {
7558 		switch (token->ipt_type)
7559 		{
7560 		case IPFGENITER_IPF :
7561 			(void) ipf_derefrule(softc, (frentry_t **)datap);
7562 			break;
7563 		case IPFGENITER_IPNAT :
7564 			WRITE_ENTER(&softc->ipf_nat);
7565 			ipf_nat_rule_deref(softc, (ipnat_t **)datap);
7566 			RWLOCK_EXIT(&softc->ipf_nat);
7567 			break;
7568 		case IPFGENITER_NAT :
7569 			ipf_nat_deref(softc, (nat_t **)datap);
7570 			break;
7571 		case IPFGENITER_STATE :
7572 			ipf_state_deref(softc, (ipstate_t **)datap);
7573 			break;
7574 		case IPFGENITER_FRAG :
7575 			ipf_frag_pkt_deref(softc, (ipfr_t **)datap);
7576 			break;
7577 		case IPFGENITER_NATFRAG :
7578 			ipf_frag_nat_deref(softc, (ipfr_t **)datap);
7579 			break;
7580 		case IPFGENITER_HOSTMAP :
7581 			WRITE_ENTER(&softc->ipf_nat);
7582 			ipf_nat_hostmapdel(softc, (hostmap_t **)datap);
7583 			RWLOCK_EXIT(&softc->ipf_nat);
7584 			break;
7585 		default :
7586 			ipf_lookup_iterderef(softc, token->ipt_type, data);
7587 			break;
7588 		}
7589 	}
7590 
7591 	ipf_token_unlink(softc, token);
7592 	KFREE(token);
7593 	return (0);
7594 }
7595 
7596 
7597 /* ------------------------------------------------------------------------ */
7598 /* Function:    ipf_nextrule                                                */
7599 /* Returns:     frentry_t * - NULL == no more rules, else pointer to next   */
7600 /* Parameters:  softc(I)    - pointer to soft context main structure        */
7601 /*              fr(I)       - pointer to filter rule                        */
7602 /*              out(I)      - 1 == out rules, 0 == input rules              */
7603 /*                                                                          */
7604 /* Starting with "fr", find the next rule to visit. This includes visiting  */
7605 /* the list of rule groups if either fr is NULL (empty list) or it is the   */
7606 /* last rule in the list. When walking rule lists, it is either input or    */
7607 /* output rules that are returned, never both.                              */
7608 /* ------------------------------------------------------------------------ */
7609 static frentry_t *
7610 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, frentry_t *fr,
7611 	int out)
7612 {
7613 	frentry_t *next;
7614 	frgroup_t *fg;
7615 
7616 	if (fr != NULL && fr->fr_group != -1) {
7617 		fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group,
7618 				   unit, active, NULL);
7619 		if (fg != NULL)
7620 			fg = fg->fg_next;
7621 	} else {
7622 		fg = softc->ipf_groups[unit][active];
7623 	}
7624 
7625 	while (fg != NULL) {
7626 		next = fg->fg_start;
7627 		while (next != NULL) {
7628 			if (out) {
7629 				if (next->fr_flags & FR_OUTQUE)
7630 					return (next);
7631 			} else if (next->fr_flags & FR_INQUE) {
7632 				return (next);
7633 			}
7634 			next = next->fr_next;
7635 		}
7636 		if (next == NULL)
7637 			fg = fg->fg_next;
7638 	}
7639 
7640 	return (NULL);
7641 }
7642 
7643 /* ------------------------------------------------------------------------ */
7644 /* Function:    ipf_getnextrule                                             */
7645 /* Returns:     int - 0 = success, else error                               */
7646 /* Parameters:  softc(I)- pointer to soft context main structure            */
7647 /*              t(I)   - pointer to destination information to resolve      */
7648 /*              ptr(I) - pointer to ipfobj_t to copyin from user space      */
7649 /*                                                                          */
7650 /* This function's first job is to bring in the ipfruleiter_t structure via */
7651 /* the ipfobj_t structure to determine what should be the next rule to      */
7652 /* return. Once the ipfruleiter_t has been brought in, it then tries to     */
7653 /* find the 'next rule'.  This may include searching rule group lists or    */
7654 /* just be as simple as looking at the 'next' field in the rule structure.  */
7655 /* When we have found the rule to return, increase its reference count and  */
7656 /* if we used an existing rule to get here, decrease its reference count.   */
7657 /* ------------------------------------------------------------------------ */
7658 int
7659 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr)
7660 {
7661 	frentry_t *fr, *next, zero;
7662 	ipfruleiter_t it;
7663 	int error, out;
7664 	frgroup_t *fg;
7665 	ipfobj_t obj;
7666 	int predict;
7667 	char *dst;
7668 	int unit;
7669 
7670 	if (t == NULL || ptr == NULL) {
7671 		IPFERROR(84);
7672 		return (EFAULT);
7673 	}
7674 
7675 	error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER);
7676 	if (error != 0)
7677 		return (error);
7678 
7679 	if ((it.iri_inout < 0) || (it.iri_inout > 3)) {
7680 		IPFERROR(85);
7681 		return (EINVAL);
7682 	}
7683 	if ((it.iri_active != 0) && (it.iri_active != 1)) {
7684 		IPFERROR(86);
7685 		return (EINVAL);
7686 	}
7687 	if (it.iri_nrules == 0) {
7688 		IPFERROR(87);
7689 		return (ENOSPC);
7690 	}
7691 	if (it.iri_rule == NULL) {
7692 		IPFERROR(88);
7693 		return (EFAULT);
7694 	}
7695 
7696 	fg = NULL;
7697 	fr = t->ipt_data;
7698 	if ((it.iri_inout & F_OUT) != 0)
7699 		out = 1;
7700 	else
7701 		out = 0;
7702 	if ((it.iri_inout & F_ACIN) != 0)
7703 		unit = IPL_LOGCOUNT;
7704 	else
7705 		unit = IPL_LOGIPF;
7706 
7707 	READ_ENTER(&softc->ipf_mutex);
7708 	if (fr == NULL) {
7709 		if (*it.iri_group == '\0') {
7710 			if (unit == IPL_LOGCOUNT) {
7711 				next = softc->ipf_acct[out][it.iri_active];
7712 			} else {
7713 				next = softc->ipf_rules[out][it.iri_active];
7714 			}
7715 			if (next == NULL)
7716 				next = ipf_nextrule(softc, it.iri_active,
7717 						    unit, NULL, out);
7718 		} else {
7719 			fg = ipf_findgroup(softc, it.iri_group, unit,
7720 					   it.iri_active, NULL);
7721 			if (fg != NULL)
7722 				next = fg->fg_start;
7723 			else
7724 				next = NULL;
7725 		}
7726 	} else {
7727 		next = fr->fr_next;
7728 		if (next == NULL)
7729 			next = ipf_nextrule(softc, it.iri_active, unit,
7730 					    fr, out);
7731 	}
7732 
7733 	if (next != NULL && next->fr_next != NULL)
7734 		predict = 1;
7735 	else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL)
7736 		predict = 1;
7737 	else
7738 		predict = 0;
7739 
7740 	if (fr != NULL)
7741 		(void) ipf_derefrule(softc, &fr);
7742 
7743 	obj.ipfo_type = IPFOBJ_FRENTRY;
7744 	dst = (char *)it.iri_rule;
7745 
7746 	if (next != NULL) {
7747 		obj.ipfo_size = next->fr_size;
7748 		MUTEX_ENTER(&next->fr_lock);
7749 		next->fr_ref++;
7750 		MUTEX_EXIT(&next->fr_lock);
7751 		t->ipt_data = next;
7752 	} else {
7753 		obj.ipfo_size = sizeof(frentry_t);
7754 		bzero(&zero, sizeof(zero));
7755 		next = &zero;
7756 		t->ipt_data = NULL;
7757 	}
7758 	it.iri_rule = predict ? next : NULL;
7759 	if (predict == 0)
7760 		ipf_token_mark_complete(t);
7761 
7762 	RWLOCK_EXIT(&softc->ipf_mutex);
7763 
7764 	obj.ipfo_ptr = dst;
7765 	error = ipf_outobjk(softc, &obj, next);
7766 	if (error == 0 && t->ipt_data != NULL) {
7767 		dst += obj.ipfo_size;
7768 		if (next->fr_data != NULL) {
7769 			ipfobj_t dobj;
7770 
7771 			if (next->fr_type == FR_T_IPFEXPR)
7772 				dobj.ipfo_type = IPFOBJ_IPFEXPR;
7773 			else
7774 				dobj.ipfo_type = IPFOBJ_FRIPF;
7775 			dobj.ipfo_size = next->fr_dsize;
7776 			dobj.ipfo_rev = obj.ipfo_rev;
7777 			dobj.ipfo_ptr = dst;
7778 			error = ipf_outobjk(softc, &dobj, next->fr_data);
7779 		}
7780 	}
7781 
7782 	if ((fr != NULL) && (next == &zero))
7783 		(void) ipf_derefrule(softc, &fr);
7784 
7785 	return (error);
7786 }
7787 
7788 
7789 /* ------------------------------------------------------------------------ */
7790 /* Function:    ipf_frruleiter                                              */
7791 /* Returns:     int - 0 = success, else error                               */
7792 /* Parameters:  softc(I)- pointer to soft context main structure            */
7793 /*              data(I) - the token type to match                           */
7794 /*              uid(I)  - uid owning the token                              */
7795 /*              ptr(I)  - context pointer for the token                     */
7796 /*                                                                          */
7797 /* This function serves as a stepping stone between ipf_ipf_ioctl and       */
7798 /* ipf_getnextrule.  It's role is to find the right token in the kernel for */
7799 /* the process doing the ioctl and use that to ask for the next rule.       */
7800 /* ------------------------------------------------------------------------ */
7801 static int
7802 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
7803 {
7804 	ipftoken_t *token;
7805 	ipfruleiter_t it;
7806 	ipfobj_t obj;
7807 	int error;
7808 
7809 	token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx);
7810 	if (token != NULL) {
7811 		error = ipf_getnextrule(softc, token, data);
7812 		WRITE_ENTER(&softc->ipf_tokens);
7813 		ipf_token_deref(softc, token);
7814 		RWLOCK_EXIT(&softc->ipf_tokens);
7815 	} else {
7816 		error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER);
7817 		if (error != 0)
7818 			return (error);
7819 		it.iri_rule = NULL;
7820 		error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER);
7821 	}
7822 
7823 	return (error);
7824 }
7825 
7826 
7827 /* ------------------------------------------------------------------------ */
7828 /* Function:    ipf_geniter                                                 */
7829 /* Returns:     int - 0 = success, else error                               */
7830 /* Parameters:  softc(I) - pointer to soft context main structure           */
7831 /*              token(I) - pointer to ipftoken_t structure                  */
7832 /*              itp(I)   - pointer to iterator data                         */
7833 /*                                                                          */
7834 /* Decide which iterator function to call using information passed through  */
7835 /* the ipfgeniter_t structure at itp.                                       */
7836 /* ------------------------------------------------------------------------ */
7837 static int
7838 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp)
7839 {
7840 	int error;
7841 
7842 	switch (itp->igi_type)
7843 	{
7844 	case IPFGENITER_FRAG :
7845 		error = ipf_frag_pkt_next(softc, token, itp);
7846 		break;
7847 	default :
7848 		IPFERROR(92);
7849 		error = EINVAL;
7850 		break;
7851 	}
7852 
7853 	return (error);
7854 }
7855 
7856 
7857 /* ------------------------------------------------------------------------ */
7858 /* Function:    ipf_genericiter                                             */
7859 /* Returns:     int - 0 = success, else error                               */
7860 /* Parameters:  softc(I)- pointer to soft context main structure            */
7861 /*              data(I) - the token type to match                           */
7862 /*              uid(I)  - uid owning the token                              */
7863 /*              ptr(I)  - context pointer for the token                     */
7864 /*                                                                          */
7865 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role   */
7866 /* ------------------------------------------------------------------------ */
7867 int
7868 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx)
7869 {
7870 	ipftoken_t *token;
7871 	ipfgeniter_t iter;
7872 	int error;
7873 
7874 	error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER);
7875 	if (error != 0)
7876 		return (error);
7877 
7878 	token = ipf_token_find(softc, iter.igi_type, uid, ctx);
7879 	if (token != NULL) {
7880 		token->ipt_subtype = iter.igi_type;
7881 		error = ipf_geniter(softc, token, &iter);
7882 		WRITE_ENTER(&softc->ipf_tokens);
7883 		ipf_token_deref(softc, token);
7884 		RWLOCK_EXIT(&softc->ipf_tokens);
7885 	} else {
7886 		IPFERROR(93);
7887 		error = 0;
7888 	}
7889 
7890 	return (error);
7891 }
7892 
7893 
7894 /* ------------------------------------------------------------------------ */
7895 /* Function:    ipf_ipf_ioctl                                               */
7896 /* Returns:     int - 0 = success, else error                               */
7897 /* Parameters:  softc(I)- pointer to soft context main structure           */
7898 /*              data(I) - the token type to match                           */
7899 /*              cmd(I)  - the ioctl command number                          */
7900 /*              mode(I) - mode flags for the ioctl                          */
7901 /*              uid(I)  - uid owning the token                              */
7902 /*              ptr(I)  - context pointer for the token                     */
7903 /*                                                                          */
7904 /* This function handles all of the ioctl command that are actually isssued */
7905 /* to the /dev/ipl device.                                                  */
7906 /* ------------------------------------------------------------------------ */
7907 int
7908 ipf_ipf_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, int mode,
7909 	int uid, void *ctx)
7910 {
7911 	friostat_t fio;
7912 	int error, tmp;
7913 	ipfobj_t obj;
7914 	SPL_INT(s);
7915 
7916 	switch (cmd)
7917 	{
7918 	case SIOCFRENB :
7919 		if (!(mode & FWRITE)) {
7920 			IPFERROR(94);
7921 			error = EPERM;
7922 		} else {
7923 			error = BCOPYIN(data, &tmp, sizeof(tmp));
7924 			if (error != 0) {
7925 				IPFERROR(95);
7926 				error = EFAULT;
7927 				break;
7928 			}
7929 
7930 			WRITE_ENTER(&softc->ipf_global);
7931 			if (tmp) {
7932 				if (softc->ipf_running > 0)
7933 					error = 0;
7934 				else
7935 					error = ipfattach(softc);
7936 				if (error == 0)
7937 					softc->ipf_running = 1;
7938 				else
7939 					(void) ipfdetach(softc);
7940 			} else {
7941 				if (softc->ipf_running == 1)
7942 					error = ipfdetach(softc);
7943 				else
7944 					error = 0;
7945 				if (error == 0)
7946 					softc->ipf_running = -1;
7947 			}
7948 			RWLOCK_EXIT(&softc->ipf_global);
7949 		}
7950 		break;
7951 
7952 	case SIOCIPFSET :
7953 		if (!(mode & FWRITE)) {
7954 			IPFERROR(96);
7955 			error = EPERM;
7956 			break;
7957 		}
7958 		/* FALLTHRU */
7959 	case SIOCIPFGETNEXT :
7960 	case SIOCIPFGET :
7961 		error = ipf_ipftune(softc, cmd, (void *)data);
7962 		break;
7963 
7964 	case SIOCSETFF :
7965 		if (!(mode & FWRITE)) {
7966 			IPFERROR(97);
7967 			error = EPERM;
7968 		} else {
7969 			error = BCOPYIN(data, &softc->ipf_flags,
7970 					sizeof(softc->ipf_flags));
7971 			if (error != 0) {
7972 				IPFERROR(98);
7973 				error = EFAULT;
7974 			}
7975 		}
7976 		break;
7977 
7978 	case SIOCGETFF :
7979 		error = BCOPYOUT(&softc->ipf_flags, data,
7980 				 sizeof(softc->ipf_flags));
7981 		if (error != 0) {
7982 			IPFERROR(99);
7983 			error = EFAULT;
7984 		}
7985 		break;
7986 
7987 	case SIOCFUNCL :
7988 		error = ipf_resolvefunc(softc, (void *)data);
7989 		break;
7990 
7991 	case SIOCINAFR :
7992 	case SIOCRMAFR :
7993 	case SIOCADAFR :
7994 	case SIOCZRLST :
7995 		if (!(mode & FWRITE)) {
7996 			IPFERROR(100);
7997 			error = EPERM;
7998 		} else {
7999 			error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
8000 					  softc->ipf_active, 1);
8001 		}
8002 		break;
8003 
8004 	case SIOCINIFR :
8005 	case SIOCRMIFR :
8006 	case SIOCADIFR :
8007 		if (!(mode & FWRITE)) {
8008 			IPFERROR(101);
8009 			error = EPERM;
8010 		} else {
8011 			error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
8012 					  1 - softc->ipf_active, 1);
8013 		}
8014 		break;
8015 
8016 	case SIOCSWAPA :
8017 		if (!(mode & FWRITE)) {
8018 			IPFERROR(102);
8019 			error = EPERM;
8020 		} else {
8021 			WRITE_ENTER(&softc->ipf_mutex);
8022 			error = BCOPYOUT(&softc->ipf_active, data,
8023 					 sizeof(softc->ipf_active));
8024 			if (error != 0) {
8025 				IPFERROR(103);
8026 				error = EFAULT;
8027 			} else {
8028 				softc->ipf_active = 1 - softc->ipf_active;
8029 			}
8030 			RWLOCK_EXIT(&softc->ipf_mutex);
8031 		}
8032 		break;
8033 
8034 	case SIOCGETFS :
8035 		error = ipf_inobj(softc, (void *)data, &obj, &fio,
8036 				  IPFOBJ_IPFSTAT);
8037 		if (error != 0)
8038 			break;
8039 		ipf_getstat(softc, &fio, obj.ipfo_rev);
8040 		error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT);
8041 		break;
8042 
8043 	case SIOCFRZST :
8044 		if (!(mode & FWRITE)) {
8045 			IPFERROR(104);
8046 			error = EPERM;
8047 		} else
8048 			error = ipf_zerostats(softc, (caddr_t)data);
8049 		break;
8050 
8051 	case SIOCIPFFL :
8052 		if (!(mode & FWRITE)) {
8053 			IPFERROR(105);
8054 			error = EPERM;
8055 		} else {
8056 			error = BCOPYIN(data, &tmp, sizeof(tmp));
8057 			if (!error) {
8058 				tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
8059 				error = BCOPYOUT(&tmp, data, sizeof(tmp));
8060 				if (error != 0) {
8061 					IPFERROR(106);
8062 					error = EFAULT;
8063 				}
8064 			} else {
8065 				IPFERROR(107);
8066 				error = EFAULT;
8067 			}
8068 		}
8069 		break;
8070 
8071 #ifdef USE_INET6
8072 	case SIOCIPFL6 :
8073 		if (!(mode & FWRITE)) {
8074 			IPFERROR(108);
8075 			error = EPERM;
8076 		} else {
8077 			error = BCOPYIN(data, &tmp, sizeof(tmp));
8078 			if (!error) {
8079 				tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
8080 				error = BCOPYOUT(&tmp, data, sizeof(tmp));
8081 				if (error != 0) {
8082 					IPFERROR(109);
8083 					error = EFAULT;
8084 				}
8085 			} else {
8086 				IPFERROR(110);
8087 				error = EFAULT;
8088 			}
8089 		}
8090 		break;
8091 #endif
8092 
8093 	case SIOCSTLCK :
8094 		if (!(mode & FWRITE)) {
8095 			IPFERROR(122);
8096 			error = EPERM;
8097 		} else {
8098 			error = BCOPYIN(data, &tmp, sizeof(tmp));
8099 			if (error == 0) {
8100 				ipf_state_setlock(softc->ipf_state_soft, tmp);
8101 				ipf_nat_setlock(softc->ipf_nat_soft, tmp);
8102 				ipf_frag_setlock(softc->ipf_frag_soft, tmp);
8103 				ipf_auth_setlock(softc->ipf_auth_soft, tmp);
8104 			} else {
8105 				IPFERROR(111);
8106 				error = EFAULT;
8107 			}
8108 		}
8109 		break;
8110 
8111 #ifdef	IPFILTER_LOG
8112 	case SIOCIPFFB :
8113 		if (!(mode & FWRITE)) {
8114 			IPFERROR(112);
8115 			error = EPERM;
8116 		} else {
8117 			tmp = ipf_log_clear(softc, IPL_LOGIPF);
8118 			error = BCOPYOUT(&tmp, data, sizeof(tmp));
8119 			if (error) {
8120 				IPFERROR(113);
8121 				error = EFAULT;
8122 			}
8123 		}
8124 		break;
8125 #endif /* IPFILTER_LOG */
8126 
8127 	case SIOCFRSYN :
8128 		if (!(mode & FWRITE)) {
8129 			IPFERROR(114);
8130 			error = EPERM;
8131 		} else {
8132 			WRITE_ENTER(&softc->ipf_global);
8133 #if (SOLARIS && defined(_KERNEL)) && !defined(INSTANCES)
8134 			error = ipfsync();
8135 #else
8136 			ipf_sync(softc, NULL);
8137 			error = 0;
8138 #endif
8139 			RWLOCK_EXIT(&softc->ipf_global);
8140 
8141 		}
8142 		break;
8143 
8144 	case SIOCGFRST :
8145 		error = ipf_outobj(softc, (void *)data,
8146 				   ipf_frag_stats(softc->ipf_frag_soft),
8147 				   IPFOBJ_FRAGSTAT);
8148 		break;
8149 
8150 #ifdef	IPFILTER_LOG
8151 	case FIONREAD :
8152 		tmp = ipf_log_bytesused(softc, IPL_LOGIPF);
8153 		error = BCOPYOUT(&tmp, data, sizeof(tmp));
8154 		break;
8155 #endif
8156 
8157 	case SIOCIPFITER :
8158 		SPL_SCHED(s);
8159 		error = ipf_frruleiter(softc, data, uid, ctx);
8160 		SPL_X(s);
8161 		break;
8162 
8163 	case SIOCGENITER :
8164 		SPL_SCHED(s);
8165 		error = ipf_genericiter(softc, data, uid, ctx);
8166 		SPL_X(s);
8167 		break;
8168 
8169 	case SIOCIPFDELTOK :
8170 		error = BCOPYIN(data, &tmp, sizeof(tmp));
8171 		if (error == 0) {
8172 			SPL_SCHED(s);
8173 			error = ipf_token_del(softc, tmp, uid, ctx);
8174 			SPL_X(s);
8175 		}
8176 		break;
8177 
8178 	default :
8179 		IPFERROR(115);
8180 		error = EINVAL;
8181 		break;
8182 	}
8183 
8184 	return (error);
8185 }
8186 
8187 
8188 /* ------------------------------------------------------------------------ */
8189 /* Function:    ipf_decaps                                                  */
8190 /* Returns:     int        - -1 == decapsulation failed, else bit mask of   */
8191 /*                           flags indicating packet filtering decision.    */
8192 /* Parameters:  fin(I)     - pointer to packet information                  */
8193 /*              pass(I)    - IP protocol version to match                   */
8194 /*              l5proto(I) - layer 5 protocol to decode UDP data as.        */
8195 /*                                                                          */
8196 /* This function is called for packets that are wrapt up in other packets,  */
8197 /* for example, an IP packet that is the entire data segment for another IP */
8198 /* packet.  If the basic constraints for this are satisfied, change the     */
8199 /* buffer to point to the start of the inner packet and start processing    */
8200 /* rules belonging to the head group this rule specifies.                   */
8201 /* ------------------------------------------------------------------------ */
8202 u_32_t
8203 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto)
8204 {
8205 	fr_info_t fin2, *fino = NULL;
8206 	int elen, hlen, nh;
8207 	grehdr_t gre;
8208 	ip_t *ip;
8209 	mb_t *m;
8210 
8211 	if ((fin->fin_flx & FI_COALESCE) == 0)
8212 		if (ipf_coalesce(fin) == -1)
8213 			goto cantdecaps;
8214 
8215 	m = fin->fin_m;
8216 	hlen = fin->fin_hlen;
8217 
8218 	switch (fin->fin_p)
8219 	{
8220 	case IPPROTO_UDP :
8221 		/*
8222 		 * In this case, the specific protocol being decapsulated
8223 		 * inside UDP frames comes from the rule.
8224 		 */
8225 		nh = fin->fin_fr->fr_icode;
8226 		break;
8227 
8228 	case IPPROTO_GRE :	/* 47 */
8229 		bcopy(fin->fin_dp, (char *)&gre, sizeof(gre));
8230 		hlen += sizeof(grehdr_t);
8231 		if (gre.gr_R|gre.gr_s)
8232 			goto cantdecaps;
8233 		if (gre.gr_C)
8234 			hlen += 4;
8235 		if (gre.gr_K)
8236 			hlen += 4;
8237 		if (gre.gr_S)
8238 			hlen += 4;
8239 
8240 		nh = IPPROTO_IP;
8241 
8242 		/*
8243 		 * If the routing options flag is set, validate that it is
8244 		 * there and bounce over it.
8245 		 */
8246 #if 0
8247 		/* This is really heavy weight and lots of room for error, */
8248 		/* so for now, put it off and get the simple stuff right.  */
8249 		if (gre.gr_R) {
8250 			u_char off, len, *s;
8251 			u_short af;
8252 			int end;
8253 
8254 			end = 0;
8255 			s = fin->fin_dp;
8256 			s += hlen;
8257 			aplen = fin->fin_plen - hlen;
8258 			while (aplen > 3) {
8259 				af = (s[0] << 8) | s[1];
8260 				off = s[2];
8261 				len = s[3];
8262 				aplen -= 4;
8263 				s += 4;
8264 				if (af == 0 && len == 0) {
8265 					end = 1;
8266 					break;
8267 				}
8268 				if (aplen < len)
8269 					break;
8270 				s += len;
8271 				aplen -= len;
8272 			}
8273 			if (end != 1)
8274 				goto cantdecaps;
8275 			hlen = s - (u_char *)fin->fin_dp;
8276 		}
8277 #endif
8278 		break;
8279 
8280 #ifdef IPPROTO_IPIP
8281 	case IPPROTO_IPIP :	/* 4 */
8282 #endif
8283 		nh = IPPROTO_IP;
8284 		break;
8285 
8286 	default :	/* Includes ESP, AH is special for IPv4 */
8287 		goto cantdecaps;
8288 	}
8289 
8290 	switch (nh)
8291 	{
8292 	case IPPROTO_IP :
8293 	case IPPROTO_IPV6 :
8294 		break;
8295 	default :
8296 		goto cantdecaps;
8297 	}
8298 
8299 	bcopy((char *)fin, (char *)&fin2, sizeof(fin2));
8300 	fino = fin;
8301 	fin = &fin2;
8302 	elen = hlen;
8303 #if SOLARIS && defined(_KERNEL)
8304 	m->b_rptr += elen;
8305 #else
8306 	m->m_data += elen;
8307 	m->m_len -= elen;
8308 #endif
8309 	fin->fin_plen -= elen;
8310 
8311 	ip = (ip_t *)((char *)fin->fin_ip + elen);
8312 
8313 	/*
8314 	 * Make sure we have at least enough data for the network layer
8315 	 * header.
8316 	 */
8317 	if (IP_V(ip) == 4)
8318 		hlen = IP_HL(ip) << 2;
8319 #ifdef USE_INET6
8320 	else if (IP_V(ip) == 6)
8321 		hlen = sizeof(ip6_t);
8322 #endif
8323 	else
8324 		goto cantdecaps2;
8325 
8326 	if (fin->fin_plen < hlen)
8327 		goto cantdecaps2;
8328 
8329 	fin->fin_dp = (char *)ip + hlen;
8330 
8331 	if (IP_V(ip) == 4) {
8332 		/*
8333 		 * Perform IPv4 header checksum validation.
8334 		 */
8335 		if (ipf_cksum((u_short *)ip, hlen))
8336 			goto cantdecaps2;
8337 	}
8338 
8339 	if (ipf_makefrip(hlen, ip, fin) == -1) {
8340 cantdecaps2:
8341 		if (m != NULL) {
8342 #if SOLARIS && defined(_KERNEL)
8343 			m->b_rptr -= elen;
8344 #else
8345 			m->m_data -= elen;
8346 			m->m_len += elen;
8347 #endif
8348 		}
8349 cantdecaps:
8350 		DT1(frb_decapfrip, fr_info_t *, fin);
8351 		pass &= ~FR_CMDMASK;
8352 		pass |= FR_BLOCK|FR_QUICK;
8353 		fin->fin_reason = FRB_DECAPFRIP;
8354 		return (-1);
8355 	}
8356 
8357 	pass = ipf_scanlist(fin, pass);
8358 
8359 	/*
8360 	 * Copy the packet filter "result" fields out of the fr_info_t struct
8361 	 * that is local to the decapsulation processing and back into the
8362 	 * one we were called with.
8363 	 */
8364 	fino->fin_flx = fin->fin_flx;
8365 	fino->fin_rev = fin->fin_rev;
8366 	fino->fin_icode = fin->fin_icode;
8367 	fino->fin_rule = fin->fin_rule;
8368 	(void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN);
8369 	fino->fin_fr = fin->fin_fr;
8370 	fino->fin_error = fin->fin_error;
8371 	fino->fin_mp = fin->fin_mp;
8372 	fino->fin_m = fin->fin_m;
8373 	m = fin->fin_m;
8374 	if (m != NULL) {
8375 #if SOLARIS && defined(_KERNEL)
8376 		m->b_rptr -= elen;
8377 #else
8378 		m->m_data -= elen;
8379 		m->m_len += elen;
8380 #endif
8381 	}
8382 	return (pass);
8383 }
8384 
8385 
8386 /* ------------------------------------------------------------------------ */
8387 /* Function:    ipf_matcharray_load                                         */
8388 /* Returns:     int         - 0 = success, else error                       */
8389 /* Parameters:  softc(I)    - pointer to soft context main structure        */
8390 /*              data(I)     - pointer to ioctl data                         */
8391 /*              objp(I)     - ipfobj_t structure to load data into          */
8392 /*              arrayptr(I) - pointer to location to store array pointer    */
8393 /*                                                                          */
8394 /* This function loads in a mathing array through the ipfobj_t struct that  */
8395 /* describes it.  Sanity checking and array size limitations are enforced   */
8396 /* in this function to prevent userspace from trying to load in something   */
8397 /* that is insanely big.  Once the size of the array is known, the memory   */
8398 /* required is malloc'd and returned through changing *arrayptr.  The       */
8399 /* contents of the array are verified before returning.  Only in the event  */
8400 /* of a successful call is the caller required to free up the malloc area.  */
8401 /* ------------------------------------------------------------------------ */
8402 int
8403 ipf_matcharray_load(ipf_main_softc_t *softc, caddr_t data, ipfobj_t *objp,
8404 	int **arrayptr)
8405 {
8406 	int arraysize, *array, error;
8407 
8408 	*arrayptr = NULL;
8409 
8410 	error = BCOPYIN(data, objp, sizeof(*objp));
8411 	if (error != 0) {
8412 		IPFERROR(116);
8413 		return (EFAULT);
8414 	}
8415 
8416 	if (objp->ipfo_type != IPFOBJ_IPFEXPR) {
8417 		IPFERROR(117);
8418 		return (EINVAL);
8419 	}
8420 
8421 	if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) ||
8422 	    (objp->ipfo_size > 1024)) {
8423 		IPFERROR(118);
8424 		return (EINVAL);
8425 	}
8426 
8427 	arraysize = objp->ipfo_size * sizeof(*array);
8428 	KMALLOCS(array, int *, arraysize);
8429 	if (array == NULL) {
8430 		IPFERROR(119);
8431 		return (ENOMEM);
8432 	}
8433 
8434 	error = COPYIN(objp->ipfo_ptr, array, arraysize);
8435 	if (error != 0) {
8436 		KFREES(array, arraysize);
8437 		IPFERROR(120);
8438 		return (EFAULT);
8439 	}
8440 
8441 	if (ipf_matcharray_verify(array, arraysize) != 0) {
8442 		KFREES(array, arraysize);
8443 		IPFERROR(121);
8444 		return (EINVAL);
8445 	}
8446 
8447 	*arrayptr = array;
8448 	return (0);
8449 }
8450 
8451 
8452 /* ------------------------------------------------------------------------ */
8453 /* Function:    ipf_matcharray_verify                                       */
8454 /* Returns:     Nil                                                         */
8455 /* Parameters:  array(I)     - pointer to matching array                    */
8456 /*              arraysize(I) - number of elements in the array              */
8457 /*                                                                          */
8458 /* Verify the contents of a matching array by stepping through each element */
8459 /* in it.  The actual commands in the array are not verified for            */
8460 /* correctness, only that all of the sizes are correctly within limits.     */
8461 /* ------------------------------------------------------------------------ */
8462 int
8463 ipf_matcharray_verify(int *array, int arraysize)
8464 {
8465 	int i, nelem, maxidx;
8466 	ipfexp_t *e;
8467 
8468 	nelem = arraysize / sizeof(*array);
8469 
8470 	/*
8471 	 * Currently, it makes no sense to have an array less than 6
8472 	 * elements long - the initial size at the from, a single operation
8473 	 * (minimum 4 in length) and a trailer, for a total of 6.
8474 	 */
8475 	if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) {
8476 		return (-1);
8477 	}
8478 
8479 	/*
8480 	 * Verify the size of data pointed to by array with how long
8481 	 * the array claims to be itself.
8482 	 */
8483 	if (array[0] * sizeof(*array) != arraysize) {
8484 		return (-1);
8485 	}
8486 
8487 	maxidx = nelem - 1;
8488 	/*
8489 	 * The last opcode in this array should be an IPF_EXP_END.
8490 	 */
8491 	if (array[maxidx] != IPF_EXP_END) {
8492 		return (-1);
8493 	}
8494 
8495 	for (i = 1; i < maxidx; ) {
8496 		e = (ipfexp_t *)(array + i);
8497 
8498 		/*
8499 		 * The length of the bits to check must be at least 1
8500 		 * (or else there is nothing to comapre with!) and it
8501 		 * cannot exceed the length of the data present.
8502 		 */
8503 		if ((e->ipfe_size < 1 ) ||
8504 		    (e->ipfe_size + i > maxidx)) {
8505 			return (-1);
8506 		}
8507 		i += e->ipfe_size;
8508 	}
8509 	return (0);
8510 }
8511 
8512 
8513 /* ------------------------------------------------------------------------ */
8514 /* Function:    ipf_fr_matcharray                                           */
8515 /* Returns:     int      - 0 = match failed, else positive match            */
8516 /* Parameters:  fin(I)   - pointer to packet information                    */
8517 /*              array(I) - pointer to matching array                        */
8518 /*                                                                          */
8519 /* This function is used to apply a matching array against a packet and     */
8520 /* return an indication of whether or not the packet successfully matches   */
8521 /* all of the commands in it.                                               */
8522 /* ------------------------------------------------------------------------ */
8523 static int
8524 ipf_fr_matcharray(fr_info_t *fin, int *array)
8525 {
8526 	int i, n, *x, rv, p;
8527 	ipfexp_t *e;
8528 
8529 	rv = 0;
8530 	n = array[0];
8531 	x = array + 1;
8532 
8533 	for (; n > 0; x += 3 + x[3], rv = 0) {
8534 		e = (ipfexp_t *)x;
8535 		if (e->ipfe_cmd == IPF_EXP_END)
8536 			break;
8537 		n -= e->ipfe_size;
8538 
8539 		/*
8540 		 * The upper 16 bits currently store the protocol value.
8541 		 * This is currently used with TCP and UDP port compares and
8542 		 * allows "tcp.port = 80" without requiring an explicit
8543 		 " "ip.pr = tcp" first.
8544 		 */
8545 		p = e->ipfe_cmd >> 16;
8546 		if ((p != 0) && (p != fin->fin_p))
8547 			break;
8548 
8549 		switch (e->ipfe_cmd)
8550 		{
8551 		case IPF_EXP_IP_PR :
8552 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8553 				rv |= (fin->fin_p == e->ipfe_arg0[i]);
8554 			}
8555 			break;
8556 
8557 		case IPF_EXP_IP_SRCADDR :
8558 			if (fin->fin_v != 4)
8559 				break;
8560 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8561 				rv |= ((fin->fin_saddr &
8562 					e->ipfe_arg0[i * 2 + 1]) ==
8563 				       e->ipfe_arg0[i * 2]);
8564 			}
8565 			break;
8566 
8567 		case IPF_EXP_IP_DSTADDR :
8568 			if (fin->fin_v != 4)
8569 				break;
8570 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8571 				rv |= ((fin->fin_daddr &
8572 					e->ipfe_arg0[i * 2 + 1]) ==
8573 				       e->ipfe_arg0[i * 2]);
8574 			}
8575 			break;
8576 
8577 		case IPF_EXP_IP_ADDR :
8578 			if (fin->fin_v != 4)
8579 				break;
8580 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8581 				rv |= ((fin->fin_saddr &
8582 					e->ipfe_arg0[i * 2 + 1]) ==
8583 				       e->ipfe_arg0[i * 2]) ||
8584 				      ((fin->fin_daddr &
8585 					e->ipfe_arg0[i * 2 + 1]) ==
8586 				       e->ipfe_arg0[i * 2]);
8587 			}
8588 			break;
8589 
8590 #ifdef USE_INET6
8591 		case IPF_EXP_IP6_SRCADDR :
8592 			if (fin->fin_v != 6)
8593 				break;
8594 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8595 				rv |= IP6_MASKEQ(&fin->fin_src6,
8596 						 &e->ipfe_arg0[i * 8 + 4],
8597 						 &e->ipfe_arg0[i * 8]);
8598 			}
8599 			break;
8600 
8601 		case IPF_EXP_IP6_DSTADDR :
8602 			if (fin->fin_v != 6)
8603 				break;
8604 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8605 				rv |= IP6_MASKEQ(&fin->fin_dst6,
8606 						 &e->ipfe_arg0[i * 8 + 4],
8607 						 &e->ipfe_arg0[i * 8]);
8608 			}
8609 			break;
8610 
8611 		case IPF_EXP_IP6_ADDR :
8612 			if (fin->fin_v != 6)
8613 				break;
8614 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8615 				rv |= IP6_MASKEQ(&fin->fin_src6,
8616 						 &e->ipfe_arg0[i * 8 + 4],
8617 						 &e->ipfe_arg0[i * 8]) ||
8618 				      IP6_MASKEQ(&fin->fin_dst6,
8619 						 &e->ipfe_arg0[i * 8 + 4],
8620 						 &e->ipfe_arg0[i * 8]);
8621 			}
8622 			break;
8623 #endif
8624 
8625 		case IPF_EXP_UDP_PORT :
8626 		case IPF_EXP_TCP_PORT :
8627 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8628 				rv |= (fin->fin_sport == e->ipfe_arg0[i]) ||
8629 				      (fin->fin_dport == e->ipfe_arg0[i]);
8630 			}
8631 			break;
8632 
8633 		case IPF_EXP_UDP_SPORT :
8634 		case IPF_EXP_TCP_SPORT :
8635 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8636 				rv |= (fin->fin_sport == e->ipfe_arg0[i]);
8637 			}
8638 			break;
8639 
8640 		case IPF_EXP_UDP_DPORT :
8641 		case IPF_EXP_TCP_DPORT :
8642 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8643 				rv |= (fin->fin_dport == e->ipfe_arg0[i]);
8644 			}
8645 			break;
8646 
8647 		case IPF_EXP_TCP_FLAGS :
8648 			for (i = 0; !rv && i < e->ipfe_narg; i++) {
8649 				rv |= ((fin->fin_tcpf &
8650 					e->ipfe_arg0[i * 2 + 1]) ==
8651 				       e->ipfe_arg0[i * 2]);
8652 			}
8653 			break;
8654 		}
8655 		rv ^= e->ipfe_not;
8656 
8657 		if (rv == 0)
8658 			break;
8659 	}
8660 
8661 	return (rv);
8662 }
8663 
8664 
8665 /* ------------------------------------------------------------------------ */
8666 /* Function:    ipf_queueflush                                              */
8667 /* Returns:     int - number of entries flushed (0 = none)                  */
8668 /* Parameters:  softc(I)    - pointer to soft context main structure        */
8669 /*              deletefn(I) - function to call to delete entry              */
8670 /*              ipfqs(I)    - top of the list of ipf internal queues        */
8671 /*              userqs(I)   - top of the list of user defined timeouts      */
8672 /*                                                                          */
8673 /* This fucntion gets called when the state/NAT hash tables fill up and we  */
8674 /* need to try a bit harder to free up some space.  The algorithm used here */
8675 /* split into two parts but both halves have the same goal: to reduce the   */
8676 /* number of connections considered to be "active" to the low watermark.    */
8677 /* There are two steps in doing this:                                       */
8678 /* 1) Remove any TCP connections that are already considered to be "closed" */
8679 /*    but have not yet been removed from the state table.  The two states   */
8680 /*    TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect       */
8681 /*    candidates for this style of removal.  If freeing up entries in       */
8682 /*    CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark,   */
8683 /*    we do not go on to step 2.                                            */
8684 /*                                                                          */
8685 /* 2) Look for the oldest entries on each timeout queue and free them if    */
8686 /*    they are within the given window we are considering.  Where the       */
8687 /*    window starts and the steps taken to increase its size depend upon    */
8688 /*    how long ipf has been running (ipf_ticks.)  Anything modified in the  */
8689 /*    last 30 seconds is not touched.                                       */
8690 /*                                              touched                     */
8691 /*         die     ipf_ticks  30*1.5    1800*1.5   |  43200*1.5             */
8692 /*           |          |        |           |     |     |                  */
8693 /* future <--+----------+--------+-----------+-----+-----+-----------> past */
8694 /*                     now        \_int=30s_/ \_int=1hr_/ \_int=12hr        */
8695 /*                                                                          */
8696 /* Points to note:                                                          */
8697 /* - tqe_die is the time, in the future, when entries die.                  */
8698 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */
8699 /*   ticks.                                                                 */
8700 /* - tqe_touched is when the entry was last used by NAT/state               */
8701 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be    */
8702 /*   ipf_ticks any given timeout queue and vice versa.                      */
8703 /* - both tqe_die and tqe_touched increase over time                        */
8704 /* - timeout queues are sorted with the highest value of tqe_die at the     */
8705 /*   bottom and therefore the smallest values of each are at the top        */
8706 /* - the pointer passed in as ipfqs should point to an array of timeout     */
8707 /*   queues representing each of the TCP states                             */
8708 /*                                                                          */
8709 /* We start by setting up a maximum range to scan for things to move of     */
8710 /* iend (newest) to istart (oldest) in chunks of "interval".  If nothing is */
8711 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */
8712 /* we start again with a new value for "iend" and "istart".  This is        */
8713 /* continued until we either finish the scan of 30 second intervals or the  */
8714 /* low water mark is reached.                                               */
8715 /* ------------------------------------------------------------------------ */
8716 int
8717 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn,
8718 	ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low)
8719 {
8720 	u_long interval, istart, iend;
8721 	ipftq_t *ifq, *ifqnext;
8722 	ipftqent_t *tqe, *tqn;
8723 	int removed = 0;
8724 
8725 	for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) {
8726 		tqn = tqe->tqe_next;
8727 		if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8728 			removed++;
8729 	}
8730 	if ((*activep * 100 / size) > low) {
8731 		for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head;
8732 		     ((tqe = tqn) != NULL); ) {
8733 			tqn = tqe->tqe_next;
8734 			if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8735 				removed++;
8736 		}
8737 	}
8738 
8739 	if ((*activep * 100 / size) <= low) {
8740 		return (removed);
8741 	}
8742 
8743 	/*
8744 	 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
8745 	 *       used then the operations are upgraded to floating point
8746 	 *       and kernels don't like floating point...
8747 	 */
8748 	if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
8749 		istart = IPF_TTLVAL(86400 * 4);
8750 		interval = IPF_TTLVAL(43200);
8751 	} else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
8752 		istart = IPF_TTLVAL(43200);
8753 		interval = IPF_TTLVAL(1800);
8754 	} else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) {
8755 		istart = IPF_TTLVAL(1800);
8756 		interval = IPF_TTLVAL(30);
8757 	} else {
8758 		return (0);
8759 	}
8760 	if (istart > softc->ipf_ticks) {
8761 		if (softc->ipf_ticks - interval < interval)
8762 			istart = interval;
8763 		else
8764 			istart = (softc->ipf_ticks / interval) * interval;
8765 	}
8766 
8767 	iend = softc->ipf_ticks - interval;
8768 
8769 	while ((*activep * 100 / size) > low) {
8770 		u_long try;
8771 
8772 		try = softc->ipf_ticks - istart;
8773 
8774 		for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
8775 			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
8776 				if (try < tqe->tqe_touched)
8777 					break;
8778 				tqn = tqe->tqe_next;
8779 				if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8780 					removed++;
8781 			}
8782 		}
8783 
8784 		for (ifq = userqs; ifq != NULL; ifq = ifqnext) {
8785 			ifqnext = ifq->ifq_next;
8786 
8787 			for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
8788 				if (try < tqe->tqe_touched)
8789 					break;
8790 				tqn = tqe->tqe_next;
8791 				if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8792 					removed++;
8793 			}
8794 		}
8795 
8796 		if (try >= iend) {
8797 			if (interval == IPF_TTLVAL(43200)) {
8798 				interval = IPF_TTLVAL(1800);
8799 			} else if (interval == IPF_TTLVAL(1800)) {
8800 				interval = IPF_TTLVAL(30);
8801 			} else {
8802 				break;
8803 			}
8804 			if (interval >= softc->ipf_ticks)
8805 				break;
8806 
8807 			iend = softc->ipf_ticks - interval;
8808 		}
8809 		istart -= interval;
8810 	}
8811 
8812 	return (removed);
8813 }
8814 
8815 
8816 /* ------------------------------------------------------------------------ */
8817 /* Function:    ipf_deliverlocal                                            */
8818 /* Returns:     int - 1 = local address, 0 = non-local address              */
8819 /* Parameters:  softc(I)     - pointer to soft context main structure       */
8820 /*              ipversion(I) - IP protocol version (4 or 6)                 */
8821 /*              ifp(I)       - network interface pointer                    */
8822 /*              ipaddr(I)    - IPv4/6 destination address                   */
8823 /*                                                                          */
8824 /* This fucntion is used to determine in the address "ipaddr" belongs to    */
8825 /* the network interface represented by ifp.                                */
8826 /* ------------------------------------------------------------------------ */
8827 int
8828 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp,
8829 	i6addr_t *ipaddr)
8830 {
8831 	i6addr_t addr;
8832 	int islocal = 0;
8833 
8834 	if (ipversion == 4) {
8835 		if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) {
8836 			if (addr.in4.s_addr == ipaddr->in4.s_addr)
8837 				islocal = 1;
8838 		}
8839 
8840 #ifdef USE_INET6
8841 	} else if (ipversion == 6) {
8842 		if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) {
8843 			if (IP6_EQ(&addr, ipaddr))
8844 				islocal = 1;
8845 		}
8846 #endif
8847 	}
8848 
8849 	return (islocal);
8850 }
8851 
8852 
8853 /* ------------------------------------------------------------------------ */
8854 /* Function:    ipf_settimeout                                              */
8855 /* Returns:     int - 0 = success, -1 = failure                             */
8856 /* Parameters:  softc(I) - pointer to soft context main structure           */
8857 /*              t(I)     - pointer to tuneable array entry                  */
8858 /*              p(I)     - pointer to values passed in to apply             */
8859 /*                                                                          */
8860 /* This function is called to set the timeout values for each distinct      */
8861 /* queue timeout that is available.  When called, it calls into both the    */
8862 /* state and NAT code, telling them to update their timeout queues.         */
8863 /* ------------------------------------------------------------------------ */
8864 static int
8865 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t,
8866 	ipftuneval_t *p)
8867 {
8868 
8869 	/*
8870 	 * ipf_interror should be set by the functions called here, not
8871 	 * by this function - it's just a middle man.
8872 	 */
8873 	if (ipf_state_settimeout(softc, t, p) == -1)
8874 		return (-1);
8875 	if (ipf_nat_settimeout(softc, t, p) == -1)
8876 		return (-1);
8877 	return (0);
8878 }
8879 
8880 
8881 /* ------------------------------------------------------------------------ */
8882 /* Function:    ipf_apply_timeout                                           */
8883 /* Returns:     int - 0 = success, -1 = failure                             */
8884 /* Parameters:  head(I)    - pointer to tuneable array entry                */
8885 /*              seconds(I) - pointer to values passed in to apply           */
8886 /*                                                                          */
8887 /* This function applies a timeout of "seconds" to the timeout queue that   */
8888 /* is pointed to by "head".  All entries on this list have an expiration    */
8889 /* set to be the current tick value of ipf plus the ttl.  Given that this   */
8890 /* function should only be called when the delta is non-zero, the task is   */
8891 /* to walk the entire list and apply the change.  The sort order will not   */
8892 /* change.  The only catch is that this is O(n) across the list, so if the  */
8893 /* queue has lots of entries (10s of thousands or 100s of thousands), it    */
8894 /* could take a relatively long time to work through them all.              */
8895 /* ------------------------------------------------------------------------ */
8896 void
8897 ipf_apply_timeout(ipftq_t *head, u_int seconds)
8898 {
8899 	u_int oldtimeout, newtimeout;
8900 	ipftqent_t *tqe;
8901 	int delta;
8902 
8903 	MUTEX_ENTER(&head->ifq_lock);
8904 	oldtimeout = head->ifq_ttl;
8905 	newtimeout = IPF_TTLVAL(seconds);
8906 	delta = oldtimeout - newtimeout;
8907 
8908 	head->ifq_ttl = newtimeout;
8909 
8910 	for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) {
8911 		tqe->tqe_die += delta;
8912 	}
8913 	MUTEX_EXIT(&head->ifq_lock);
8914 }
8915 
8916 
8917 /* ------------------------------------------------------------------------ */
8918 /* Function:   ipf_settimeout_tcp                                           */
8919 /* Returns:    int - 0 = successfully applied, -1 = failed                  */
8920 /* Parameters: t(I)   - pointer to tuneable to change                       */
8921 /*             p(I)   - pointer to new timeout information                  */
8922 /*             tab(I) - pointer to table of TCP queues                      */
8923 /*                                                                          */
8924 /* This function applies the new timeout (p) to the TCP tunable (t) and     */
8925 /* updates all of the entries on the relevant timeout queue by calling      */
8926 /* ipf_apply_timeout().                                                     */
8927 /* ------------------------------------------------------------------------ */
8928 int
8929 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab)
8930 {
8931 	if (!strcmp(t->ipft_name, "tcp_idle_timeout") ||
8932 	    !strcmp(t->ipft_name, "tcp_established")) {
8933 		ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int);
8934 	} else if (!strcmp(t->ipft_name, "tcp_close_wait")) {
8935 		ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int);
8936 	} else if (!strcmp(t->ipft_name, "tcp_last_ack")) {
8937 		ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int);
8938 	} else if (!strcmp(t->ipft_name, "tcp_timeout")) {
8939 		ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
8940 		ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
8941 		ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
8942 	} else if (!strcmp(t->ipft_name, "tcp_listen")) {
8943 		ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
8944 	} else if (!strcmp(t->ipft_name, "tcp_half_established")) {
8945 		ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
8946 	} else if (!strcmp(t->ipft_name, "tcp_closing")) {
8947 		ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
8948 	} else if (!strcmp(t->ipft_name, "tcp_syn_received")) {
8949 		ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int);
8950 	} else if (!strcmp(t->ipft_name, "tcp_syn_sent")) {
8951 		ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int);
8952 	} else if (!strcmp(t->ipft_name, "tcp_closed")) {
8953 		ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
8954 	} else if (!strcmp(t->ipft_name, "tcp_half_closed")) {
8955 		ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
8956 	} else if (!strcmp(t->ipft_name, "tcp_time_wait")) {
8957 		ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int);
8958 	} else {
8959 		/*
8960 		 * ipf_interror isn't set here because it should be set
8961 		 * by whatever called this function.
8962 		 */
8963 		return (-1);
8964 	}
8965 	return (0);
8966 }
8967 
8968 
8969 /* ------------------------------------------------------------------------ */
8970 /* Function:   ipf_main_soft_create                                         */
8971 /* Returns:    NULL = failure, else success                                 */
8972 /* Parameters: arg(I) - pointer to soft context structure if already allocd */
8973 /*                                                                          */
8974 /* Create the foundation soft context structure. In circumstances where it  */
8975 /* is not required to dynamically allocate the context, a pointer can be    */
8976 /* passed in (rather than NULL) to a structure to be initialised.           */
8977 /* The main thing of interest is that a number of locks are initialised     */
8978 /* here instead of in the where might be expected - in the relevant create  */
8979 /* function elsewhere.  This is done because the current locking design has */
8980 /* some areas where these locks are used outside of their module.           */
8981 /* Possibly the most important exercise that is done here is setting of all */
8982 /* the timeout values, allowing them to be changed before init().           */
8983 /* ------------------------------------------------------------------------ */
8984 void *
8985 ipf_main_soft_create(void *arg)
8986 {
8987 	ipf_main_softc_t *softc;
8988 
8989 	if (arg == NULL) {
8990 		KMALLOC(softc, ipf_main_softc_t *);
8991 		if (softc == NULL)
8992 			return (NULL);
8993 	} else {
8994 		softc = arg;
8995 	}
8996 
8997 	bzero((char *)softc, sizeof(*softc));
8998 
8999 	/*
9000 	 * This serves as a flag as to whether or not the softc should be
9001 	 * free'd when _destroy is called.
9002 	 */
9003 	softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0;
9004 
9005 	softc->ipf_tuners = ipf_tune_array_copy(softc,
9006 						sizeof(ipf_main_tuneables),
9007 						ipf_main_tuneables);
9008 	if (softc->ipf_tuners == NULL) {
9009 		ipf_main_soft_destroy(softc);
9010 		return (NULL);
9011 	}
9012 
9013 	MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex");
9014 	MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock");
9015 	RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex");
9016 	RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock");
9017 	RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock");
9018 	RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock");
9019 	RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock");
9020 	RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock");
9021 	RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock");
9022 
9023 	softc->ipf_token_head = NULL;
9024 	softc->ipf_token_tail = &softc->ipf_token_head;
9025 
9026 	softc->ipf_tcpidletimeout = FIVE_DAYS;
9027 	softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL);
9028 	softc->ipf_tcplastack = IPF_TTLVAL(30);
9029 	softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL);
9030 	softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL);
9031 	softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL);
9032 	softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL);
9033 	softc->ipf_tcpclosed = IPF_TTLVAL(30);
9034 	softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600);
9035 	softc->ipf_udptimeout = IPF_TTLVAL(120);
9036 	softc->ipf_udpacktimeout = IPF_TTLVAL(12);
9037 	softc->ipf_icmptimeout = IPF_TTLVAL(60);
9038 	softc->ipf_icmpacktimeout = IPF_TTLVAL(6);
9039 	softc->ipf_iptimeout = IPF_TTLVAL(60);
9040 
9041 #if defined(IPFILTER_DEFAULT_BLOCK)
9042 	softc->ipf_pass = FR_BLOCK|FR_NOMATCH;
9043 #else
9044 	softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
9045 #endif
9046 	softc->ipf_minttl = 4;
9047 	softc->ipf_icmpminfragmtu = 68;
9048 	softc->ipf_flags = IPF_LOGGING;
9049 
9050 #ifdef LARGE_NAT
9051 	softc->ipf_large_nat = 1;
9052 #endif
9053 	ipf_fbsd_kenv_get(softc);
9054 
9055 	return (softc);
9056 }
9057 
9058 /* ------------------------------------------------------------------------ */
9059 /* Function:   ipf_main_soft_init                                           */
9060 /* Returns:    0 = success, -1 = failure                                    */
9061 /* Parameters: softc(I) - pointer to soft context main structure            */
9062 /*                                                                          */
9063 /* A null-op function that exists as a placeholder so that the flow in      */
9064 /* other functions is obvious.                                              */
9065 /* ------------------------------------------------------------------------ */
9066 /*ARGSUSED*/
9067 int
9068 ipf_main_soft_init(ipf_main_softc_t *softc)
9069 {
9070 	return (0);
9071 }
9072 
9073 
9074 /* ------------------------------------------------------------------------ */
9075 /* Function:   ipf_main_soft_destroy                                        */
9076 /* Returns:    void                                                         */
9077 /* Parameters: softc(I) - pointer to soft context main structure            */
9078 /*                                                                          */
9079 /* Undo everything that we did in ipf_main_soft_create.                     */
9080 /*                                                                          */
9081 /* The most important check that needs to be made here is whether or not    */
9082 /* the structure was allocated by ipf_main_soft_create() by checking what   */
9083 /* value is stored in ipf_dynamic_main.                                     */
9084 /* ------------------------------------------------------------------------ */
9085 /*ARGSUSED*/
9086 void
9087 ipf_main_soft_destroy(ipf_main_softc_t *softc)
9088 {
9089 
9090 	RW_DESTROY(&softc->ipf_frag);
9091 	RW_DESTROY(&softc->ipf_poolrw);
9092 	RW_DESTROY(&softc->ipf_nat);
9093 	RW_DESTROY(&softc->ipf_state);
9094 	RW_DESTROY(&softc->ipf_tokens);
9095 	RW_DESTROY(&softc->ipf_mutex);
9096 	RW_DESTROY(&softc->ipf_global);
9097 	MUTEX_DESTROY(&softc->ipf_timeoutlock);
9098 	MUTEX_DESTROY(&softc->ipf_rw);
9099 
9100 	if (softc->ipf_tuners != NULL) {
9101 		KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables));
9102 	}
9103 	if (softc->ipf_dynamic_softc == 1) {
9104 		KFREE(softc);
9105 	}
9106 }
9107 
9108 
9109 /* ------------------------------------------------------------------------ */
9110 /* Function:   ipf_main_soft_fini                                           */
9111 /* Returns:    0 = success, -1 = failure                                    */
9112 /* Parameters: softc(I) - pointer to soft context main structure            */
9113 /*                                                                          */
9114 /* Clean out the rules which have been added since _init was last called,   */
9115 /* the only dynamic part of the mainline.                                   */
9116 /* ------------------------------------------------------------------------ */
9117 int
9118 ipf_main_soft_fini(ipf_main_softc_t *softc)
9119 {
9120 	(void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
9121 	(void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
9122 	(void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
9123 	(void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE);
9124 
9125 	return (0);
9126 }
9127 
9128 
9129 /* ------------------------------------------------------------------------ */
9130 /* Function:   ipf_main_load                                                */
9131 /* Returns:    0 = success, -1 = failure                                    */
9132 /* Parameters: none                                                         */
9133 /*                                                                          */
9134 /* Handle global initialisation that needs to be done for the base part of  */
9135 /* IPFilter. At present this just amounts to initialising some ICMP lookup  */
9136 /* arrays that get used by the state/NAT code.                              */
9137 /* ------------------------------------------------------------------------ */
9138 int
9139 ipf_main_load(void)
9140 {
9141 	int i;
9142 
9143 	/* fill icmp reply type table */
9144 	for (i = 0; i <= ICMP_MAXTYPE; i++)
9145 		icmpreplytype4[i] = -1;
9146 	icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
9147 	icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
9148 	icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
9149 	icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
9150 
9151 #ifdef  USE_INET6
9152 	/* fill icmp reply type table */
9153 	for (i = 0; i <= ICMP6_MAXTYPE; i++)
9154 		icmpreplytype6[i] = -1;
9155 	icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
9156 	icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
9157 	icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
9158 	icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
9159 	icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
9160 #endif
9161 
9162 	return (0);
9163 }
9164 
9165 
9166 /* ------------------------------------------------------------------------ */
9167 /* Function:   ipf_main_unload                                              */
9168 /* Returns:    0 = success, -1 = failure                                    */
9169 /* Parameters: none                                                         */
9170 /*                                                                          */
9171 /* A null-op function that exists as a placeholder so that the flow in      */
9172 /* other functions is obvious.                                              */
9173 /* ------------------------------------------------------------------------ */
9174 int
9175 ipf_main_unload(void)
9176 {
9177 	return (0);
9178 }
9179 
9180 
9181 /* ------------------------------------------------------------------------ */
9182 /* Function:   ipf_load_all                                                 */
9183 /* Returns:    0 = success, -1 = failure                                    */
9184 /* Parameters: none                                                         */
9185 /*                                                                          */
9186 /* Work through all of the subsystems inside IPFilter and call the load     */
9187 /* function for each in an order that won't lead to a crash :)              */
9188 /* ------------------------------------------------------------------------ */
9189 int
9190 ipf_load_all(void)
9191 {
9192 	if (ipf_main_load() == -1)
9193 		return (-1);
9194 
9195 	if (ipf_state_main_load() == -1)
9196 		return (-1);
9197 
9198 	if (ipf_nat_main_load() == -1)
9199 		return (-1);
9200 
9201 	if (ipf_frag_main_load() == -1)
9202 		return (-1);
9203 
9204 	if (ipf_auth_main_load() == -1)
9205 		return (-1);
9206 
9207 	if (ipf_proxy_main_load() == -1)
9208 		return (-1);
9209 
9210 	return (0);
9211 }
9212 
9213 
9214 /* ------------------------------------------------------------------------ */
9215 /* Function:   ipf_unload_all                                               */
9216 /* Returns:    0 = success, -1 = failure                                    */
9217 /* Parameters: none                                                         */
9218 /*                                                                          */
9219 /* Work through all of the subsystems inside IPFilter and call the unload   */
9220 /* function for each in an order that won't lead to a crash :)              */
9221 /* ------------------------------------------------------------------------ */
9222 int
9223 ipf_unload_all(void)
9224 {
9225 	if (ipf_proxy_main_unload() == -1)
9226 		return (-1);
9227 
9228 	if (ipf_auth_main_unload() == -1)
9229 		return (-1);
9230 
9231 	if (ipf_frag_main_unload() == -1)
9232 		return (-1);
9233 
9234 	if (ipf_nat_main_unload() == -1)
9235 		return (-1);
9236 
9237 	if (ipf_state_main_unload() == -1)
9238 		return (-1);
9239 
9240 	if (ipf_main_unload() == -1)
9241 		return (-1);
9242 
9243 	return (0);
9244 }
9245 
9246 
9247 /* ------------------------------------------------------------------------ */
9248 /* Function:   ipf_create_all                                               */
9249 /* Returns:    NULL = failure, else success                                 */
9250 /* Parameters: arg(I) - pointer to soft context main structure              */
9251 /*                                                                          */
9252 /* Work through all of the subsystems inside IPFilter and call the create   */
9253 /* function for each in an order that won't lead to a crash :)              */
9254 /* ------------------------------------------------------------------------ */
9255 ipf_main_softc_t *
9256 ipf_create_all(void *arg)
9257 {
9258 	ipf_main_softc_t *softc;
9259 
9260 	softc = ipf_main_soft_create(arg);
9261 	if (softc == NULL)
9262 		return (NULL);
9263 
9264 #ifdef IPFILTER_LOG
9265 	softc->ipf_log_soft = ipf_log_soft_create(softc);
9266 	if (softc->ipf_log_soft == NULL) {
9267 		ipf_destroy_all(softc);
9268 		return (NULL);
9269 	}
9270 #endif
9271 
9272 	softc->ipf_lookup_soft = ipf_lookup_soft_create(softc);
9273 	if (softc->ipf_lookup_soft == NULL) {
9274 		ipf_destroy_all(softc);
9275 		return (NULL);
9276 	}
9277 
9278 	softc->ipf_sync_soft = ipf_sync_soft_create(softc);
9279 	if (softc->ipf_sync_soft == NULL) {
9280 		ipf_destroy_all(softc);
9281 		return (NULL);
9282 	}
9283 
9284 	softc->ipf_state_soft = ipf_state_soft_create(softc);
9285 	if (softc->ipf_state_soft == NULL) {
9286 		ipf_destroy_all(softc);
9287 		return (NULL);
9288 	}
9289 
9290 	softc->ipf_nat_soft = ipf_nat_soft_create(softc);
9291 	if (softc->ipf_nat_soft == NULL) {
9292 		ipf_destroy_all(softc);
9293 		return (NULL);
9294 	}
9295 
9296 	softc->ipf_frag_soft = ipf_frag_soft_create(softc);
9297 	if (softc->ipf_frag_soft == NULL) {
9298 		ipf_destroy_all(softc);
9299 		return (NULL);
9300 	}
9301 
9302 	softc->ipf_auth_soft = ipf_auth_soft_create(softc);
9303 	if (softc->ipf_auth_soft == NULL) {
9304 		ipf_destroy_all(softc);
9305 		return (NULL);
9306 	}
9307 
9308 	softc->ipf_proxy_soft = ipf_proxy_soft_create(softc);
9309 	if (softc->ipf_proxy_soft == NULL) {
9310 		ipf_destroy_all(softc);
9311 		return (NULL);
9312 	}
9313 
9314 	return (softc);
9315 }
9316 
9317 
9318 /* ------------------------------------------------------------------------ */
9319 /* Function:   ipf_destroy_all                                              */
9320 /* Returns:    void                                                         */
9321 /* Parameters: softc(I) - pointer to soft context main structure            */
9322 /*                                                                          */
9323 /* Work through all of the subsystems inside IPFilter and call the destroy  */
9324 /* function for each in an order that won't lead to a crash :)              */
9325 /*                                                                          */
9326 /* Every one of these functions is expected to succeed, so there is no      */
9327 /* checking of return values.                                               */
9328 /* ------------------------------------------------------------------------ */
9329 void
9330 ipf_destroy_all(ipf_main_softc_t *softc)
9331 {
9332 
9333 	if (softc->ipf_state_soft != NULL) {
9334 		ipf_state_soft_destroy(softc, softc->ipf_state_soft);
9335 		softc->ipf_state_soft = NULL;
9336 	}
9337 
9338 	if (softc->ipf_nat_soft != NULL) {
9339 		ipf_nat_soft_destroy(softc, softc->ipf_nat_soft);
9340 		softc->ipf_nat_soft = NULL;
9341 	}
9342 
9343 	if (softc->ipf_frag_soft != NULL) {
9344 		ipf_frag_soft_destroy(softc, softc->ipf_frag_soft);
9345 		softc->ipf_frag_soft = NULL;
9346 	}
9347 
9348 	if (softc->ipf_auth_soft != NULL) {
9349 		ipf_auth_soft_destroy(softc, softc->ipf_auth_soft);
9350 		softc->ipf_auth_soft = NULL;
9351 	}
9352 
9353 	if (softc->ipf_proxy_soft != NULL) {
9354 		ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft);
9355 		softc->ipf_proxy_soft = NULL;
9356 	}
9357 
9358 	if (softc->ipf_sync_soft != NULL) {
9359 		ipf_sync_soft_destroy(softc, softc->ipf_sync_soft);
9360 		softc->ipf_sync_soft = NULL;
9361 	}
9362 
9363 	if (softc->ipf_lookup_soft != NULL) {
9364 		ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft);
9365 		softc->ipf_lookup_soft = NULL;
9366 	}
9367 
9368 #ifdef IPFILTER_LOG
9369 	if (softc->ipf_log_soft != NULL) {
9370 		ipf_log_soft_destroy(softc, softc->ipf_log_soft);
9371 		softc->ipf_log_soft = NULL;
9372 	}
9373 #endif
9374 
9375 	ipf_main_soft_destroy(softc);
9376 }
9377 
9378 
9379 /* ------------------------------------------------------------------------ */
9380 /* Function:   ipf_init_all                                                 */
9381 /* Returns:    0 = success, -1 = failure                                    */
9382 /* Parameters: softc(I) - pointer to soft context main structure            */
9383 /*                                                                          */
9384 /* Work through all of the subsystems inside IPFilter and call the init     */
9385 /* function for each in an order that won't lead to a crash :)              */
9386 /* ------------------------------------------------------------------------ */
9387 int
9388 ipf_init_all(ipf_main_softc_t *softc)
9389 {
9390 
9391 	if (ipf_main_soft_init(softc) == -1)
9392 		return (-1);
9393 
9394 #ifdef IPFILTER_LOG
9395 	if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1)
9396 		return (-1);
9397 #endif
9398 
9399 	if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1)
9400 		return (-1);
9401 
9402 	if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1)
9403 		return (-1);
9404 
9405 	if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1)
9406 		return (-1);
9407 
9408 	if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1)
9409 		return (-1);
9410 
9411 	if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1)
9412 		return (-1);
9413 
9414 	if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1)
9415 		return (-1);
9416 
9417 	if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1)
9418 		return (-1);
9419 
9420 	return (0);
9421 }
9422 
9423 
9424 /* ------------------------------------------------------------------------ */
9425 /* Function:   ipf_fini_all                                                 */
9426 /* Returns:    0 = success, -1 = failure                                    */
9427 /* Parameters: softc(I) - pointer to soft context main structure            */
9428 /*                                                                          */
9429 /* Work through all of the subsystems inside IPFilter and call the fini     */
9430 /* function for each in an order that won't lead to a crash :)              */
9431 /* ------------------------------------------------------------------------ */
9432 int
9433 ipf_fini_all(ipf_main_softc_t *softc)
9434 {
9435 
9436 	ipf_token_flush(softc);
9437 
9438 	if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1)
9439 		return (-1);
9440 
9441 	if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1)
9442 		return (-1);
9443 
9444 	if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1)
9445 		return (-1);
9446 
9447 	if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1)
9448 		return (-1);
9449 
9450 	if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1)
9451 		return (-1);
9452 
9453 	if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1)
9454 		return (-1);
9455 
9456 	if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1)
9457 		return (-1);
9458 
9459 #ifdef IPFILTER_LOG
9460 	if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1)
9461 		return (-1);
9462 #endif
9463 
9464 	if (ipf_main_soft_fini(softc) == -1)
9465 		return (-1);
9466 
9467 	return (0);
9468 }
9469 
9470 
9471 /* ------------------------------------------------------------------------ */
9472 /* Function:    ipf_rule_expire                                             */
9473 /* Returns:     Nil                                                         */
9474 /* Parameters:  softc(I) - pointer to soft context main structure           */
9475 /*                                                                          */
9476 /* At present this function exists just to support temporary addition of    */
9477 /* firewall rules. Both inactive and active lists are scanned for items to  */
9478 /* purge, as by rights, the expiration is computed as soon as the rule is   */
9479 /* loaded in.                                                               */
9480 /* ------------------------------------------------------------------------ */
9481 void
9482 ipf_rule_expire(ipf_main_softc_t *softc)
9483 {
9484 	frentry_t *fr;
9485 
9486 	if ((softc->ipf_rule_explist[0] == NULL) &&
9487 	    (softc->ipf_rule_explist[1] == NULL))
9488 		return;
9489 
9490 	WRITE_ENTER(&softc->ipf_mutex);
9491 
9492 	while ((fr = softc->ipf_rule_explist[0]) != NULL) {
9493 		/*
9494 		 * Because the list is kept sorted on insertion, the fist
9495 		 * one that dies in the future means no more work to do.
9496 		 */
9497 		if (fr->fr_die > softc->ipf_ticks)
9498 			break;
9499 		ipf_rule_delete(softc, fr, IPL_LOGIPF, 0);
9500 	}
9501 
9502 	while ((fr = softc->ipf_rule_explist[1]) != NULL) {
9503 		/*
9504 		 * Because the list is kept sorted on insertion, the fist
9505 		 * one that dies in the future means no more work to do.
9506 		 */
9507 		if (fr->fr_die > softc->ipf_ticks)
9508 			break;
9509 		ipf_rule_delete(softc, fr, IPL_LOGIPF, 1);
9510 	}
9511 
9512 	RWLOCK_EXIT(&softc->ipf_mutex);
9513 }
9514 
9515 
9516 static int ipf_ht_node_cmp(struct host_node_s *, struct host_node_s *);
9517 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int,
9518 				      i6addr_t *);
9519 
9520 host_node_t RBI_ZERO(ipf_rb);
9521 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp)
9522 
9523 
9524 /* ------------------------------------------------------------------------ */
9525 /* Function:    ipf_ht_node_cmp                                             */
9526 /* Returns:     int   - 0 == nodes are the same, ..                         */
9527 /* Parameters:  k1(I) - pointer to first key to compare                     */
9528 /*              k2(I) - pointer to second key to compare                    */
9529 /*                                                                          */
9530 /* The "key" for the node is a combination of two fields: the address       */
9531 /* family and the address itself.                                           */
9532 /*                                                                          */
9533 /* Because we're not actually interpreting the address data, it isn't       */
9534 /* necessary to convert them to/from network/host byte order. The mask is   */
9535 /* just used to remove bits that aren't significant - it doesn't matter     */
9536 /* where they are, as long as they're always in the same place.             */
9537 /*                                                                          */
9538 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because    */
9539 /* this is where individual ones will differ the most - but not true for    */
9540 /* for /48's, etc.                                                          */
9541 /* ------------------------------------------------------------------------ */
9542 static int
9543 ipf_ht_node_cmp(struct host_node_s *k1, struct host_node_s *k2)
9544 {
9545 	int i;
9546 
9547 	i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family);
9548 	if (i != 0)
9549 		return (i);
9550 
9551 	if (k1->hn_addr.adf_family == AF_INET)
9552 		return (k2->hn_addr.adf_addr.in4.s_addr -
9553 			k1->hn_addr.adf_addr.in4.s_addr);
9554 
9555 	i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3];
9556 	if (i != 0)
9557 		return (i);
9558 	i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2];
9559 	if (i != 0)
9560 		return (i);
9561 	i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1];
9562 	if (i != 0)
9563 		return (i);
9564 	i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0];
9565 	return (i);
9566 }
9567 
9568 
9569 /* ------------------------------------------------------------------------ */
9570 /* Function:    ipf_ht_node_make_key                                        */
9571 /* Returns:     Nil                                                         */
9572 /* parameters:  htp(I)    - pointer to address tracking structure           */
9573 /*              key(I)    - where to store masked address for lookup        */
9574 /*              family(I) - protocol family of address                      */
9575 /*              addr(I)   - pointer to network address                      */
9576 /*                                                                          */
9577 /* Using the "netmask" (number of bits) stored parent host tracking struct, */
9578 /* copy the address passed in into the key structure whilst masking out the */
9579 /* bits that we don't want.                                                 */
9580 /*                                                                          */
9581 /* Because the parser will set ht_netmask to 128 if there is no protocol    */
9582 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we  */
9583 /* have to be wary of that and not allow 32-128 to happen.                  */
9584 /* ------------------------------------------------------------------------ */
9585 static void
9586 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family,
9587 	i6addr_t *addr)
9588 {
9589 	key->hn_addr.adf_family = family;
9590 	if (family == AF_INET) {
9591 		u_32_t mask;
9592 		int bits;
9593 
9594 		key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4);
9595 		bits = htp->ht_netmask;
9596 		if (bits >= 32) {
9597 			mask = 0xffffffff;
9598 		} else {
9599 			mask = htonl(0xffffffff << (32 - bits));
9600 		}
9601 		key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask;
9602 #ifdef USE_INET6
9603 	} else {
9604 		int bits = htp->ht_netmask;
9605 
9606 		key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6);
9607 		if (bits > 96) {
9608 			key->hn_addr.adf_addr.i6[3] = addr->i6[3] &
9609 					     htonl(0xffffffff << (128 - bits));
9610 			key->hn_addr.adf_addr.i6[2] = addr->i6[2];
9611 			key->hn_addr.adf_addr.i6[1] = addr->i6[2];
9612 			key->hn_addr.adf_addr.i6[0] = addr->i6[2];
9613 		} else if (bits > 64) {
9614 			key->hn_addr.adf_addr.i6[3] = 0;
9615 			key->hn_addr.adf_addr.i6[2] = addr->i6[2] &
9616 					     htonl(0xffffffff << (96 - bits));
9617 			key->hn_addr.adf_addr.i6[1] = addr->i6[1];
9618 			key->hn_addr.adf_addr.i6[0] = addr->i6[0];
9619 		} else if (bits > 32) {
9620 			key->hn_addr.adf_addr.i6[3] = 0;
9621 			key->hn_addr.adf_addr.i6[2] = 0;
9622 			key->hn_addr.adf_addr.i6[1] = addr->i6[1] &
9623 					     htonl(0xffffffff << (64 - bits));
9624 			key->hn_addr.adf_addr.i6[0] = addr->i6[0];
9625 		} else {
9626 			key->hn_addr.adf_addr.i6[3] = 0;
9627 			key->hn_addr.adf_addr.i6[2] = 0;
9628 			key->hn_addr.adf_addr.i6[1] = 0;
9629 			key->hn_addr.adf_addr.i6[0] = addr->i6[0] &
9630 					     htonl(0xffffffff << (32 - bits));
9631 		}
9632 #endif
9633 	}
9634 }
9635 
9636 
9637 /* ------------------------------------------------------------------------ */
9638 /* Function:    ipf_ht_node_add                                             */
9639 /* Returns:     int       - 0 == success,  -1 == failure                    */
9640 /* Parameters:  softc(I)  - pointer to soft context main structure          */
9641 /*              htp(I)    - pointer to address tracking structure           */
9642 /*              family(I) - protocol family of address                      */
9643 /*              addr(I)   - pointer to network address                      */
9644 /*                                                                          */
9645 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
9646 /*       ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
9647 /*                                                                          */
9648 /* After preparing the key with the address information to find, look in    */
9649 /* the red-black tree to see if the address is known. A successful call to  */
9650 /* this function can mean one of two things: a new node was added to the    */
9651 /* tree or a matching node exists and we're able to bump up its activity.   */
9652 /* ------------------------------------------------------------------------ */
9653 int
9654 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family,
9655 	i6addr_t *addr)
9656 {
9657 	host_node_t *h;
9658 	host_node_t k;
9659 
9660 	ipf_ht_node_make_key(htp, &k, family, addr);
9661 
9662 	h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
9663 	if (h == NULL) {
9664 		if (htp->ht_cur_nodes >= htp->ht_max_nodes)
9665 			return (-1);
9666 		KMALLOC(h, host_node_t *);
9667 		if (h == NULL) {
9668 			DT(ipf_rb_no_mem);
9669 			LBUMP(ipf_rb_no_mem);
9670 			return (-1);
9671 		}
9672 
9673 		/*
9674 		 * If there was a macro to initialise the RB node then that
9675 		 * would get used here, but there isn't...
9676 		 */
9677 		bzero((char *)h, sizeof(*h));
9678 		h->hn_addr = k.hn_addr;
9679 		h->hn_addr.adf_family = k.hn_addr.adf_family;
9680 		RBI_INSERT(ipf_rb, &htp->ht_root, h);
9681 		htp->ht_cur_nodes++;
9682 	} else {
9683 		if ((htp->ht_max_per_node != 0) &&
9684 		    (h->hn_active >= htp->ht_max_per_node)) {
9685 			DT(ipf_rb_node_max);
9686 			LBUMP(ipf_rb_node_max);
9687 			return (-1);
9688 		}
9689 	}
9690 
9691 	h->hn_active++;
9692 
9693 	return (0);
9694 }
9695 
9696 
9697 /* ------------------------------------------------------------------------ */
9698 /* Function:    ipf_ht_node_del                                             */
9699 /* Returns:     int       - 0 == success,  -1 == failure                    */
9700 /* parameters:  htp(I)    - pointer to address tracking structure           */
9701 /*              family(I) - protocol family of address                      */
9702 /*              addr(I)   - pointer to network address                      */
9703 /*                                                                          */
9704 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
9705 /*       ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
9706 /*                                                                          */
9707 /* Try and find the address passed in amongst the leavese on this tree to   */
9708 /* be friend. If found then drop the active account for that node drops by  */
9709 /* one. If that count reaches 0, it is time to free it all up.              */
9710 /* ------------------------------------------------------------------------ */
9711 int
9712 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr)
9713 {
9714 	host_node_t *h;
9715 	host_node_t k;
9716 
9717 	ipf_ht_node_make_key(htp, &k, family, addr);
9718 
9719 	h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
9720 	if (h == NULL) {
9721 		return (-1);
9722 	} else {
9723 		h->hn_active--;
9724 		if (h->hn_active == 0) {
9725 			(void) RBI_DELETE(ipf_rb, &htp->ht_root, h);
9726 			htp->ht_cur_nodes--;
9727 			KFREE(h);
9728 		}
9729 	}
9730 
9731 	return (0);
9732 }
9733 
9734 
9735 /* ------------------------------------------------------------------------ */
9736 /* Function:    ipf_rb_ht_init                                              */
9737 /* Returns:     Nil                                                         */
9738 /* Parameters:  head(I) - pointer to host tracking structure                */
9739 /*                                                                          */
9740 /* Initialise the host tracking structure to be ready for use above.        */
9741 /* ------------------------------------------------------------------------ */
9742 void
9743 ipf_rb_ht_init(host_track_t *head)
9744 {
9745 	RBI_INIT(ipf_rb, &head->ht_root);
9746 }
9747 
9748 
9749 /* ------------------------------------------------------------------------ */
9750 /* Function:    ipf_rb_ht_freenode                                          */
9751 /* Returns:     Nil                                                         */
9752 /* Parameters:  head(I) - pointer to host tracking structure                */
9753 /*              arg(I)  - additional argument from walk caller              */
9754 /*                                                                          */
9755 /* Free an actual host_node_t structure.                                    */
9756 /* ------------------------------------------------------------------------ */
9757 void
9758 ipf_rb_ht_freenode(host_node_t *node, void *arg)
9759 {
9760 	KFREE(node);
9761 }
9762 
9763 
9764 /* ------------------------------------------------------------------------ */
9765 /* Function:    ipf_rb_ht_flush                                             */
9766 /* Returns:     Nil                                                         */
9767 /* Parameters:  head(I) - pointer to host tracking structure                */
9768 /*                                                                          */
9769 /* Remove all of the nodes in the tree tracking hosts by calling a walker   */
9770 /* and free'ing each one.                                                   */
9771 /* ------------------------------------------------------------------------ */
9772 void
9773 ipf_rb_ht_flush(host_track_t *head)
9774 {
9775 	RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL);
9776 }
9777 
9778 
9779 /* ------------------------------------------------------------------------ */
9780 /* Function:    ipf_slowtimer                                               */
9781 /* Returns:     Nil                                                         */
9782 /* Parameters:  ptr(I) - pointer to main ipf soft context structure         */
9783 /*                                                                          */
9784 /* Slowly expire held state for fragments.  Timeouts are set * in           */
9785 /* expectation of this being called twice per second.                       */
9786 /* ------------------------------------------------------------------------ */
9787 void
9788 ipf_slowtimer(ipf_main_softc_t *softc)
9789 {
9790 
9791 	ipf_token_expire(softc);
9792 	ipf_frag_expire(softc);
9793 	ipf_state_expire(softc);
9794 	ipf_nat_expire(softc);
9795 	ipf_auth_expire(softc);
9796 	ipf_lookup_expire(softc);
9797 	ipf_rule_expire(softc);
9798 	ipf_sync_expire(softc);
9799 	softc->ipf_ticks++;
9800 }
9801 
9802 
9803 /* ------------------------------------------------------------------------ */
9804 /* Function:    ipf_inet_mask_add                                           */
9805 /* Returns:     Nil                                                         */
9806 /* Parameters:  bits(I) - pointer to nat context information                */
9807 /*              mtab(I) - pointer to mask hash table structure              */
9808 /*                                                                          */
9809 /* When called, bits represents the mask of a new NAT rule that has just    */
9810 /* been added. This function inserts a bitmask into the array of masks to   */
9811 /* search when searching for a matching NAT rule for a packet.              */
9812 /* Prevention of duplicate masks is achieved by checking the use count for  */
9813 /* a given netmask.                                                         */
9814 /* ------------------------------------------------------------------------ */
9815 void
9816 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab)
9817 {
9818 	u_32_t mask;
9819 	int i, j;
9820 
9821 	mtab->imt4_masks[bits]++;
9822 	if (mtab->imt4_masks[bits] > 1)
9823 		return;
9824 
9825 	if (bits == 0)
9826 		mask = 0;
9827 	else
9828 		mask = 0xffffffff << (32 - bits);
9829 
9830 	for (i = 0; i < 33; i++) {
9831 		if (ntohl(mtab->imt4_active[i]) < mask) {
9832 			for (j = 32; j > i; j--)
9833 				mtab->imt4_active[j] = mtab->imt4_active[j - 1];
9834 			mtab->imt4_active[i] = htonl(mask);
9835 			break;
9836 		}
9837 	}
9838 	mtab->imt4_max++;
9839 }
9840 
9841 
9842 /* ------------------------------------------------------------------------ */
9843 /* Function:    ipf_inet_mask_del                                           */
9844 /* Returns:     Nil                                                         */
9845 /* Parameters:  bits(I) - number of bits set in the netmask                 */
9846 /*              mtab(I) - pointer to mask hash table structure              */
9847 /*                                                                          */
9848 /* Remove the 32bit bitmask represented by "bits" from the collection of    */
9849 /* netmasks stored inside of mtab.                                          */
9850 /* ------------------------------------------------------------------------ */
9851 void
9852 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab)
9853 {
9854 	u_32_t mask;
9855 	int i, j;
9856 
9857 	mtab->imt4_masks[bits]--;
9858 	if (mtab->imt4_masks[bits] > 0)
9859 		return;
9860 
9861 	mask = htonl(0xffffffff << (32 - bits));
9862 	for (i = 0; i < 33; i++) {
9863 		if (mtab->imt4_active[i] == mask) {
9864 			for (j = i + 1; j < 33; j++)
9865 				mtab->imt4_active[j - 1] = mtab->imt4_active[j];
9866 			break;
9867 		}
9868 	}
9869 	mtab->imt4_max--;
9870 	ASSERT(mtab->imt4_max >= 0);
9871 }
9872 
9873 
9874 #ifdef USE_INET6
9875 /* ------------------------------------------------------------------------ */
9876 /* Function:    ipf_inet6_mask_add                                          */
9877 /* Returns:     Nil                                                         */
9878 /* Parameters:  bits(I) - number of bits set in mask                        */
9879 /*              mask(I) - pointer to mask to add                            */
9880 /*              mtab(I) - pointer to mask hash table structure              */
9881 /*                                                                          */
9882 /* When called, bitcount represents the mask of a IPv6 NAT map rule that    */
9883 /* has just been added. This function inserts a bitmask into the array of   */
9884 /* masks to search when searching for a matching NAT rule for a packet.     */
9885 /* Prevention of duplicate masks is achieved by checking the use count for  */
9886 /* a given netmask.                                                         */
9887 /* ------------------------------------------------------------------------ */
9888 void
9889 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab)
9890 {
9891 	i6addr_t zero;
9892 	int i, j;
9893 
9894 	mtab->imt6_masks[bits]++;
9895 	if (mtab->imt6_masks[bits] > 1)
9896 		return;
9897 
9898 	if (bits == 0) {
9899 		mask = &zero;
9900 		zero.i6[0] = 0;
9901 		zero.i6[1] = 0;
9902 		zero.i6[2] = 0;
9903 		zero.i6[3] = 0;
9904 	}
9905 
9906 	for (i = 0; i < 129; i++) {
9907 		if (IP6_LT(&mtab->imt6_active[i], mask)) {
9908 			for (j = 128; j > i; j--)
9909 				mtab->imt6_active[j] = mtab->imt6_active[j - 1];
9910 			mtab->imt6_active[i] = *mask;
9911 			break;
9912 		}
9913 	}
9914 	mtab->imt6_max++;
9915 }
9916 
9917 
9918 /* ------------------------------------------------------------------------ */
9919 /* Function:    ipf_inet6_mask_del                                          */
9920 /* Returns:     Nil                                                         */
9921 /* Parameters:  bits(I) - number of bits set in mask                        */
9922 /*              mask(I) - pointer to mask to remove                         */
9923 /*              mtab(I) - pointer to mask hash table structure              */
9924 /*                                                                          */
9925 /* Remove the 128bit bitmask represented by "bits" from the collection of   */
9926 /* netmasks stored inside of mtab.                                          */
9927 /* ------------------------------------------------------------------------ */
9928 void
9929 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab)
9930 {
9931 	i6addr_t zero;
9932 	int i, j;
9933 
9934 	mtab->imt6_masks[bits]--;
9935 	if (mtab->imt6_masks[bits] > 0)
9936 		return;
9937 
9938 	if (bits == 0)
9939 		mask = &zero;
9940 	zero.i6[0] = 0;
9941 	zero.i6[1] = 0;
9942 	zero.i6[2] = 0;
9943 	zero.i6[3] = 0;
9944 
9945 	for (i = 0; i < 129; i++) {
9946 		if (IP6_EQ(&mtab->imt6_active[i], mask)) {
9947 			for (j = i + 1; j < 129; j++) {
9948 				mtab->imt6_active[j - 1] = mtab->imt6_active[j];
9949 				if (IP6_EQ(&mtab->imt6_active[j - 1], &zero))
9950 					break;
9951 			}
9952 			break;
9953 		}
9954 	}
9955 	mtab->imt6_max--;
9956 	ASSERT(mtab->imt6_max >= 0);
9957 }
9958 #endif
9959