]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/contrib/ipfilter/netinet/fil.c
MFC r348987, r348989:
[FreeBSD/stable/10.git] / sys / contrib / ipfilter / netinet / fil.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  *
8  * Copyright 2008 Sun Microsystems.
9  *
10  * $Id$
11  *
12  */
13 #if defined(KERNEL) || defined(_KERNEL)
14 # undef KERNEL
15 # undef _KERNEL
16 # define        KERNEL  1
17 # define        _KERNEL 1
18 #endif
19 #include <sys/errno.h>
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/time.h>
23 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
24     (__FreeBSD_version >= 220000)
25 # if (__FreeBSD_version >= 400000)
26 #  if !defined(IPFILTER_LKM)
27 #   include "opt_inet6.h"
28 #  endif
29 #  if (__FreeBSD_version == 400019)
30 #   define CSUM_DELAY_DATA
31 #  endif
32 # endif
33 # include <sys/filio.h>
34 #else
35 # include <sys/ioctl.h>
36 #endif
37 #if (defined(__SVR4) || defined(__svr4__)) && defined(sun)
38 # include <sys/filio.h>
39 #endif
40 #if !defined(_AIX51)
41 # include <sys/fcntl.h>
42 #endif
43 #if defined(_KERNEL)
44 # include <sys/systm.h>
45 # include <sys/file.h>
46 #else
47 # include <stdio.h>
48 # include <string.h>
49 # include <stdlib.h>
50 # include <stddef.h>
51 # include <sys/file.h>
52 # define _KERNEL
53 # ifdef __OpenBSD__
54 struct file;
55 # endif
56 # include <sys/uio.h>
57 # undef _KERNEL
58 #endif
59 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \
60     !defined(linux)
61 # include <sys/mbuf.h>
62 #else
63 # if !defined(linux)
64 #  include <sys/byteorder.h>
65 # endif
66 # if (SOLARIS2 < 5) && defined(sun)
67 #  include <sys/dditypes.h>
68 # endif
69 #endif
70 #ifdef __hpux
71 # define _NET_ROUTE_INCLUDED
72 #endif
73 #if !defined(linux)
74 # include <sys/protosw.h>
75 #endif
76 #include <sys/socket.h>
77 #include <net/if.h>
78 #ifdef sun
79 # include <net/af.h>
80 #endif
81 #include <netinet/in.h>
82 #include <netinet/in_systm.h>
83 #include <netinet/ip.h>
84 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
85 # include <sys/hashing.h>
86 # include <netinet/in_var.h>
87 #endif
88 #include <netinet/tcp.h>
89 #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL)
90 # include <netinet/udp.h>
91 # include <netinet/ip_icmp.h>
92 #endif
93 #ifdef __hpux
94 # undef _NET_ROUTE_INCLUDED
95 #endif
96 #ifdef __osf__
97 # undef _RADIX_H_
98 #endif
99 #include "netinet/ip_compat.h"
100 #ifdef  USE_INET6
101 # include <netinet/icmp6.h>
102 # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux)
103 #  include <netinet6/in6_var.h>
104 # endif
105 #endif
106 #include "netinet/ip_fil.h"
107 #include "netinet/ip_nat.h"
108 #include "netinet/ip_frag.h"
109 #include "netinet/ip_state.h"
110 #include "netinet/ip_proxy.h"
111 #include "netinet/ip_auth.h"
112 #ifdef IPFILTER_SCAN
113 # include "netinet/ip_scan.h"
114 #endif
115 #include "netinet/ip_sync.h"
116 #include "netinet/ip_lookup.h"
117 #include "netinet/ip_pool.h"
118 #include "netinet/ip_htable.h"
119 #ifdef IPFILTER_COMPILED
120 # include "netinet/ip_rules.h"
121 #endif
122 #if defined(IPFILTER_BPF) && defined(_KERNEL)
123 # include <net/bpf.h>
124 #endif
125 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
126 # include <sys/malloc.h>
127 #endif
128 #include "netinet/ipl.h"
129
130 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
131 # include <sys/callout.h>
132 extern struct callout ipf_slowtimer_ch;
133 #endif
134 #if defined(__OpenBSD__)
135 # include <sys/timeout.h>
136 extern struct timeout ipf_slowtimer_ch;
137 #endif
138 /* END OF INCLUDES */
139
140 #if !defined(lint)
141 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
142 static const char rcsid[] = "@(#)$FreeBSD$";
143 /* static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $"; */
144 #endif
145
146 #ifndef _KERNEL
147 # include "ipf.h"
148 # include "ipt.h"
149 extern  int     opts;
150 extern  int     blockreason;
151 #endif /* _KERNEL */
152
153 #define LBUMP(x)        softc->x++
154 #define LBUMPD(x, y)    do { softc->x.y++; DT(y); } while (0)
155
156 static  INLINE int      ipf_check_ipf __P((fr_info_t *, frentry_t *, int));
157 static  u_32_t          ipf_checkcipso __P((fr_info_t *, u_char *, int));
158 static  u_32_t          ipf_checkripso __P((u_char *));
159 static  u_32_t          ipf_decaps __P((fr_info_t *, u_32_t, int));
160 #ifdef IPFILTER_LOG
161 static  frentry_t       *ipf_dolog __P((fr_info_t *, u_32_t *));
162 #endif
163 static  int             ipf_flushlist __P((ipf_main_softc_t *, int *,
164                                            frentry_t **));
165 static  int             ipf_flush_groups __P((ipf_main_softc_t *, frgroup_t **,
166                                               int));
167 static  ipfunc_t        ipf_findfunc __P((ipfunc_t));
168 static  void            *ipf_findlookup __P((ipf_main_softc_t *, int,
169                                              frentry_t *,
170                                              i6addr_t *, i6addr_t *));
171 static  frentry_t       *ipf_firewall __P((fr_info_t *, u_32_t *));
172 static  int             ipf_fr_matcharray __P((fr_info_t *, int *));
173 static  int             ipf_frruleiter __P((ipf_main_softc_t *, void *, int,
174                                             void *));
175 static  void            ipf_funcfini __P((ipf_main_softc_t *, frentry_t *));
176 static  int             ipf_funcinit __P((ipf_main_softc_t *, frentry_t *));
177 static  int             ipf_geniter __P((ipf_main_softc_t *, ipftoken_t *,
178                                          ipfgeniter_t *));
179 static  void            ipf_getstat __P((ipf_main_softc_t *,
180                                          struct friostat *, int));
181 static  int             ipf_group_flush __P((ipf_main_softc_t *, frgroup_t *));
182 static  void            ipf_group_free __P((frgroup_t *));
183 static  int             ipf_grpmapfini __P((struct ipf_main_softc_s *,
184                                             frentry_t *));
185 static  int             ipf_grpmapinit __P((struct ipf_main_softc_s *,
186                                             frentry_t *));
187 static  frentry_t       *ipf_nextrule __P((ipf_main_softc_t *, int, int,
188                                            frentry_t *, int));
189 static  int             ipf_portcheck __P((frpcmp_t *, u_32_t));
190 static  INLINE int      ipf_pr_ah __P((fr_info_t *));
191 static  INLINE void     ipf_pr_esp __P((fr_info_t *));
192 static  INLINE void     ipf_pr_gre __P((fr_info_t *));
193 static  INLINE void     ipf_pr_udp __P((fr_info_t *));
194 static  INLINE void     ipf_pr_tcp __P((fr_info_t *));
195 static  INLINE void     ipf_pr_icmp __P((fr_info_t *));
196 static  INLINE void     ipf_pr_ipv4hdr __P((fr_info_t *));
197 static  INLINE void     ipf_pr_short __P((fr_info_t *, int));
198 static  INLINE int      ipf_pr_tcpcommon __P((fr_info_t *));
199 static  INLINE int      ipf_pr_udpcommon __P((fr_info_t *));
200 static  void            ipf_rule_delete __P((ipf_main_softc_t *, frentry_t *f,
201                                              int, int));
202 static  void            ipf_rule_expire_insert __P((ipf_main_softc_t *,
203                                                     frentry_t *, int));
204 static  int             ipf_synclist __P((ipf_main_softc_t *, frentry_t *,
205                                           void *));
206 static  void            ipf_token_flush __P((ipf_main_softc_t *));
207 static  void            ipf_token_unlink __P((ipf_main_softc_t *,
208                                               ipftoken_t *));
209 static  ipftuneable_t   *ipf_tune_findbyname __P((ipftuneable_t *,
210                                                   const char *));
211 static  ipftuneable_t   *ipf_tune_findbycookie __P((ipftuneable_t **, void *,
212                                                     void **));
213 static  int             ipf_updateipid __P((fr_info_t *));
214 static  int             ipf_settimeout __P((struct ipf_main_softc_s *,
215                                             struct ipftuneable *,
216                                             ipftuneval_t *));
217 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
218      !defined(__FreeBSD__)) || \
219     FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
220     OPENBSD_LT_REV(200006)
221 static  int             ppsratecheck(struct timeval *, int *, int);
222 #endif
223
224
225 /*
226  * bit values for identifying presence of individual IP options
227  * All of these tables should be ordered by increasing key value on the left
228  * hand side to allow for binary searching of the array and include a trailer
229  * with a 0 for the bitmask for linear searches to easily find the end with.
230  */
231 static const    struct  optlist ipopts[20] = {
232         { IPOPT_NOP,    0x000001 },
233         { IPOPT_RR,     0x000002 },
234         { IPOPT_ZSU,    0x000004 },
235         { IPOPT_MTUP,   0x000008 },
236         { IPOPT_MTUR,   0x000010 },
237         { IPOPT_ENCODE, 0x000020 },
238         { IPOPT_TS,     0x000040 },
239         { IPOPT_TR,     0x000080 },
240         { IPOPT_SECURITY, 0x000100 },
241         { IPOPT_LSRR,   0x000200 },
242         { IPOPT_E_SEC,  0x000400 },
243         { IPOPT_CIPSO,  0x000800 },
244         { IPOPT_SATID,  0x001000 },
245         { IPOPT_SSRR,   0x002000 },
246         { IPOPT_ADDEXT, 0x004000 },
247         { IPOPT_VISA,   0x008000 },
248         { IPOPT_IMITD,  0x010000 },
249         { IPOPT_EIP,    0x020000 },
250         { IPOPT_FINN,   0x040000 },
251         { 0,            0x000000 }
252 };
253
254 #ifdef USE_INET6
255 static const struct optlist ip6exthdr[] = {
256         { IPPROTO_HOPOPTS,              0x000001 },
257         { IPPROTO_IPV6,                 0x000002 },
258         { IPPROTO_ROUTING,              0x000004 },
259         { IPPROTO_FRAGMENT,             0x000008 },
260         { IPPROTO_ESP,                  0x000010 },
261         { IPPROTO_AH,                   0x000020 },
262         { IPPROTO_NONE,                 0x000040 },
263         { IPPROTO_DSTOPTS,              0x000080 },
264         { IPPROTO_MOBILITY,             0x000100 },
265         { 0,                            0 }
266 };
267 #endif
268
269 /*
270  * bit values for identifying presence of individual IP security options
271  */
272 static const    struct  optlist secopt[8] = {
273         { IPSO_CLASS_RES4,      0x01 },
274         { IPSO_CLASS_TOPS,      0x02 },
275         { IPSO_CLASS_SECR,      0x04 },
276         { IPSO_CLASS_RES3,      0x08 },
277         { IPSO_CLASS_CONF,      0x10 },
278         { IPSO_CLASS_UNCL,      0x20 },
279         { IPSO_CLASS_RES2,      0x40 },
280         { IPSO_CLASS_RES1,      0x80 }
281 };
282
283 char    ipfilter_version[] = IPL_VERSION;
284
285 int     ipf_features = 0
286 #ifdef  IPFILTER_LKM
287                 | IPF_FEAT_LKM
288 #endif
289 #ifdef  IPFILTER_LOG
290                 | IPF_FEAT_LOG
291 #endif
292                 | IPF_FEAT_LOOKUP
293 #ifdef  IPFILTER_BPF
294                 | IPF_FEAT_BPF
295 #endif
296 #ifdef  IPFILTER_COMPILED
297                 | IPF_FEAT_COMPILED
298 #endif
299 #ifdef  IPFILTER_CKSUM
300                 | IPF_FEAT_CKSUM
301 #endif
302                 | IPF_FEAT_SYNC
303 #ifdef  IPFILTER_SCAN
304                 | IPF_FEAT_SCAN
305 #endif
306 #ifdef  USE_INET6
307                 | IPF_FEAT_IPV6
308 #endif
309         ;
310
311
312 /*
313  * Table of functions available for use with call rules.
314  */
315 static ipfunc_resolve_t ipf_availfuncs[] = {
316         { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini },
317         { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini },
318         { "",         NULL,           NULL,           NULL }
319 };
320
321 static ipftuneable_t ipf_main_tuneables[] = {
322         { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) },
323                 "ipf_flags",            0,      0xffffffff,
324                 stsizeof(ipf_main_softc_t, ipf_flags),
325                 0,                      NULL,   NULL },
326         { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) },
327                 "active",               0,      0,
328                 stsizeof(ipf_main_softc_t, ipf_active),
329                 IPFT_RDONLY,            NULL,   NULL },
330         { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) },
331                 "control_forwarding",   0, 1,
332                 stsizeof(ipf_main_softc_t, ipf_control_forwarding),
333                 0,                      NULL,   NULL },
334         { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) },
335                 "update_ipid",          0,      1,
336                 stsizeof(ipf_main_softc_t, ipf_update_ipid),
337                 0,                      NULL,   NULL },
338         { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) },
339                 "chksrc",               0,      1,
340                 stsizeof(ipf_main_softc_t, ipf_chksrc),
341                 0,                      NULL,   NULL },
342         { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) },
343                 "min_ttl",              0,      1,
344                 stsizeof(ipf_main_softc_t, ipf_minttl),
345                 0,                      NULL,   NULL },
346         { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) },
347                 "icmp_minfragmtu",      0,      1,
348                 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu),
349                 0,                      NULL,   NULL },
350         { { (void *)offsetof(ipf_main_softc_t, ipf_pass) },
351                 "default_pass",         0,      0xffffffff,
352                 stsizeof(ipf_main_softc_t, ipf_pass),
353                 0,                      NULL,   NULL },
354         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) },
355                 "tcp_idle_timeout",     1,      0x7fffffff,
356                 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout),
357                 0,                      NULL,   ipf_settimeout },
358         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) },
359                 "tcp_close_wait",       1,      0x7fffffff,
360                 stsizeof(ipf_main_softc_t, ipf_tcpclosewait),
361                 0,                      NULL,   ipf_settimeout },
362         { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) },
363                 "tcp_last_ack",         1,      0x7fffffff,
364                 stsizeof(ipf_main_softc_t, ipf_tcplastack),
365                 0,                      NULL,   ipf_settimeout },
366         { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) },
367                 "tcp_timeout",          1,      0x7fffffff,
368                 stsizeof(ipf_main_softc_t, ipf_tcptimeout),
369                 0,                      NULL,   ipf_settimeout },
370         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) },
371                 "tcp_syn_sent",         1,      0x7fffffff,
372                 stsizeof(ipf_main_softc_t, ipf_tcpsynsent),
373                 0,                      NULL,   ipf_settimeout },
374         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) },
375                 "tcp_syn_received",     1,      0x7fffffff,
376                 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv),
377                 0,                      NULL,   ipf_settimeout },
378         { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) },
379                 "tcp_closed",           1,      0x7fffffff,
380                 stsizeof(ipf_main_softc_t, ipf_tcpclosed),
381                 0,                      NULL,   ipf_settimeout },
382         { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) },
383                 "tcp_half_closed",      1,      0x7fffffff,
384                 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed),
385                 0,                      NULL,   ipf_settimeout },
386         { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) },
387                 "tcp_time_wait",        1,      0x7fffffff,
388                 stsizeof(ipf_main_softc_t, ipf_tcptimewait),
389                 0,                      NULL,   ipf_settimeout },
390         { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) },
391                 "udp_timeout",          1,      0x7fffffff,
392                 stsizeof(ipf_main_softc_t, ipf_udptimeout),
393                 0,                      NULL,   ipf_settimeout },
394         { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) },
395                 "udp_ack_timeout",      1,      0x7fffffff,
396                 stsizeof(ipf_main_softc_t, ipf_udpacktimeout),
397                 0,                      NULL,   ipf_settimeout },
398         { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) },
399                 "icmp_timeout",         1,      0x7fffffff,
400                 stsizeof(ipf_main_softc_t, ipf_icmptimeout),
401                 0,                      NULL,   ipf_settimeout },
402         { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) },
403                 "icmp_ack_timeout",     1,      0x7fffffff,
404                 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout),
405                 0,                      NULL,   ipf_settimeout },
406         { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) },
407                 "ip_timeout",           1,      0x7fffffff,
408                 stsizeof(ipf_main_softc_t, ipf_iptimeout),
409                 0,                      NULL,   ipf_settimeout },
410 #if defined(INSTANCES) && defined(_KERNEL)
411         { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) },
412                 "intercept_loopback",   0,      1,
413                 stsizeof(ipf_main_softc_t, ipf_get_loopback),
414                 0,                      NULL,   ipf_set_loopback },
415 #endif
416         { { 0 },
417                 NULL,                   0,      0,
418                 0,
419                 0,                      NULL,   NULL }
420 };
421
422
423 /*
424  * The next section of code is a a collection of small routines that set
425  * fields in the fr_info_t structure passed based on properties of the
426  * current packet.  There are different routines for the same protocol
427  * for each of IPv4 and IPv6.  Adding a new protocol, for which there
428  * will "special" inspection for setup, is now more easily done by adding
429  * a new routine and expanding the ipf_pr_ipinit*() function rather than by
430  * adding more code to a growing switch statement.
431  */
432 #ifdef USE_INET6
433 static  INLINE int      ipf_pr_ah6 __P((fr_info_t *));
434 static  INLINE void     ipf_pr_esp6 __P((fr_info_t *));
435 static  INLINE void     ipf_pr_gre6 __P((fr_info_t *));
436 static  INLINE void     ipf_pr_udp6 __P((fr_info_t *));
437 static  INLINE void     ipf_pr_tcp6 __P((fr_info_t *));
438 static  INLINE void     ipf_pr_icmp6 __P((fr_info_t *));
439 static  INLINE void     ipf_pr_ipv6hdr __P((fr_info_t *));
440 static  INLINE void     ipf_pr_short6 __P((fr_info_t *, int));
441 static  INLINE int      ipf_pr_hopopts6 __P((fr_info_t *));
442 static  INLINE int      ipf_pr_mobility6 __P((fr_info_t *));
443 static  INLINE int      ipf_pr_routing6 __P((fr_info_t *));
444 static  INLINE int      ipf_pr_dstopts6 __P((fr_info_t *));
445 static  INLINE int      ipf_pr_fragment6 __P((fr_info_t *));
446 static  INLINE struct ip6_ext *ipf_pr_ipv6exthdr __P((fr_info_t *, int, int));
447
448
449 /* ------------------------------------------------------------------------ */
450 /* Function:    ipf_pr_short6                                               */
451 /* Returns:     void                                                        */
452 /* Parameters:  fin(I)  - pointer to packet information                     */
453 /*              xmin(I) - minimum header size                               */
454 /*                                                                          */
455 /* IPv6 Only                                                                */
456 /* This is function enforces the 'is a packet too short to be legit' rule   */
457 /* for IPv6 and marks the packet with FI_SHORT if so.  See function comment */
458 /* for ipf_pr_short() for more details.                                     */
459 /* ------------------------------------------------------------------------ */
460 static INLINE void
461 ipf_pr_short6(fin, xmin)
462         fr_info_t *fin;
463         int xmin;
464 {
465
466         if (fin->fin_dlen < xmin)
467                 fin->fin_flx |= FI_SHORT;
468 }
469
470
471 /* ------------------------------------------------------------------------ */
472 /* Function:    ipf_pr_ipv6hdr                                              */
473 /* Returns:     void                                                        */
474 /* Parameters:  fin(I) - pointer to packet information                      */
475 /*                                                                          */
476 /* IPv6 Only                                                                */
477 /* Copy values from the IPv6 header into the fr_info_t struct and call the  */
478 /* per-protocol analyzer if it exists.  In validating the packet, a protocol*/
479 /* analyzer may pullup or free the packet itself so we need to be vigiliant */
480 /* of that possibility arising.                                             */
481 /* ------------------------------------------------------------------------ */
482 static INLINE void
483 ipf_pr_ipv6hdr(fin)
484         fr_info_t *fin;
485 {
486         ip6_t *ip6 = (ip6_t *)fin->fin_ip;
487         int p, go = 1, i, hdrcount;
488         fr_ip_t *fi = &fin->fin_fi;
489
490         fin->fin_off = 0;
491
492         fi->fi_tos = 0;
493         fi->fi_optmsk = 0;
494         fi->fi_secmsk = 0;
495         fi->fi_auth = 0;
496
497         p = ip6->ip6_nxt;
498         fin->fin_crc = p;
499         fi->fi_ttl = ip6->ip6_hlim;
500         fi->fi_src.in6 = ip6->ip6_src;
501         fin->fin_crc += fi->fi_src.i6[0];
502         fin->fin_crc += fi->fi_src.i6[1];
503         fin->fin_crc += fi->fi_src.i6[2];
504         fin->fin_crc += fi->fi_src.i6[3];
505         fi->fi_dst.in6 = ip6->ip6_dst;
506         fin->fin_crc += fi->fi_dst.i6[0];
507         fin->fin_crc += fi->fi_dst.i6[1];
508         fin->fin_crc += fi->fi_dst.i6[2];
509         fin->fin_crc += fi->fi_dst.i6[3];
510         fin->fin_id = 0;
511         if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
512                 fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
513
514         hdrcount = 0;
515         while (go && !(fin->fin_flx & FI_SHORT)) {
516                 switch (p)
517                 {
518                 case IPPROTO_UDP :
519                         ipf_pr_udp6(fin);
520                         go = 0;
521                         break;
522
523                 case IPPROTO_TCP :
524                         ipf_pr_tcp6(fin);
525                         go = 0;
526                         break;
527
528                 case IPPROTO_ICMPV6 :
529                         ipf_pr_icmp6(fin);
530                         go = 0;
531                         break;
532
533                 case IPPROTO_GRE :
534                         ipf_pr_gre6(fin);
535                         go = 0;
536                         break;
537
538                 case IPPROTO_HOPOPTS :
539                         p = ipf_pr_hopopts6(fin);
540                         break;
541
542                 case IPPROTO_MOBILITY :
543                         p = ipf_pr_mobility6(fin);
544                         break;
545
546                 case IPPROTO_DSTOPTS :
547                         p = ipf_pr_dstopts6(fin);
548                         break;
549
550                 case IPPROTO_ROUTING :
551                         p = ipf_pr_routing6(fin);
552                         break;
553
554                 case IPPROTO_AH :
555                         p = ipf_pr_ah6(fin);
556                         break;
557
558                 case IPPROTO_ESP :
559                         ipf_pr_esp6(fin);
560                         go = 0;
561                         break;
562
563                 case IPPROTO_IPV6 :
564                         for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
565                                 if (ip6exthdr[i].ol_val == p) {
566                                         fin->fin_flx |= ip6exthdr[i].ol_bit;
567                                         break;
568                                 }
569                         go = 0;
570                         break;
571
572                 case IPPROTO_NONE :
573                         go = 0;
574                         break;
575
576                 case IPPROTO_FRAGMENT :
577                         p = ipf_pr_fragment6(fin);
578                         /*
579                          * Given that the only fragments we want to let through
580                          * (where fin_off != 0) are those where the non-first
581                          * fragments only have data, we can safely stop looking
582                          * at headers if this is a non-leading fragment.
583                          */
584                         if (fin->fin_off != 0)
585                                 go = 0;
586                         break;
587
588                 default :
589                         go = 0;
590                         break;
591                 }
592                 hdrcount++;
593
594                 /*
595                  * It is important to note that at this point, for the
596                  * extension headers (go != 0), the entire header may not have
597                  * been pulled up when the code gets to this point.  This is
598                  * only done for "go != 0" because the other header handlers
599                  * will all pullup their complete header.  The other indicator
600                  * of an incomplete packet is that this was just an extension
601                  * header.
602                  */
603                 if ((go != 0) && (p != IPPROTO_NONE) &&
604                     (ipf_pr_pullup(fin, 0) == -1)) {
605                         p = IPPROTO_NONE;
606                         break;
607                 }
608         }
609
610         /*
611          * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup
612          * and destroy whatever packet was here.  The caller of this function
613          * expects us to return if there is a problem with ipf_pullup.
614          */
615         if (fin->fin_m == NULL) {
616                 ipf_main_softc_t *softc = fin->fin_main_soft;
617
618                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad);
619                 return;
620         }
621
622         fi->fi_p = p;
623
624         /*
625          * IPv6 fragment case 1 - see comment for ipf_pr_fragment6().
626          * "go != 0" imples the above loop hasn't arrived at a layer 4 header.
627          */
628         if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) {
629                 ipf_main_softc_t *softc = fin->fin_main_soft;
630
631                 fin->fin_flx |= FI_BAD;
632                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag);
633                 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad);
634         }
635 }
636
637
638 /* ------------------------------------------------------------------------ */
639 /* Function:    ipf_pr_ipv6exthdr                                           */
640 /* Returns:     struct ip6_ext * - pointer to the start of the next header  */
641 /*                                 or NULL if there is a prolblem.          */
642 /* Parameters:  fin(I)      - pointer to packet information                 */
643 /*              multiple(I) - flag indicating yes/no if multiple occurances */
644 /*                            of this extension header are allowed.         */
645 /*              proto(I)    - protocol number for this extension header     */
646 /*                                                                          */
647 /* IPv6 Only                                                                */
648 /* This function embodies a number of common checks that all IPv6 extension */
649 /* headers must be subjected to.  For example, making sure the packet is    */
650 /* big enough for it to be in, checking if it is repeated and setting a     */
651 /* flag to indicate its presence.                                           */
652 /* ------------------------------------------------------------------------ */
653 static INLINE struct ip6_ext *
654 ipf_pr_ipv6exthdr(fin, multiple, proto)
655         fr_info_t *fin;
656         int multiple, proto;
657 {
658         ipf_main_softc_t *softc = fin->fin_main_soft;
659         struct ip6_ext *hdr;
660         u_short shift;
661         int i;
662
663         fin->fin_flx |= FI_V6EXTHDR;
664
665                                 /* 8 is default length of extension hdr */
666         if ((fin->fin_dlen - 8) < 0) {
667                 fin->fin_flx |= FI_SHORT;
668                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short);
669                 return NULL;
670         }
671
672         if (ipf_pr_pullup(fin, 8) == -1) {
673                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup);
674                 return NULL;
675         }
676
677         hdr = fin->fin_dp;
678         switch (proto)
679         {
680         case IPPROTO_FRAGMENT :
681                 shift = 8;
682                 break;
683         default :
684                 shift = 8 + (hdr->ip6e_len << 3);
685                 break;
686         }
687
688         if (shift > fin->fin_dlen) {    /* Nasty extension header length? */
689                 fin->fin_flx |= FI_BAD;
690                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen);
691                 return NULL;
692         }
693
694         fin->fin_dp = (char *)fin->fin_dp + shift;
695         fin->fin_dlen -= shift;
696
697         /*
698          * If we have seen a fragment header, do not set any flags to indicate
699          * the presence of this extension header as it has no impact on the
700          * end result until after it has been defragmented.
701          */
702         if (fin->fin_flx & FI_FRAG)
703                 return hdr;
704
705         for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
706                 if (ip6exthdr[i].ol_val == proto) {
707                         /*
708                          * Most IPv6 extension headers are only allowed once.
709                          */
710                         if ((multiple == 0) &&
711                             ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0))
712                                 fin->fin_flx |= FI_BAD;
713                         else
714                                 fin->fin_optmsk |= ip6exthdr[i].ol_bit;
715                         break;
716                 }
717
718         return hdr;
719 }
720
721
722 /* ------------------------------------------------------------------------ */
723 /* Function:    ipf_pr_hopopts6                                             */
724 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
725 /* Parameters:  fin(I) - pointer to packet information                      */
726 /*                                                                          */
727 /* IPv6 Only                                                                */
728 /* This is function checks pending hop by hop options extension header      */
729 /* ------------------------------------------------------------------------ */
730 static INLINE int
731 ipf_pr_hopopts6(fin)
732         fr_info_t *fin;
733 {
734         struct ip6_ext *hdr;
735
736         hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
737         if (hdr == NULL)
738                 return IPPROTO_NONE;
739         return hdr->ip6e_nxt;
740 }
741
742
743 /* ------------------------------------------------------------------------ */
744 /* Function:    ipf_pr_mobility6                                            */
745 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
746 /* Parameters:  fin(I) - pointer to packet information                      */
747 /*                                                                          */
748 /* IPv6 Only                                                                */
749 /* This is function checks the IPv6 mobility extension header               */
750 /* ------------------------------------------------------------------------ */
751 static INLINE int
752 ipf_pr_mobility6(fin)
753         fr_info_t *fin;
754 {
755         struct ip6_ext *hdr;
756
757         hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
758         if (hdr == NULL)
759                 return IPPROTO_NONE;
760         return hdr->ip6e_nxt;
761 }
762
763
764 /* ------------------------------------------------------------------------ */
765 /* Function:    ipf_pr_routing6                                             */
766 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
767 /* Parameters:  fin(I) - pointer to packet information                      */
768 /*                                                                          */
769 /* IPv6 Only                                                                */
770 /* This is function checks pending routing extension header                 */
771 /* ------------------------------------------------------------------------ */
772 static INLINE int
773 ipf_pr_routing6(fin)
774         fr_info_t *fin;
775 {
776         struct ip6_routing *hdr;
777
778         hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING);
779         if (hdr == NULL)
780                 return IPPROTO_NONE;
781
782         switch (hdr->ip6r_type)
783         {
784         case 0 :
785                 /*
786                  * Nasty extension header length?
787                  */
788                 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) ||
789                     (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) {
790                         ipf_main_softc_t *softc = fin->fin_main_soft;
791
792                         fin->fin_flx |= FI_BAD;
793                         LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad);
794                         return IPPROTO_NONE;
795                 }
796                 break;
797
798         default :
799                 break;
800         }
801
802         return hdr->ip6r_nxt;
803 }
804
805
806 /* ------------------------------------------------------------------------ */
807 /* Function:    ipf_pr_fragment6                                            */
808 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
809 /* Parameters:  fin(I) - pointer to packet information                      */
810 /*                                                                          */
811 /* IPv6 Only                                                                */
812 /* Examine the IPv6 fragment header and extract fragment offset information.*/
813 /*                                                                          */
814 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */
815 /* so than in IPv4.  There are 5 cases of fragments with IPv6 that all      */
816 /* packets with a fragment header can fit into.  They are as follows:       */
817 /*                                                                          */
818 /* 1.  [IPv6][0-n EH][FH][0-n EH] (no L4HDR present)                        */
819 /* 2.  [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short)                       */
820 /* 3.  [IPV6][0-n EH][FH][L4HDR part][0-n data] (short)                     */
821 /* 4.  [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data]                          */
822 /* 5.  [IPV6][0-n EH][FH][data]                                             */
823 /*                                                                          */
824 /* IPV6 = IPv6 header, FH = Fragment Header,                                */
825 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */
826 /*                                                                          */
827 /* Packets that match 1, 2, 3 will be dropped as the only reasonable        */
828 /* scenario in which they happen is in extreme circumstances that are most  */
829 /* likely to be an indication of an attack rather than normal traffic.      */
830 /* A type 3 packet may be sent by an attacked after a type 4 packet.  There */
831 /* are two rules that can be used to guard against type 3 packets: L4       */
832 /* headers must always be in a packet that has the offset field set to 0    */
833 /* and no packet is allowed to overlay that where offset = 0.               */
834 /* ------------------------------------------------------------------------ */
835 static INLINE int
836 ipf_pr_fragment6(fin)
837         fr_info_t *fin;
838 {
839         ipf_main_softc_t *softc = fin->fin_main_soft;
840         struct ip6_frag *frag;
841
842         fin->fin_flx |= FI_FRAG;
843
844         frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT);
845         if (frag == NULL) {
846                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad);
847                 return IPPROTO_NONE;
848         }
849
850         if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
851                 /*
852                  * Any fragment that isn't the last fragment must have its
853                  * length as a multiple of 8.
854                  */
855                 if ((fin->fin_plen & 7) != 0)
856                         fin->fin_flx |= FI_BAD;
857         }
858
859         fin->fin_fraghdr = frag;
860         fin->fin_id = frag->ip6f_ident;
861         fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
862         if (fin->fin_off != 0)
863                 fin->fin_flx |= FI_FRAGBODY;
864
865         /*
866          * Jumbograms aren't handled, so the max. length is 64k
867          */
868         if ((fin->fin_off << 3) + fin->fin_dlen > 65535)
869                   fin->fin_flx |= FI_BAD;
870
871         /*
872          * We don't know where the transport layer header (or whatever is next
873          * is), as it could be behind destination options (amongst others) so
874          * return the fragment header as the type of packet this is.  Note that
875          * this effectively disables the fragment cache for > 1 protocol at a
876          * time.
877          */
878         return frag->ip6f_nxt;
879 }
880
881
882 /* ------------------------------------------------------------------------ */
883 /* Function:    ipf_pr_dstopts6                                             */
884 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
885 /* Parameters:  fin(I) - pointer to packet information                      */
886 /*                                                                          */
887 /* IPv6 Only                                                                */
888 /* This is function checks pending destination options extension header     */
889 /* ------------------------------------------------------------------------ */
890 static INLINE int
891 ipf_pr_dstopts6(fin)
892         fr_info_t *fin;
893 {
894         ipf_main_softc_t *softc = fin->fin_main_soft;
895         struct ip6_ext *hdr;
896
897         hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS);
898         if (hdr == NULL) {
899                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad);
900                 return IPPROTO_NONE;
901         }
902         return hdr->ip6e_nxt;
903 }
904
905
906 /* ------------------------------------------------------------------------ */
907 /* Function:    ipf_pr_icmp6                                                */
908 /* Returns:     void                                                        */
909 /* Parameters:  fin(I) - pointer to packet information                      */
910 /*                                                                          */
911 /* IPv6 Only                                                                */
912 /* This routine is mainly concerned with determining the minimum valid size */
913 /* for an ICMPv6 packet.                                                    */
914 /* ------------------------------------------------------------------------ */
915 static INLINE void
916 ipf_pr_icmp6(fin)
917         fr_info_t *fin;
918 {
919         int minicmpsz = sizeof(struct icmp6_hdr);
920         struct icmp6_hdr *icmp6;
921
922         if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) {
923                 ipf_main_softc_t *softc = fin->fin_main_soft;
924
925                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup);
926                 return;
927         }
928
929         if (fin->fin_dlen > 1) {
930                 ip6_t *ip6;
931
932                 icmp6 = fin->fin_dp;
933
934                 fin->fin_data[0] = *(u_short *)icmp6;
935
936                 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
937                         fin->fin_flx |= FI_ICMPQUERY;
938
939                 switch (icmp6->icmp6_type)
940                 {
941                 case ICMP6_ECHO_REPLY :
942                 case ICMP6_ECHO_REQUEST :
943                         if (fin->fin_dlen >= 6)
944                                 fin->fin_data[1] = icmp6->icmp6_id;
945                         minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
946                         break;
947
948                 case ICMP6_DST_UNREACH :
949                 case ICMP6_PACKET_TOO_BIG :
950                 case ICMP6_TIME_EXCEEDED :
951                 case ICMP6_PARAM_PROB :
952                         fin->fin_flx |= FI_ICMPERR;
953                         minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
954                         if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
955                                 break;
956
957                         if (M_LEN(fin->fin_m) < fin->fin_plen) {
958                                 if (ipf_coalesce(fin) != 1)
959                                         return;
960                         }
961
962                         if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
963                                 return;
964
965                         /*
966                          * If the destination of this packet doesn't match the
967                          * source of the original packet then this packet is
968                          * not correct.
969                          */
970                         icmp6 = fin->fin_dp;
971                         ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN);
972                         if (IP6_NEQ(&fin->fin_fi.fi_dst,
973                                     (i6addr_t *)&ip6->ip6_src))
974                                 fin->fin_flx |= FI_BAD;
975                         break;
976                 default :
977                         break;
978                 }
979         }
980
981         ipf_pr_short6(fin, minicmpsz);
982         if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) {
983                 u_char p = fin->fin_p;
984
985                 fin->fin_p = IPPROTO_ICMPV6;
986                 ipf_checkv6sum(fin);
987                 fin->fin_p = p;
988         }
989 }
990
991
992 /* ------------------------------------------------------------------------ */
993 /* Function:    ipf_pr_udp6                                                 */
994 /* Returns:     void                                                        */
995 /* Parameters:  fin(I) - pointer to packet information                      */
996 /*                                                                          */
997 /* IPv6 Only                                                                */
998 /* Analyse the packet for IPv6/UDP properties.                              */
999 /* Is not expected to be called for fragmented packets.                     */
1000 /* ------------------------------------------------------------------------ */
1001 static INLINE void
1002 ipf_pr_udp6(fin)
1003         fr_info_t *fin;
1004 {
1005
1006         if (ipf_pr_udpcommon(fin) == 0) {
1007                 u_char p = fin->fin_p;
1008
1009                 fin->fin_p = IPPROTO_UDP;
1010                 ipf_checkv6sum(fin);
1011                 fin->fin_p = p;
1012         }
1013 }
1014
1015
1016 /* ------------------------------------------------------------------------ */
1017 /* Function:    ipf_pr_tcp6                                                 */
1018 /* Returns:     void                                                        */
1019 /* Parameters:  fin(I) - pointer to packet information                      */
1020 /*                                                                          */
1021 /* IPv6 Only                                                                */
1022 /* Analyse the packet for IPv6/TCP properties.                              */
1023 /* Is not expected to be called for fragmented packets.                     */
1024 /* ------------------------------------------------------------------------ */
1025 static INLINE void
1026 ipf_pr_tcp6(fin)
1027         fr_info_t *fin;
1028 {
1029
1030         if (ipf_pr_tcpcommon(fin) == 0) {
1031                 u_char p = fin->fin_p;
1032
1033                 fin->fin_p = IPPROTO_TCP;
1034                 ipf_checkv6sum(fin);
1035                 fin->fin_p = p;
1036         }
1037 }
1038
1039
1040 /* ------------------------------------------------------------------------ */
1041 /* Function:    ipf_pr_esp6                                                 */
1042 /* Returns:     void                                                        */
1043 /* Parameters:  fin(I) - pointer to packet information                      */
1044 /*                                                                          */
1045 /* IPv6 Only                                                                */
1046 /* Analyse the packet for ESP properties.                                   */
1047 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
1048 /* even though the newer ESP packets must also have a sequence number that  */
1049 /* is 32bits as well, it is not possible(?) to determine the version from a */
1050 /* simple packet header.                                                    */
1051 /* ------------------------------------------------------------------------ */
1052 static INLINE void
1053 ipf_pr_esp6(fin)
1054         fr_info_t *fin;
1055 {
1056
1057         if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) {
1058                 ipf_main_softc_t *softc = fin->fin_main_soft;
1059
1060                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup);
1061                 return;
1062         }
1063 }
1064
1065
1066 /* ------------------------------------------------------------------------ */
1067 /* Function:    ipf_pr_ah6                                                  */
1068 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
1069 /* Parameters:  fin(I) - pointer to packet information                      */
1070 /*                                                                          */
1071 /* IPv6 Only                                                                */
1072 /* Analyse the packet for AH properties.                                    */
1073 /* The minimum length is taken to be the combination of all fields in the   */
1074 /* header being present and no authentication data (null algorithm used.)   */
1075 /* ------------------------------------------------------------------------ */
1076 static INLINE int
1077 ipf_pr_ah6(fin)
1078         fr_info_t *fin;
1079 {
1080         authhdr_t *ah;
1081
1082         fin->fin_flx |= FI_AH;
1083
1084         ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
1085         if (ah == NULL) {
1086                 ipf_main_softc_t *softc = fin->fin_main_soft;
1087
1088                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad);
1089                 return IPPROTO_NONE;
1090         }
1091
1092         ipf_pr_short6(fin, sizeof(*ah));
1093
1094         /*
1095          * No need for another pullup, ipf_pr_ipv6exthdr() will pullup
1096          * enough data to satisfy ah_next (the very first one.)
1097          */
1098         return ah->ah_next;
1099 }
1100
1101
1102 /* ------------------------------------------------------------------------ */
1103 /* Function:    ipf_pr_gre6                                                 */
1104 /* Returns:     void                                                        */
1105 /* Parameters:  fin(I) - pointer to packet information                      */
1106 /*                                                                          */
1107 /* Analyse the packet for GRE properties.                                   */
1108 /* ------------------------------------------------------------------------ */
1109 static INLINE void
1110 ipf_pr_gre6(fin)
1111         fr_info_t *fin;
1112 {
1113         grehdr_t *gre;
1114
1115         if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
1116                 ipf_main_softc_t *softc = fin->fin_main_soft;
1117
1118                 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup);
1119                 return;
1120         }
1121
1122         gre = fin->fin_dp;
1123         if (GRE_REV(gre->gr_flags) == 1)
1124                 fin->fin_data[0] = gre->gr_call;
1125 }
1126 #endif  /* USE_INET6 */
1127
1128
1129 /* ------------------------------------------------------------------------ */
1130 /* Function:    ipf_pr_pullup                                               */
1131 /* Returns:     int     - 0 == pullup succeeded, -1 == failure              */
1132 /* Parameters:  fin(I)  - pointer to packet information                     */
1133 /*              plen(I) - length (excluding L3 header) to pullup            */
1134 /*                                                                          */
1135 /* Short inline function to cut down on code duplication to perform a call  */
1136 /* to ipf_pullup to ensure there is the required amount of data,            */
1137 /* consecutively in the packet buffer.                                      */
1138 /*                                                                          */
1139 /* This function pulls up 'extra' data at the location of fin_dp.  fin_dp   */
1140 /* points to the first byte after the complete layer 3 header, which will   */
1141 /* include all of the known extension headers for IPv6 or options for IPv4. */
1142 /*                                                                          */
1143 /* Since fr_pullup() expects the total length of bytes to be pulled up, it  */
1144 /* is necessary to add those we can already assume to be pulled up (fin_dp  */
1145 /* - fin_ip) to what is passed through.                                     */
1146 /* ------------------------------------------------------------------------ */
1147 int
1148 ipf_pr_pullup(fin, plen)
1149         fr_info_t *fin;
1150         int plen;
1151 {
1152         ipf_main_softc_t *softc = fin->fin_main_soft;
1153
1154         if (fin->fin_m != NULL) {
1155                 if (fin->fin_dp != NULL)
1156                         plen += (char *)fin->fin_dp -
1157                                 ((char *)fin->fin_ip + fin->fin_hlen);
1158                 plen += fin->fin_hlen;
1159                 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
1160 #if defined(_KERNEL)
1161                         if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
1162                                 DT(ipf_pullup_fail);
1163                                 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
1164                                 return -1;
1165                         }
1166                         LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
1167 #else
1168                         LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
1169                         /*
1170                          * Fake ipf_pullup failing
1171                          */
1172                         fin->fin_reason = FRB_PULLUP;
1173                         *fin->fin_mp = NULL;
1174                         fin->fin_m = NULL;
1175                         fin->fin_ip = NULL;
1176                         return -1;
1177 #endif
1178                 }
1179         }
1180         return 0;
1181 }
1182
1183
1184 /* ------------------------------------------------------------------------ */
1185 /* Function:    ipf_pr_short                                                */
1186 /* Returns:     void                                                        */
1187 /* Parameters:  fin(I)  - pointer to packet information                     */
1188 /*              xmin(I) - minimum header size                               */
1189 /*                                                                          */
1190 /* Check if a packet is "short" as defined by xmin.  The rule we are        */
1191 /* applying here is that the packet must not be fragmented within the layer */
1192 /* 4 header.  That is, it must not be a fragment that has its offset set to */
1193 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the    */
1194 /* entire layer 4 header must be present (min).                             */
1195 /* ------------------------------------------------------------------------ */
1196 static INLINE void
1197 ipf_pr_short(fin, xmin)
1198         fr_info_t *fin;
1199         int xmin;
1200 {
1201
1202         if (fin->fin_off == 0) {
1203                 if (fin->fin_dlen < xmin)
1204                         fin->fin_flx |= FI_SHORT;
1205         } else if (fin->fin_off < xmin) {
1206                 fin->fin_flx |= FI_SHORT;
1207         }
1208 }
1209
1210
1211 /* ------------------------------------------------------------------------ */
1212 /* Function:    ipf_pr_icmp                                                 */
1213 /* Returns:     void                                                        */
1214 /* Parameters:  fin(I) - pointer to packet information                      */
1215 /*                                                                          */
1216 /* IPv4 Only                                                                */
1217 /* Do a sanity check on the packet for ICMP (v4).  In nearly all cases,     */
1218 /* except extrememly bad packets, both type and code will be present.       */
1219 /* The expected minimum size of an ICMP packet is very much dependent on    */
1220 /* the type of it.                                                          */
1221 /*                                                                          */
1222 /* XXX - other ICMP sanity checks?                                          */
1223 /* ------------------------------------------------------------------------ */
1224 static INLINE void
1225 ipf_pr_icmp(fin)
1226         fr_info_t *fin;
1227 {
1228         ipf_main_softc_t *softc = fin->fin_main_soft;
1229         int minicmpsz = sizeof(struct icmp);
1230         icmphdr_t *icmp;
1231         ip_t *oip;
1232
1233         ipf_pr_short(fin, ICMPERR_ICMPHLEN);
1234
1235         if (fin->fin_off != 0) {
1236                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag);
1237                 return;
1238         }
1239
1240         if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) {
1241                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup);
1242                 return;
1243         }
1244
1245         icmp = fin->fin_dp;
1246
1247         fin->fin_data[0] = *(u_short *)icmp;
1248         fin->fin_data[1] = icmp->icmp_id;
1249
1250         switch (icmp->icmp_type)
1251         {
1252         case ICMP_ECHOREPLY :
1253         case ICMP_ECHO :
1254         /* Router discovery messaes - RFC 1256 */
1255         case ICMP_ROUTERADVERT :
1256         case ICMP_ROUTERSOLICIT :
1257                 fin->fin_flx |= FI_ICMPQUERY;
1258                 minicmpsz = ICMP_MINLEN;
1259                 break;
1260         /*
1261          * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1262          * 3 * timestamp(3 * 4)
1263          */
1264         case ICMP_TSTAMP :
1265         case ICMP_TSTAMPREPLY :
1266                 fin->fin_flx |= FI_ICMPQUERY;
1267                 minicmpsz = 20;
1268                 break;
1269         /*
1270          * type(1) + code(1) + cksum(2) + id(2) seq(2) +
1271          * mask(4)
1272          */
1273         case ICMP_IREQ :
1274         case ICMP_IREQREPLY :
1275         case ICMP_MASKREQ :
1276         case ICMP_MASKREPLY :
1277                 fin->fin_flx |= FI_ICMPQUERY;
1278                 minicmpsz = 12;
1279                 break;
1280         /*
1281          * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
1282          */
1283         case ICMP_UNREACH :
1284 #ifdef icmp_nextmtu
1285                 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
1286                         if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu)
1287                                 fin->fin_flx |= FI_BAD;
1288                 }
1289 #endif
1290                 /* FALLTHROUGH */
1291         case ICMP_SOURCEQUENCH :
1292         case ICMP_REDIRECT :
1293         case ICMP_TIMXCEED :
1294         case ICMP_PARAMPROB :
1295                 fin->fin_flx |= FI_ICMPERR;
1296                 if (ipf_coalesce(fin) != 1) {
1297                         LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce);
1298                         return;
1299                 }
1300
1301                 /*
1302                  * ICMP error packets should not be generated for IP
1303                  * packets that are a fragment that isn't the first
1304                  * fragment.
1305                  */
1306                 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
1307                 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
1308                         fin->fin_flx |= FI_BAD;
1309
1310                 /*
1311                  * If the destination of this packet doesn't match the
1312                  * source of the original packet then this packet is
1313                  * not correct.
1314                  */
1315                 if (oip->ip_src.s_addr != fin->fin_daddr)
1316                         fin->fin_flx |= FI_BAD;
1317                 break;
1318         default :
1319                 break;
1320         }
1321
1322         ipf_pr_short(fin, minicmpsz);
1323
1324         ipf_checkv4sum(fin);
1325 }
1326
1327
1328 /* ------------------------------------------------------------------------ */
1329 /* Function:    ipf_pr_tcpcommon                                            */
1330 /* Returns:     int    - 0 = header ok, 1 = bad packet, -1 = buffer error   */
1331 /* Parameters:  fin(I) - pointer to packet information                      */
1332 /*                                                                          */
1333 /* TCP header sanity checking.  Look for bad combinations of TCP flags,     */
1334 /* and make some checks with how they interact with other fields.           */
1335 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is     */
1336 /* valid and mark the packet as bad if not.                                 */
1337 /* ------------------------------------------------------------------------ */
1338 static INLINE int
1339 ipf_pr_tcpcommon(fin)
1340         fr_info_t *fin;
1341 {
1342         ipf_main_softc_t *softc = fin->fin_main_soft;
1343         int flags, tlen;
1344         tcphdr_t *tcp;
1345
1346         fin->fin_flx |= FI_TCPUDP;
1347         if (fin->fin_off != 0) {
1348                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag);
1349                 return 0;
1350         }
1351
1352         if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) {
1353                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
1354                 return -1;
1355         }
1356
1357         tcp = fin->fin_dp;
1358         if (fin->fin_dlen > 3) {
1359                 fin->fin_sport = ntohs(tcp->th_sport);
1360                 fin->fin_dport = ntohs(tcp->th_dport);
1361         }
1362
1363         if ((fin->fin_flx & FI_SHORT) != 0) {
1364                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short);
1365                 return 1;
1366         }
1367
1368         /*
1369          * Use of the TCP data offset *must* result in a value that is at
1370          * least the same size as the TCP header.
1371          */
1372         tlen = TCP_OFF(tcp) << 2;
1373         if (tlen < sizeof(tcphdr_t)) {
1374                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small);
1375                 fin->fin_flx |= FI_BAD;
1376                 return 1;
1377         }
1378
1379         flags = tcp->th_flags;
1380         fin->fin_tcpf = tcp->th_flags;
1381
1382         /*
1383          * If the urgent flag is set, then the urgent pointer must
1384          * also be set and vice versa.  Good TCP packets do not have
1385          * just one of these set.
1386          */
1387         if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) {
1388                 fin->fin_flx |= FI_BAD;
1389 #if 0
1390         } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) {
1391                 /*
1392                  * Ignore this case (#if 0) as it shows up in "real"
1393                  * traffic with bogus values in the urgent pointer field.
1394                  */
1395                 fin->fin_flx |= FI_BAD;
1396 #endif
1397         } else if (((flags & (TH_SYN|TH_FIN)) != 0) &&
1398                    ((flags & (TH_RST|TH_ACK)) == TH_RST)) {
1399                 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
1400                 fin->fin_flx |= FI_BAD;
1401 #if 1
1402         } else if (((flags & TH_SYN) != 0) &&
1403                    ((flags & (TH_URG|TH_PUSH)) != 0)) {
1404                 /*
1405                  * SYN with URG and PUSH set is not for normal TCP but it is
1406                  * possible(?) with T/TCP...but who uses T/TCP?
1407                  */
1408                 fin->fin_flx |= FI_BAD;
1409 #endif
1410         } else if (!(flags & TH_ACK)) {
1411                 /*
1412                  * If the ack bit isn't set, then either the SYN or
1413                  * RST bit must be set.  If the SYN bit is set, then
1414                  * we expect the ACK field to be 0.  If the ACK is
1415                  * not set and if URG, PSH or FIN are set, consdier
1416                  * that to indicate a bad TCP packet.
1417                  */
1418                 if ((flags == TH_SYN) && (tcp->th_ack != 0)) {
1419                         /*
1420                          * Cisco PIX sets the ACK field to a random value.
1421                          * In light of this, do not set FI_BAD until a patch
1422                          * is available from Cisco to ensure that
1423                          * interoperability between existing systems is
1424                          * achieved.
1425                          */
1426                         /*fin->fin_flx |= FI_BAD*/;
1427                 } else if (!(flags & (TH_RST|TH_SYN))) {
1428                         fin->fin_flx |= FI_BAD;
1429                 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) {
1430                         fin->fin_flx |= FI_BAD;
1431                 }
1432         }
1433         if (fin->fin_flx & FI_BAD) {
1434                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags);
1435                 return 1;
1436         }
1437
1438         /*
1439          * At this point, it's not exactly clear what is to be gained by
1440          * marking up which TCP options are and are not present.  The one we
1441          * are most interested in is the TCP window scale.  This is only in
1442          * a SYN packet [RFC1323] so we don't need this here...?
1443          * Now if we were to analyse the header for passive fingerprinting,
1444          * then that might add some weight to adding this...
1445          */
1446         if (tlen == sizeof(tcphdr_t)) {
1447                 return 0;
1448         }
1449
1450         if (ipf_pr_pullup(fin, tlen) == -1) {
1451                 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
1452                 return -1;
1453         }
1454
1455 #if 0
1456         tcp = fin->fin_dp;
1457         ip = fin->fin_ip;
1458         s = (u_char *)(tcp + 1);
1459         off = IP_HL(ip) << 2;
1460 # ifdef _KERNEL
1461         if (fin->fin_mp != NULL) {
1462                 mb_t *m = *fin->fin_mp;
1463
1464                 if (off + tlen > M_LEN(m))
1465                         return;
1466         }
1467 # endif
1468         for (tlen -= (int)sizeof(*tcp); tlen > 0; ) {
1469                 opt = *s;
1470                 if (opt == '\0')
1471                         break;
1472                 else if (opt == TCPOPT_NOP)
1473                         ol = 1;
1474                 else {
1475                         if (tlen < 2)
1476                                 break;
1477                         ol = (int)*(s + 1);
1478                         if (ol < 2 || ol > tlen)
1479                                 break;
1480                 }
1481
1482                 for (i = 9, mv = 4; mv >= 0; ) {
1483                         op = ipopts + i;
1484                         if (opt == (u_char)op->ol_val) {
1485                                 optmsk |= op->ol_bit;
1486                                 break;
1487                         }
1488                 }
1489                 tlen -= ol;
1490                 s += ol;
1491         }
1492 #endif /* 0 */
1493
1494         return 0;
1495 }
1496
1497
1498
1499 /* ------------------------------------------------------------------------ */
1500 /* Function:    ipf_pr_udpcommon                                            */
1501 /* Returns:     int    - 0 = header ok, 1 = bad packet                      */
1502 /* Parameters:  fin(I) - pointer to packet information                      */
1503 /*                                                                          */
1504 /* Extract the UDP source and destination ports, if present.  If compiled   */
1505 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid.          */
1506 /* ------------------------------------------------------------------------ */
1507 static INLINE int
1508 ipf_pr_udpcommon(fin)
1509         fr_info_t *fin;
1510 {
1511         udphdr_t *udp;
1512
1513         fin->fin_flx |= FI_TCPUDP;
1514
1515         if (!fin->fin_off && (fin->fin_dlen > 3)) {
1516                 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) {
1517                         ipf_main_softc_t *softc = fin->fin_main_soft;
1518
1519                         fin->fin_flx |= FI_SHORT;
1520                         LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup);
1521                         return 1;
1522                 }
1523
1524                 udp = fin->fin_dp;
1525
1526                 fin->fin_sport = ntohs(udp->uh_sport);
1527                 fin->fin_dport = ntohs(udp->uh_dport);
1528         }
1529
1530         return 0;
1531 }
1532
1533
1534 /* ------------------------------------------------------------------------ */
1535 /* Function:    ipf_pr_tcp                                                  */
1536 /* Returns:     void                                                        */
1537 /* Parameters:  fin(I) - pointer to packet information                      */
1538 /*                                                                          */
1539 /* IPv4 Only                                                                */
1540 /* Analyse the packet for IPv4/TCP properties.                              */
1541 /* ------------------------------------------------------------------------ */
1542 static INLINE void
1543 ipf_pr_tcp(fin)
1544         fr_info_t *fin;
1545 {
1546
1547         ipf_pr_short(fin, sizeof(tcphdr_t));
1548
1549         if (ipf_pr_tcpcommon(fin) == 0)
1550                 ipf_checkv4sum(fin);
1551 }
1552
1553
1554 /* ------------------------------------------------------------------------ */
1555 /* Function:    ipf_pr_udp                                                  */
1556 /* Returns:     void                                                        */
1557 /* Parameters:  fin(I) - pointer to packet information                      */
1558 /*                                                                          */
1559 /* IPv4 Only                                                                */
1560 /* Analyse the packet for IPv4/UDP properties.                              */
1561 /* ------------------------------------------------------------------------ */
1562 static INLINE void
1563 ipf_pr_udp(fin)
1564         fr_info_t *fin;
1565 {
1566
1567         ipf_pr_short(fin, sizeof(udphdr_t));
1568
1569         if (ipf_pr_udpcommon(fin) == 0)
1570                 ipf_checkv4sum(fin);
1571 }
1572
1573
1574 /* ------------------------------------------------------------------------ */
1575 /* Function:    ipf_pr_esp                                                  */
1576 /* Returns:     void                                                        */
1577 /* Parameters:  fin(I) - pointer to packet information                      */
1578 /*                                                                          */
1579 /* Analyse the packet for ESP properties.                                   */
1580 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
1581 /* even though the newer ESP packets must also have a sequence number that  */
1582 /* is 32bits as well, it is not possible(?) to determine the version from a */
1583 /* simple packet header.                                                    */
1584 /* ------------------------------------------------------------------------ */
1585 static INLINE void
1586 ipf_pr_esp(fin)
1587         fr_info_t *fin;
1588 {
1589
1590         if (fin->fin_off == 0) {
1591                 ipf_pr_short(fin, 8);
1592                 if (ipf_pr_pullup(fin, 8) == -1) {
1593                         ipf_main_softc_t *softc = fin->fin_main_soft;
1594
1595                         LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup);
1596                 }
1597         }
1598 }
1599
1600
1601 /* ------------------------------------------------------------------------ */
1602 /* Function:    ipf_pr_ah                                                   */
1603 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
1604 /* Parameters:  fin(I) - pointer to packet information                      */
1605 /*                                                                          */
1606 /* Analyse the packet for AH properties.                                    */
1607 /* The minimum length is taken to be the combination of all fields in the   */
1608 /* header being present and no authentication data (null algorithm used.)   */
1609 /* ------------------------------------------------------------------------ */
1610 static INLINE int
1611 ipf_pr_ah(fin)
1612         fr_info_t *fin;
1613 {
1614         ipf_main_softc_t *softc = fin->fin_main_soft;
1615         authhdr_t *ah;
1616         int len;
1617
1618         fin->fin_flx |= FI_AH;
1619         ipf_pr_short(fin, sizeof(*ah));
1620
1621         if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) {
1622                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad);
1623                 return IPPROTO_NONE;
1624         }
1625
1626         if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) {
1627                 DT(fr_v4_ah_pullup_1);
1628                 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
1629                 return IPPROTO_NONE;
1630         }
1631
1632         ah = (authhdr_t *)fin->fin_dp;
1633
1634         len = (ah->ah_plen + 2) << 2;
1635         ipf_pr_short(fin, len);
1636         if (ipf_pr_pullup(fin, len) == -1) {
1637                 DT(fr_v4_ah_pullup_2);
1638                 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
1639                 return IPPROTO_NONE;
1640         }
1641
1642         /*
1643          * Adjust fin_dp and fin_dlen for skipping over the authentication
1644          * header.
1645          */
1646         fin->fin_dp = (char *)fin->fin_dp + len;
1647         fin->fin_dlen -= len;
1648         return ah->ah_next;
1649 }
1650
1651
1652 /* ------------------------------------------------------------------------ */
1653 /* Function:    ipf_pr_gre                                                  */
1654 /* Returns:     void                                                        */
1655 /* Parameters:  fin(I) - pointer to packet information                      */
1656 /*                                                                          */
1657 /* Analyse the packet for GRE properties.                                   */
1658 /* ------------------------------------------------------------------------ */
1659 static INLINE void
1660 ipf_pr_gre(fin)
1661         fr_info_t *fin;
1662 {
1663         ipf_main_softc_t *softc = fin->fin_main_soft;
1664         grehdr_t *gre;
1665
1666         ipf_pr_short(fin, sizeof(grehdr_t));
1667
1668         if (fin->fin_off != 0) {
1669                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag);
1670                 return;
1671         }
1672
1673         if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
1674                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup);
1675                 return;
1676         }
1677
1678         gre = fin->fin_dp;
1679         if (GRE_REV(gre->gr_flags) == 1)
1680                 fin->fin_data[0] = gre->gr_call;
1681 }
1682
1683
1684 /* ------------------------------------------------------------------------ */
1685 /* Function:    ipf_pr_ipv4hdr                                              */
1686 /* Returns:     void                                                        */
1687 /* Parameters:  fin(I) - pointer to packet information                      */
1688 /*                                                                          */
1689 /* IPv4 Only                                                                */
1690 /* Analyze the IPv4 header and set fields in the fr_info_t structure.       */
1691 /* Check all options present and flag their presence if any exist.          */
1692 /* ------------------------------------------------------------------------ */
1693 static INLINE void
1694 ipf_pr_ipv4hdr(fin)
1695         fr_info_t *fin;
1696 {
1697         u_short optmsk = 0, secmsk = 0, auth = 0;
1698         int hlen, ol, mv, p, i;
1699         const struct optlist *op;
1700         u_char *s, opt;
1701         u_short off;
1702         fr_ip_t *fi;
1703         ip_t *ip;
1704
1705         fi = &fin->fin_fi;
1706         hlen = fin->fin_hlen;
1707
1708         ip = fin->fin_ip;
1709         p = ip->ip_p;
1710         fi->fi_p = p;
1711         fin->fin_crc = p;
1712         fi->fi_tos = ip->ip_tos;
1713         fin->fin_id = ip->ip_id;
1714         off = ntohs(ip->ip_off);
1715
1716         /* Get both TTL and protocol */
1717         fi->fi_p = ip->ip_p;
1718         fi->fi_ttl = ip->ip_ttl;
1719
1720         /* Zero out bits not used in IPv6 address */
1721         fi->fi_src.i6[1] = 0;
1722         fi->fi_src.i6[2] = 0;
1723         fi->fi_src.i6[3] = 0;
1724         fi->fi_dst.i6[1] = 0;
1725         fi->fi_dst.i6[2] = 0;
1726         fi->fi_dst.i6[3] = 0;
1727
1728         fi->fi_saddr = ip->ip_src.s_addr;
1729         fin->fin_crc += fi->fi_saddr;
1730         fi->fi_daddr = ip->ip_dst.s_addr;
1731         fin->fin_crc += fi->fi_daddr;
1732         if (IN_CLASSD(ntohl(fi->fi_daddr)))
1733                 fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
1734
1735         /*
1736          * set packet attribute flags based on the offset and
1737          * calculate the byte offset that it represents.
1738          */
1739         off &= IP_MF|IP_OFFMASK;
1740         if (off != 0) {
1741                 int morefrag = off & IP_MF;
1742
1743                 fi->fi_flx |= FI_FRAG;
1744                 off &= IP_OFFMASK;
1745                 if (off != 0) {
1746                         fin->fin_flx |= FI_FRAGBODY;
1747                         off <<= 3;
1748                         if ((off + fin->fin_dlen > 65535) ||
1749                             (fin->fin_dlen == 0) ||
1750                             ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
1751                                 /*
1752                                  * The length of the packet, starting at its
1753                                  * offset cannot exceed 65535 (0xffff) as the
1754                                  * length of an IP packet is only 16 bits.
1755                                  *
1756                                  * Any fragment that isn't the last fragment
1757                                  * must have a length greater than 0 and it
1758                                  * must be an even multiple of 8.
1759                                  */
1760                                 fi->fi_flx |= FI_BAD;
1761                         }
1762                 }
1763         }
1764         fin->fin_off = off;
1765
1766         /*
1767          * Call per-protocol setup and checking
1768          */
1769         if (p == IPPROTO_AH) {
1770                 /*
1771                  * Treat AH differently because we expect there to be another
1772                  * layer 4 header after it.
1773                  */
1774                 p = ipf_pr_ah(fin);
1775         }
1776
1777         switch (p)
1778         {
1779         case IPPROTO_UDP :
1780                 ipf_pr_udp(fin);
1781                 break;
1782         case IPPROTO_TCP :
1783                 ipf_pr_tcp(fin);
1784                 break;
1785         case IPPROTO_ICMP :
1786                 ipf_pr_icmp(fin);
1787                 break;
1788         case IPPROTO_ESP :
1789                 ipf_pr_esp(fin);
1790                 break;
1791         case IPPROTO_GRE :
1792                 ipf_pr_gre(fin);
1793                 break;
1794         }
1795
1796         ip = fin->fin_ip;
1797         if (ip == NULL)
1798                 return;
1799
1800         /*
1801          * If it is a standard IP header (no options), set the flag fields
1802          * which relate to options to 0.
1803          */
1804         if (hlen == sizeof(*ip)) {
1805                 fi->fi_optmsk = 0;
1806                 fi->fi_secmsk = 0;
1807                 fi->fi_auth = 0;
1808                 return;
1809         }
1810
1811         /*
1812          * So the IP header has some IP options attached.  Walk the entire
1813          * list of options present with this packet and set flags to indicate
1814          * which ones are here and which ones are not.  For the somewhat out
1815          * of date and obscure security classification options, set a flag to
1816          * represent which classification is present.
1817          */
1818         fi->fi_flx |= FI_OPTIONS;
1819
1820         for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
1821                 opt = *s;
1822                 if (opt == '\0')
1823                         break;
1824                 else if (opt == IPOPT_NOP)
1825                         ol = 1;
1826                 else {
1827                         if (hlen < 2)
1828                                 break;
1829                         ol = (int)*(s + 1);
1830                         if (ol < 2 || ol > hlen)
1831                                 break;
1832                 }
1833                 for (i = 9, mv = 4; mv >= 0; ) {
1834                         op = ipopts + i;
1835
1836                         if ((opt == (u_char)op->ol_val) && (ol > 4)) {
1837                                 u_32_t doi;
1838
1839                                 switch (opt)
1840                                 {
1841                                 case IPOPT_SECURITY :
1842                                         if (optmsk & op->ol_bit) {
1843                                                 fin->fin_flx |= FI_BAD;
1844                                         } else {
1845                                                 doi = ipf_checkripso(s);
1846                                                 secmsk = doi >> 16;
1847                                                 auth = doi & 0xffff;
1848                                         }
1849                                         break;
1850
1851                                 case IPOPT_CIPSO :
1852
1853                                         if (optmsk & op->ol_bit) {
1854                                                 fin->fin_flx |= FI_BAD;
1855                                         } else {
1856                                                 doi = ipf_checkcipso(fin,
1857                                                                      s, ol);
1858                                                 secmsk = doi >> 16;
1859                                                 auth = doi & 0xffff;
1860                                         }
1861                                         break;
1862                                 }
1863                                 optmsk |= op->ol_bit;
1864                         }
1865
1866                         if (opt < op->ol_val)
1867                                 i -= mv;
1868                         else
1869                                 i += mv;
1870                         mv--;
1871                 }
1872                 hlen -= ol;
1873                 s += ol;
1874         }
1875
1876         /*
1877          *
1878          */
1879         if (auth && !(auth & 0x0100))
1880                 auth &= 0xff00;
1881         fi->fi_optmsk = optmsk;
1882         fi->fi_secmsk = secmsk;
1883         fi->fi_auth = auth;
1884 }
1885
1886
1887 /* ------------------------------------------------------------------------ */
1888 /* Function:    ipf_checkripso                                              */
1889 /* Returns:     void                                                        */
1890 /* Parameters:  s(I)   - pointer to start of RIPSO option                   */
1891 /*                                                                          */
1892 /* ------------------------------------------------------------------------ */
1893 static u_32_t
1894 ipf_checkripso(s)
1895         u_char *s;
1896 {
1897         const struct optlist *sp;
1898         u_short secmsk = 0, auth = 0;
1899         u_char sec;
1900         int j, m;
1901
1902         sec = *(s + 2); /* classification */
1903         for (j = 3, m = 2; m >= 0; ) {
1904                 sp = secopt + j;
1905                 if (sec == sp->ol_val) {
1906                         secmsk |= sp->ol_bit;
1907                         auth = *(s + 3);
1908                         auth *= 256;
1909                         auth += *(s + 4);
1910                         break;
1911                 }
1912                 if (sec < sp->ol_val)
1913                         j -= m;
1914                 else
1915                         j += m;
1916                 m--;
1917         }
1918
1919         return (secmsk << 16) | auth;
1920 }
1921
1922
1923 /* ------------------------------------------------------------------------ */
1924 /* Function:    ipf_checkcipso                                              */
1925 /* Returns:     u_32_t  - 0 = failure, else the doi from the header         */
1926 /* Parameters:  fin(IO) - pointer to packet information                     */
1927 /*              s(I)    - pointer to start of CIPSO option                  */
1928 /*              ol(I)   - length of CIPSO option field                      */
1929 /*                                                                          */
1930 /* This function returns the domain of integrity (DOI) field from the CIPSO */
1931 /* header and returns that whilst also storing the highest sensitivity      */
1932 /* value found in the fr_info_t structure.                                  */
1933 /*                                                                          */
1934 /* No attempt is made to extract the category bitmaps as these are defined  */
1935 /* by the user (rather than the protocol) and can be rather numerous on the */
1936 /* end nodes.                                                               */
1937 /* ------------------------------------------------------------------------ */
1938 static u_32_t
1939 ipf_checkcipso(fin, s, ol)
1940         fr_info_t *fin;
1941         u_char *s;
1942         int ol;
1943 {
1944         ipf_main_softc_t *softc = fin->fin_main_soft;
1945         fr_ip_t *fi;
1946         u_32_t doi;
1947         u_char *t, tag, tlen, sensitivity;
1948         int len;
1949
1950         if (ol < 6 || ol > 40) {
1951                 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad);
1952                 fin->fin_flx |= FI_BAD;
1953                 return 0;
1954         }
1955
1956         fi = &fin->fin_fi;
1957         fi->fi_sensitivity = 0;
1958         /*
1959          * The DOI field MUST be there.
1960          */
1961         bcopy(s + 2, &doi, sizeof(doi));
1962
1963         t = (u_char *)s + 6;
1964         for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) {
1965                 tag = *t;
1966                 tlen = *(t + 1);
1967                 if (tlen > len || tlen < 4 || tlen > 34) {
1968                         LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen);
1969                         fin->fin_flx |= FI_BAD;
1970                         return 0;
1971                 }
1972
1973                 sensitivity = 0;
1974                 /*
1975                  * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet
1976                  * draft (16 July 1992) that has expired.
1977                  */
1978                 if (tag == 0) {
1979                         fin->fin_flx |= FI_BAD;
1980                         continue;
1981                 } else if (tag == 1) {
1982                         if (*(t + 2) != 0) {
1983                                 fin->fin_flx |= FI_BAD;
1984                                 continue;
1985                         }
1986                         sensitivity = *(t + 3);
1987                         /* Category bitmap for categories 0-239 */
1988
1989                 } else if (tag == 4) {
1990                         if (*(t + 2) != 0) {
1991                                 fin->fin_flx |= FI_BAD;
1992                                 continue;
1993                         }
1994                         sensitivity = *(t + 3);
1995                         /* Enumerated categories, 16bits each, upto 15 */
1996
1997                 } else if (tag == 5) {
1998                         if (*(t + 2) != 0) {
1999                                 fin->fin_flx |= FI_BAD;
2000                                 continue;
2001                         }
2002                         sensitivity = *(t + 3);
2003                         /* Range of categories (2*16bits), up to 7 pairs */
2004
2005                 } else if (tag > 127) {
2006                         /* Custom defined DOI */
2007                         ;
2008                 } else {
2009                         fin->fin_flx |= FI_BAD;
2010                         continue;
2011                 }
2012
2013                 if (sensitivity > fi->fi_sensitivity)
2014                         fi->fi_sensitivity = sensitivity;
2015         }
2016
2017         return doi;
2018 }
2019
2020
2021 /* ------------------------------------------------------------------------ */
2022 /* Function:    ipf_makefrip                                                */
2023 /* Returns:     int     - 0 == packet ok, -1 == packet freed                */
2024 /* Parameters:  hlen(I) - length of IP packet header                        */
2025 /*              ip(I)   - pointer to the IP header                          */
2026 /*              fin(IO) - pointer to packet information                     */
2027 /*                                                                          */
2028 /* Compact the IP header into a structure which contains just the info.     */
2029 /* which is useful for comparing IP headers with and store this information */
2030 /* in the fr_info_t structure pointer to by fin.  At present, it is assumed */
2031 /* this function will be called with either an IPv4 or IPv6 packet.         */
2032 /* ------------------------------------------------------------------------ */
2033 int
2034 ipf_makefrip(hlen, ip, fin)
2035         int hlen;
2036         ip_t *ip;
2037         fr_info_t *fin;
2038 {
2039         ipf_main_softc_t *softc = fin->fin_main_soft;
2040         int v;
2041
2042         fin->fin_depth = 0;
2043         fin->fin_hlen = (u_short)hlen;
2044         fin->fin_ip = ip;
2045         fin->fin_rule = 0xffffffff;
2046         fin->fin_group[0] = -1;
2047         fin->fin_group[1] = '\0';
2048         fin->fin_dp = (char *)ip + hlen;
2049
2050         v = fin->fin_v;
2051         if (v == 4) {
2052                 fin->fin_plen = ntohs(ip->ip_len);
2053                 fin->fin_dlen = fin->fin_plen - hlen;
2054                 ipf_pr_ipv4hdr(fin);
2055 #ifdef  USE_INET6
2056         } else if (v == 6) {
2057                 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
2058                 fin->fin_dlen = fin->fin_plen;
2059                 fin->fin_plen += hlen;
2060
2061                 ipf_pr_ipv6hdr(fin);
2062 #endif
2063         }
2064         if (fin->fin_ip == NULL) {
2065                 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed);
2066                 return -1;
2067         }
2068         return 0;
2069 }
2070
2071
2072 /* ------------------------------------------------------------------------ */
2073 /* Function:    ipf_portcheck                                               */
2074 /* Returns:     int - 1 == port matched, 0 == port match failed             */
2075 /* Parameters:  frp(I) - pointer to port check `expression'                 */
2076 /*              pop(I) - port number to evaluate                            */
2077 /*                                                                          */
2078 /* Perform a comparison of a port number against some other(s), using a     */
2079 /* structure with compare information stored in it.                         */
2080 /* ------------------------------------------------------------------------ */
2081 static INLINE int
2082 ipf_portcheck(frp, pop)
2083         frpcmp_t *frp;
2084         u_32_t pop;
2085 {
2086         int err = 1;
2087         u_32_t po;
2088
2089         po = frp->frp_port;
2090
2091         /*
2092          * Do opposite test to that required and continue if that succeeds.
2093          */
2094         switch (frp->frp_cmp)
2095         {
2096         case FR_EQUAL :
2097                 if (pop != po) /* EQUAL */
2098                         err = 0;
2099                 break;
2100         case FR_NEQUAL :
2101                 if (pop == po) /* NOTEQUAL */
2102                         err = 0;
2103                 break;
2104         case FR_LESST :
2105                 if (pop >= po) /* LESSTHAN */
2106                         err = 0;
2107                 break;
2108         case FR_GREATERT :
2109                 if (pop <= po) /* GREATERTHAN */
2110                         err = 0;
2111                 break;
2112         case FR_LESSTE :
2113                 if (pop > po) /* LT or EQ */
2114                         err = 0;
2115                 break;
2116         case FR_GREATERTE :
2117                 if (pop < po) /* GT or EQ */
2118                         err = 0;
2119                 break;
2120         case FR_OUTRANGE :
2121                 if (pop >= po && pop <= frp->frp_top) /* Out of range */
2122                         err = 0;
2123                 break;
2124         case FR_INRANGE :
2125                 if (pop <= po || pop >= frp->frp_top) /* In range */
2126                         err = 0;
2127                 break;
2128         case FR_INCRANGE :
2129                 if (pop < po || pop > frp->frp_top) /* Inclusive range */
2130                         err = 0;
2131                 break;
2132         default :
2133                 break;
2134         }
2135         return err;
2136 }
2137
2138
2139 /* ------------------------------------------------------------------------ */
2140 /* Function:    ipf_tcpudpchk                                               */
2141 /* Returns:     int - 1 == protocol matched, 0 == check failed              */
2142 /* Parameters:  fda(I) - pointer to packet information                      */
2143 /*              ft(I)  - pointer to structure with comparison data          */
2144 /*                                                                          */
2145 /* Compares the current pcket (assuming it is TCP/UDP) information with a   */
2146 /* structure containing information that we want to match against.          */
2147 /* ------------------------------------------------------------------------ */
2148 int
2149 ipf_tcpudpchk(fi, ft)
2150         fr_ip_t *fi;
2151         frtuc_t *ft;
2152 {
2153         int err = 1;
2154
2155         /*
2156          * Both ports should *always* be in the first fragment.
2157          * So far, I cannot find any cases where they can not be.
2158          *
2159          * compare destination ports
2160          */
2161         if (ft->ftu_dcmp)
2162                 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]);
2163
2164         /*
2165          * compare source ports
2166          */
2167         if (err && ft->ftu_scmp)
2168                 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]);
2169
2170         /*
2171          * If we don't have all the TCP/UDP header, then how can we
2172          * expect to do any sort of match on it ?  If we were looking for
2173          * TCP flags, then NO match.  If not, then match (which should
2174          * satisfy the "short" class too).
2175          */
2176         if (err && (fi->fi_p == IPPROTO_TCP)) {
2177                 if (fi->fi_flx & FI_SHORT)
2178                         return !(ft->ftu_tcpf | ft->ftu_tcpfm);
2179                 /*
2180                  * Match the flags ?  If not, abort this match.
2181                  */
2182                 if (ft->ftu_tcpfm &&
2183                     ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) {
2184                         FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf,
2185                                  ft->ftu_tcpfm, ft->ftu_tcpf));
2186                         err = 0;
2187                 }
2188         }
2189         return err;
2190 }
2191
2192
2193 /* ------------------------------------------------------------------------ */
2194 /* Function:    ipf_check_ipf                                               */
2195 /* Returns:     int - 0 == match, else no match                             */
2196 /* Parameters:  fin(I)     - pointer to packet information                  */
2197 /*              fr(I)      - pointer to filter rule                         */
2198 /*              portcmp(I) - flag indicating whether to attempt matching on */
2199 /*                           TCP/UDP port data.                             */
2200 /*                                                                          */
2201 /* Check to see if a packet matches an IPFilter rule.  Checks of addresses, */
2202 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
2203 /* this function.                                                           */
2204 /* ------------------------------------------------------------------------ */
2205 static INLINE int
2206 ipf_check_ipf(fin, fr, portcmp)
2207         fr_info_t *fin;
2208         frentry_t *fr;
2209         int portcmp;
2210 {
2211         u_32_t  *ld, *lm, *lip;
2212         fripf_t *fri;
2213         fr_ip_t *fi;
2214         int i;
2215
2216         fi = &fin->fin_fi;
2217         fri = fr->fr_ipf;
2218         lip = (u_32_t *)fi;
2219         lm = (u_32_t *)&fri->fri_mip;
2220         ld = (u_32_t *)&fri->fri_ip;
2221
2222         /*
2223          * first 32 bits to check coversion:
2224          * IP version, TOS, TTL, protocol
2225          */
2226         i = ((*lip & *lm) != *ld);
2227         FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
2228                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2229         if (i)
2230                 return 1;
2231
2232         /*
2233          * Next 32 bits is a constructed bitmask indicating which IP options
2234          * are present (if any) in this packet.
2235          */
2236         lip++, lm++, ld++;
2237         i = ((*lip & *lm) != *ld);
2238         FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
2239                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2240         if (i != 0)
2241                 return 1;
2242
2243         lip++, lm++, ld++;
2244         /*
2245          * Unrolled loops (4 each, for 32 bits) for address checks.
2246          */
2247         /*
2248          * Check the source address.
2249          */
2250         if (fr->fr_satype == FRI_LOOKUP) {
2251                 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr,
2252                                       fi->fi_v, lip, fin->fin_plen);
2253                 if (i == -1)
2254                         return 1;
2255                 lip += 3;
2256                 lm += 3;
2257                 ld += 3;
2258         } else {
2259                 i = ((*lip & *lm) != *ld);
2260                 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
2261                            ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2262                 if (fi->fi_v == 6) {
2263                         lip++, lm++, ld++;
2264                         i |= ((*lip & *lm) != *ld);
2265                         FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
2266                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2267                         lip++, lm++, ld++;
2268                         i |= ((*lip & *lm) != *ld);
2269                         FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
2270                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2271                         lip++, lm++, ld++;
2272                         i |= ((*lip & *lm) != *ld);
2273                         FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
2274                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2275                 } else {
2276                         lip += 3;
2277                         lm += 3;
2278                         ld += 3;
2279                 }
2280         }
2281         i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
2282         if (i != 0)
2283                 return 1;
2284
2285         /*
2286          * Check the destination address.
2287          */
2288         lip++, lm++, ld++;
2289         if (fr->fr_datype == FRI_LOOKUP) {
2290                 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr,
2291                                       fi->fi_v, lip, fin->fin_plen);
2292                 if (i == -1)
2293                         return 1;
2294                 lip += 3;
2295                 lm += 3;
2296                 ld += 3;
2297         } else {
2298                 i = ((*lip & *lm) != *ld);
2299                 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
2300                            ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2301                 if (fi->fi_v == 6) {
2302                         lip++, lm++, ld++;
2303                         i |= ((*lip & *lm) != *ld);
2304                         FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
2305                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2306                         lip++, lm++, ld++;
2307                         i |= ((*lip & *lm) != *ld);
2308                         FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
2309                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2310                         lip++, lm++, ld++;
2311                         i |= ((*lip & *lm) != *ld);
2312                         FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
2313                                    ntohl(*lip), ntohl(*lm), ntohl(*ld)));
2314                 } else {
2315                         lip += 3;
2316                         lm += 3;
2317                         ld += 3;
2318                 }
2319         }
2320         i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
2321         if (i != 0)
2322                 return 1;
2323         /*
2324          * IP addresses matched.  The next 32bits contains:
2325          * mast of old IP header security & authentication bits.
2326          */
2327         lip++, lm++, ld++;
2328         i = (*ld - (*lip & *lm));
2329         FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
2330
2331         /*
2332          * Next we have 32 bits of packet flags.
2333          */
2334         lip++, lm++, ld++;
2335         i |= (*ld - (*lip & *lm));
2336         FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
2337
2338         if (i == 0) {
2339                 /*
2340                  * If a fragment, then only the first has what we're
2341                  * looking for here...
2342                  */
2343                 if (portcmp) {
2344                         if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc))
2345                                 i = 1;
2346                 } else {
2347                         if (fr->fr_dcmp || fr->fr_scmp ||
2348                             fr->fr_tcpf || fr->fr_tcpfm)
2349                                 i = 1;
2350                         if (fr->fr_icmpm || fr->fr_icmp) {
2351                                 if (((fi->fi_p != IPPROTO_ICMP) &&
2352                                      (fi->fi_p != IPPROTO_ICMPV6)) ||
2353                                     fin->fin_off || (fin->fin_dlen < 2))
2354                                         i = 1;
2355                                 else if ((fin->fin_data[0] & fr->fr_icmpm) !=
2356                                          fr->fr_icmp) {
2357                                         FR_DEBUG(("i. %#x & %#x != %#x\n",
2358                                                  fin->fin_data[0],
2359                                                  fr->fr_icmpm, fr->fr_icmp));
2360                                         i = 1;
2361                                 }
2362                         }
2363                 }
2364         }
2365         return i;
2366 }
2367
2368
2369 /* ------------------------------------------------------------------------ */
2370 /* Function:    ipf_scanlist                                                */
2371 /* Returns:     int - result flags of scanning filter list                  */
2372 /* Parameters:  fin(I) - pointer to packet information                      */
2373 /*              pass(I) - default result to return for filtering            */
2374 /*                                                                          */
2375 /* Check the input/output list of rules for a match to the current packet.  */
2376 /* If a match is found, the value of fr_flags from the rule becomes the     */
2377 /* return value and fin->fin_fr points to the matched rule.                 */
2378 /*                                                                          */
2379 /* This function may be called recusively upto 16 times (limit inbuilt.)    */
2380 /* When unwinding, it should finish up with fin_depth as 0.                 */
2381 /*                                                                          */
2382 /* Could be per interface, but this gets real nasty when you don't have,    */
2383 /* or can't easily change, the kernel source code to .                      */
2384 /* ------------------------------------------------------------------------ */
2385 int
2386 ipf_scanlist(fin, pass)
2387         fr_info_t *fin;
2388         u_32_t pass;
2389 {
2390         ipf_main_softc_t *softc = fin->fin_main_soft;
2391         int rulen, portcmp, off, skip;
2392         struct frentry *fr, *fnext;
2393         u_32_t passt, passo;
2394
2395         /*
2396          * Do not allow nesting deeper than 16 levels.
2397          */
2398         if (fin->fin_depth >= 16)
2399                 return pass;
2400
2401         fr = fin->fin_fr;
2402
2403         /*
2404          * If there are no rules in this list, return now.
2405          */
2406         if (fr == NULL)
2407                 return pass;
2408
2409         skip = 0;
2410         portcmp = 0;
2411         fin->fin_depth++;
2412         fin->fin_fr = NULL;
2413         off = fin->fin_off;
2414
2415         if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
2416                 portcmp = 1;
2417
2418         for (rulen = 0; fr; fr = fnext, rulen++) {
2419                 fnext = fr->fr_next;
2420                 if (skip != 0) {
2421                         FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags));
2422                         skip--;
2423                         continue;
2424                 }
2425
2426                 /*
2427                  * In all checks below, a null (zero) value in the
2428                  * filter struture is taken to mean a wildcard.
2429                  *
2430                  * check that we are working for the right interface
2431                  */
2432 #ifdef  _KERNEL
2433                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
2434                         continue;
2435 #else
2436                 if (opts & (OPT_VERBOSE|OPT_DEBUG))
2437                         printf("\n");
2438                 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' :
2439                                   FR_ISPASS(pass) ? 'p' :
2440                                   FR_ISACCOUNT(pass) ? 'A' :
2441                                   FR_ISAUTH(pass) ? 'a' :
2442                                   (pass & FR_NOMATCH) ? 'n' :'b'));
2443                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
2444                         continue;
2445                 FR_VERBOSE((":i"));
2446 #endif
2447
2448                 switch (fr->fr_type)
2449                 {
2450                 case FR_T_IPF :
2451                 case FR_T_IPF_BUILTIN :
2452                         if (ipf_check_ipf(fin, fr, portcmp))
2453                                 continue;
2454                         break;
2455 #if defined(IPFILTER_BPF)
2456                 case FR_T_BPFOPC :
2457                 case FR_T_BPFOPC_BUILTIN :
2458                     {
2459                         u_char *mc;
2460                         int wlen;
2461
2462                         if (*fin->fin_mp == NULL)
2463                                 continue;
2464                         if (fin->fin_family != fr->fr_family)
2465                                 continue;
2466                         mc = (u_char *)fin->fin_m;
2467                         wlen = fin->fin_dlen + fin->fin_hlen;
2468                         if (!bpf_filter(fr->fr_data, mc, wlen, 0))
2469                                 continue;
2470                         break;
2471                     }
2472 #endif
2473                 case FR_T_CALLFUNC_BUILTIN :
2474                     {
2475                         frentry_t *f;
2476
2477                         f = (*fr->fr_func)(fin, &pass);
2478                         if (f != NULL)
2479                                 fr = f;
2480                         else
2481                                 continue;
2482                         break;
2483                     }
2484
2485                 case FR_T_IPFEXPR :
2486                 case FR_T_IPFEXPR_BUILTIN :
2487                         if (fin->fin_family != fr->fr_family)
2488                                 continue;
2489                         if (ipf_fr_matcharray(fin, fr->fr_data) == 0)
2490                                 continue;
2491                         break;
2492
2493                 default :
2494                         break;
2495                 }
2496
2497                 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
2498                         if (fin->fin_nattag == NULL)
2499                                 continue;
2500                         if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
2501                                 continue;
2502                 }
2503                 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen));
2504
2505                 passt = fr->fr_flags;
2506
2507                 /*
2508                  * If the rule is a "call now" rule, then call the function
2509                  * in the rule, if it exists and use the results from that.
2510                  * If the function pointer is bad, just make like we ignore
2511                  * it, except for increasing the hit counter.
2512                  */
2513                 if ((passt & FR_CALLNOW) != 0) {
2514                         frentry_t *frs;
2515
2516                         ATOMIC_INC64(fr->fr_hits);
2517                         if ((fr->fr_func == NULL) ||
2518                             (fr->fr_func == (ipfunc_t)-1))
2519                                 continue;
2520
2521                         frs = fin->fin_fr;
2522                         fin->fin_fr = fr;
2523                         fr = (*fr->fr_func)(fin, &passt);
2524                         if (fr == NULL) {
2525                                 fin->fin_fr = frs;
2526                                 continue;
2527                         }
2528                         passt = fr->fr_flags;
2529                 }
2530                 fin->fin_fr = fr;
2531
2532 #ifdef  IPFILTER_LOG
2533                 /*
2534                  * Just log this packet...
2535                  */
2536                 if ((passt & FR_LOGMASK) == FR_LOG) {
2537                         if (ipf_log_pkt(fin, passt) == -1) {
2538                                 if (passt & FR_LOGORBLOCK) {
2539                                         DT(frb_logfail);
2540                                         passt &= ~FR_CMDMASK;
2541                                         passt |= FR_BLOCK|FR_QUICK;
2542                                         fin->fin_reason = FRB_LOGFAIL;
2543                                 }
2544                         }
2545                 }
2546 #endif /* IPFILTER_LOG */
2547
2548                 MUTEX_ENTER(&fr->fr_lock);
2549                 fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
2550                 fr->fr_hits++;
2551                 MUTEX_EXIT(&fr->fr_lock);
2552                 fin->fin_rule = rulen;
2553
2554                 passo = pass;
2555                 if (FR_ISSKIP(passt)) {
2556                         skip = fr->fr_arg;
2557                         continue;
2558                 } else if (((passt & FR_LOGMASK) != FR_LOG) &&
2559                            ((passt & FR_LOGMASK) != FR_DECAPSULATE)) {
2560                         pass = passt;
2561                 }
2562
2563                 if (passt & (FR_RETICMP|FR_FAKEICMP))
2564                         fin->fin_icode = fr->fr_icode;
2565
2566                 if (fr->fr_group != -1) {
2567                         (void) strncpy(fin->fin_group,
2568                                        FR_NAME(fr, fr_group),
2569                                        strlen(FR_NAME(fr, fr_group)));
2570                 } else {
2571                         fin->fin_group[0] = '\0';
2572                 }
2573
2574                 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt));
2575
2576                 if (fr->fr_grphead != NULL) {
2577                         fin->fin_fr = fr->fr_grphead->fg_start;
2578                         FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead)));
2579
2580                         if (FR_ISDECAPS(passt))
2581                                 passt = ipf_decaps(fin, pass, fr->fr_icode);
2582                         else
2583                                 passt = ipf_scanlist(fin, pass);
2584
2585                         if (fin->fin_fr == NULL) {
2586                                 fin->fin_rule = rulen;
2587                                 if (fr->fr_group != -1)
2588                                         (void) strncpy(fin->fin_group,
2589                                                        fr->fr_names +
2590                                                        fr->fr_group,
2591                                                        strlen(fr->fr_names +
2592                                                               fr->fr_group));
2593                                 fin->fin_fr = fr;
2594                                 passt = pass;
2595                         }
2596                         pass = passt;
2597                 }
2598
2599                 if (pass & FR_QUICK) {
2600                         /*
2601                          * Finally, if we've asked to track state for this
2602                          * packet, set it up.  Add state for "quick" rules
2603                          * here so that if the action fails we can consider
2604                          * the rule to "not match" and keep on processing
2605                          * filter rules.
2606                          */
2607                         if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) &&
2608                             !(fin->fin_flx & FI_STATE)) {
2609                                 int out = fin->fin_out;
2610
2611                                 fin->fin_fr = fr;
2612                                 if (ipf_state_add(softc, fin, NULL, 0) == 0) {
2613                                         LBUMPD(ipf_stats[out], fr_ads);
2614                                 } else {
2615                                         LBUMPD(ipf_stats[out], fr_bads);
2616                                         pass = passo;
2617                                         continue;
2618                                 }
2619                         }
2620                         break;
2621                 }
2622         }
2623         fin->fin_depth--;
2624         return pass;
2625 }
2626
2627
2628 /* ------------------------------------------------------------------------ */
2629 /* Function:    ipf_acctpkt                                                 */
2630 /* Returns:     frentry_t* - always returns NULL                            */
2631 /* Parameters:  fin(I) - pointer to packet information                      */
2632 /*              passp(IO) - pointer to current/new filter decision (unused) */
2633 /*                                                                          */
2634 /* Checks a packet against accounting rules, if there are any for the given */
2635 /* IP protocol version.                                                     */
2636 /*                                                                          */
2637 /* N.B.: this function returns NULL to match the prototype used by other    */
2638 /* functions called from the IPFilter "mainline" in ipf_check().            */
2639 /* ------------------------------------------------------------------------ */
2640 frentry_t *
2641 ipf_acctpkt(fin, passp)
2642         fr_info_t *fin;
2643         u_32_t *passp;
2644 {
2645         ipf_main_softc_t *softc = fin->fin_main_soft;
2646         char group[FR_GROUPLEN];
2647         frentry_t *fr, *frsave;
2648         u_32_t pass, rulen;
2649
2650         passp = passp;
2651         fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
2652
2653         if (fr != NULL) {
2654                 frsave = fin->fin_fr;
2655                 bcopy(fin->fin_group, group, FR_GROUPLEN);
2656                 rulen = fin->fin_rule;
2657                 fin->fin_fr = fr;
2658                 pass = ipf_scanlist(fin, FR_NOMATCH);
2659                 if (FR_ISACCOUNT(pass)) {
2660                         LBUMPD(ipf_stats[0], fr_acct);
2661                 }
2662                 fin->fin_fr = frsave;
2663                 bcopy(group, fin->fin_group, FR_GROUPLEN);
2664                 fin->fin_rule = rulen;
2665         }
2666         return NULL;
2667 }
2668
2669
2670 /* ------------------------------------------------------------------------ */
2671 /* Function:    ipf_firewall                                                */
2672 /* Returns:     frentry_t* - returns pointer to matched rule, if no matches */
2673 /*                           were found, returns NULL.                      */
2674 /* Parameters:  fin(I) - pointer to packet information                      */
2675 /*              passp(IO) - pointer to current/new filter decision (unused) */
2676 /*                                                                          */
2677 /* Applies an appropriate set of firewall rules to the packet, to see if    */
2678 /* there are any matches.  The first check is to see if a match can be seen */
2679 /* in the cache.  If not, then search an appropriate list of rules.  Once a */
2680 /* matching rule is found, take any appropriate actions as defined by the   */
2681 /* rule - except logging.                                                   */
2682 /* ------------------------------------------------------------------------ */
2683 static frentry_t *
2684 ipf_firewall(fin, passp)
2685         fr_info_t *fin;
2686         u_32_t *passp;
2687 {
2688         ipf_main_softc_t *softc = fin->fin_main_soft;
2689         frentry_t *fr;
2690         u_32_t pass;
2691         int out;
2692
2693         out = fin->fin_out;
2694         pass = *passp;
2695
2696         /*
2697          * This rule cache will only affect packets that are not being
2698          * statefully filtered.
2699          */
2700         fin->fin_fr = softc->ipf_rules[out][softc->ipf_active];
2701         if (fin->fin_fr != NULL)
2702                 pass = ipf_scanlist(fin, softc->ipf_pass);
2703
2704         if ((pass & FR_NOMATCH)) {
2705                 LBUMPD(ipf_stats[out], fr_nom);
2706         }
2707         fr = fin->fin_fr;
2708
2709         /*
2710          * Apply packets per second rate-limiting to a rule as required.
2711          */
2712         if ((fr != NULL) && (fr->fr_pps != 0) &&
2713             !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
2714                 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr);
2715                 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST);
2716                 pass |= FR_BLOCK;
2717                 LBUMPD(ipf_stats[out], fr_ppshit);
2718                 fin->fin_reason = FRB_PPSRATE;
2719         }
2720
2721         /*
2722          * If we fail to add a packet to the authorization queue, then we
2723          * drop the packet later.  However, if it was added then pretend
2724          * we've dropped it already.
2725          */
2726         if (FR_ISAUTH(pass)) {
2727                 if (ipf_auth_new(fin->fin_m, fin) != 0) {
2728                         DT1(frb_authnew, fr_info_t *, fin);
2729                         fin->fin_m = *fin->fin_mp = NULL;
2730                         fin->fin_reason = FRB_AUTHNEW;
2731                         fin->fin_error = 0;
2732                 } else {
2733                         IPFERROR(1);
2734                         fin->fin_error = ENOSPC;
2735                 }
2736         }
2737
2738         if ((fr != NULL) && (fr->fr_func != NULL) &&
2739             (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW))
2740                 (void) (*fr->fr_func)(fin, &pass);
2741
2742         /*
2743          * If a rule is a pre-auth rule, check again in the list of rules
2744          * loaded for authenticated use.  It does not particulary matter
2745          * if this search fails because a "preauth" result, from a rule,
2746          * is treated as "not a pass", hence the packet is blocked.
2747          */
2748         if (FR_ISPREAUTH(pass)) {
2749                 pass = ipf_auth_pre_scanlist(softc, fin, pass);
2750         }
2751
2752         /*
2753          * If the rule has "keep frag" and the packet is actually a fragment,
2754          * then create a fragment state entry.
2755          */
2756         if (pass & FR_KEEPFRAG) {
2757                 if (fin->fin_flx & FI_FRAG) {
2758                         if (ipf_frag_new(softc, fin, pass) == -1) {
2759                                 LBUMP(ipf_stats[out].fr_bnfr);
2760                         } else {
2761                                 LBUMP(ipf_stats[out].fr_nfr);
2762                         }
2763                 } else {
2764                         LBUMP(ipf_stats[out].fr_cfr);
2765                 }
2766         }
2767
2768         fr = fin->fin_fr;
2769         *passp = pass;
2770
2771         return fr;
2772 }
2773
2774
2775 /* ------------------------------------------------------------------------ */
2776 /* Function:    ipf_check                                                   */
2777 /* Returns:     int -  0 == packet allowed through,                         */
2778 /*              User space:                                                 */
2779 /*                    -1 == packet blocked                                  */
2780 /*                     1 == packet not matched                              */
2781 /*                    -2 == requires authentication                         */
2782 /*              Kernel:                                                     */
2783 /*                   > 0 == filter error # for packet                       */
2784 /* Parameters: ctx(I)  - pointer to the instance context                    */
2785 /*             ip(I)   - pointer to start of IPv4/6 packet                  */
2786 /*             hlen(I) - length of header                                   */
2787 /*             ifp(I)  - pointer to interface this packet is on             */
2788 /*             out(I)  - 0 == packet going in, 1 == packet going out        */
2789 /*             mp(IO)  - pointer to caller's buffer pointer that holds this */
2790 /*                       IP packet.                                         */
2791 /* Solaris & HP-UX ONLY :                                                   */
2792 /*             qpi(I)  - pointer to STREAMS queue information for this      */
2793 /*                       interface & direction.                             */
2794 /*                                                                          */
2795 /* ipf_check() is the master function for all IPFilter packet processing.   */
2796 /* It orchestrates: Network Address Translation (NAT), checking for packet  */
2797 /* authorisation (or pre-authorisation), presence of related state info.,   */
2798 /* generating log entries, IP packet accounting, routing of packets as      */
2799 /* directed by firewall rules and of course whether or not to allow the     */
2800 /* packet to be further processed by the kernel.                            */
2801 /*                                                                          */
2802 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer  */
2803 /* freed.  Packets passed may be returned with the pointer pointed to by    */
2804 /* by "mp" changed to a new buffer.                                         */
2805 /* ------------------------------------------------------------------------ */
2806 int
2807 ipf_check(ctx, ip, hlen, ifp, out
2808 #if defined(_KERNEL) && defined(MENTAT)
2809         , qif, mp)
2810         void *qif;
2811 #else
2812         , mp)
2813 #endif
2814         mb_t **mp;
2815         ip_t *ip;
2816         int hlen;
2817         void *ifp;
2818         int out;
2819         void *ctx;
2820 {
2821         /*
2822          * The above really sucks, but short of writing a diff
2823          */
2824         ipf_main_softc_t *softc = ctx;
2825         fr_info_t frinfo;
2826         fr_info_t *fin = &frinfo;
2827         u_32_t pass = softc->ipf_pass;
2828         frentry_t *fr = NULL;
2829         int v = IP_V(ip);
2830         mb_t *mc = NULL;
2831         mb_t *m;
2832         /*
2833          * The first part of ipf_check() deals with making sure that what goes
2834          * into the filtering engine makes some sense.  Information about the
2835          * the packet is distilled, collected into a fr_info_t structure and
2836          * the an attempt to ensure the buffer the packet is in is big enough
2837          * to hold all the required packet headers.
2838          */
2839 #ifdef  _KERNEL
2840 # ifdef MENTAT
2841         qpktinfo_t *qpi = qif;
2842
2843 #  ifdef __sparc
2844         if ((u_int)ip & 0x3)
2845                 return 2;
2846 #  endif
2847 # else
2848         SPL_INT(s);
2849 # endif
2850
2851         if (softc->ipf_running <= 0) {
2852                 return 0;
2853         }
2854
2855         bzero((char *)fin, sizeof(*fin));
2856
2857 # ifdef MENTAT
2858         if (qpi->qpi_flags & QF_BROADCAST)
2859                 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2860         if (qpi->qpi_flags & QF_MULTICAST)
2861                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2862         m = qpi->qpi_m;
2863         fin->fin_qfm = m;
2864         fin->fin_qpi = qpi;
2865 # else /* MENTAT */
2866
2867         m = *mp;
2868
2869 #  if defined(M_MCAST)
2870         if ((m->m_flags & M_MCAST) != 0)
2871                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2872 #  endif
2873 #  if defined(M_MLOOP)
2874         if ((m->m_flags & M_MLOOP) != 0)
2875                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2876 #  endif
2877 #  if defined(M_BCAST)
2878         if ((m->m_flags & M_BCAST) != 0)
2879                 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2880 #  endif
2881 #  ifdef M_CANFASTFWD
2882         /*
2883          * XXX For now, IP Filter and fast-forwarding of cached flows
2884          * XXX are mutually exclusive.  Eventually, IP Filter should
2885          * XXX get a "can-fast-forward" filter rule.
2886          */
2887         m->m_flags &= ~M_CANFASTFWD;
2888 #  endif /* M_CANFASTFWD */
2889 #  if defined(CSUM_DELAY_DATA) && (!defined(__FreeBSD_version) || \
2890                                    (__FreeBSD_version < 501108))
2891         /*
2892          * disable delayed checksums.
2893          */
2894         if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
2895                 in_delayed_cksum(m);
2896                 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
2897         }
2898 #  endif /* CSUM_DELAY_DATA */
2899 # endif /* MENTAT */
2900 #else
2901         bzero((char *)fin, sizeof(*fin));
2902         m = *mp;
2903 # if defined(M_MCAST)
2904         if ((m->m_flags & M_MCAST) != 0)
2905                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2906 # endif
2907 # if defined(M_MLOOP)
2908         if ((m->m_flags & M_MLOOP) != 0)
2909                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2910 # endif
2911 # if defined(M_BCAST)
2912         if ((m->m_flags & M_BCAST) != 0)
2913                 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2914 # endif
2915 #endif /* _KERNEL */
2916
2917         fin->fin_v = v;
2918         fin->fin_m = m;
2919         fin->fin_ip = ip;
2920         fin->fin_mp = mp;
2921         fin->fin_out = out;
2922         fin->fin_ifp = ifp;
2923         fin->fin_error = ENETUNREACH;
2924         fin->fin_hlen = (u_short)hlen;
2925         fin->fin_dp = (char *)ip + hlen;
2926         fin->fin_main_soft = softc;
2927
2928         fin->fin_ipoff = (char *)ip - MTOD(m, char *);
2929
2930         SPL_NET(s);
2931
2932 #ifdef  USE_INET6
2933         if (v == 6) {
2934                 LBUMP(ipf_stats[out].fr_ipv6);
2935                 /*
2936                  * Jumbo grams are quite likely too big for internal buffer
2937                  * structures to handle comfortably, for now, so just drop
2938                  * them.
2939                  */
2940                 if (((ip6_t *)ip)->ip6_plen == 0) {
2941                         DT1(frb_jumbo, ip6_t *, (ip6_t *)ip);
2942                         pass = FR_BLOCK|FR_NOMATCH;
2943                         fin->fin_reason = FRB_JUMBO;
2944                         goto finished;
2945                 }
2946                 fin->fin_family = AF_INET6;
2947         } else
2948 #endif
2949         {
2950                 fin->fin_family = AF_INET;
2951         }
2952
2953         if (ipf_makefrip(hlen, ip, fin) == -1) {
2954                 DT1(frb_makefrip, fr_info_t *, fin);
2955                 pass = FR_BLOCK|FR_NOMATCH;
2956                 fin->fin_reason = FRB_MAKEFRIP;
2957                 goto finished;
2958         }
2959
2960         /*
2961          * For at least IPv6 packets, if a m_pullup() fails then this pointer
2962          * becomes NULL and so we have no packet to free.
2963          */
2964         if (*fin->fin_mp == NULL)
2965                 goto finished;
2966
2967         if (!out) {
2968                 if (v == 4) {
2969                         if (softc->ipf_chksrc && !ipf_verifysrc(fin)) {
2970                                 LBUMPD(ipf_stats[0], fr_v4_badsrc);
2971                                 fin->fin_flx |= FI_BADSRC;
2972                         }
2973                         if (fin->fin_ip->ip_ttl < softc->ipf_minttl) {
2974                                 LBUMPD(ipf_stats[0], fr_v4_badttl);
2975                                 fin->fin_flx |= FI_LOWTTL;
2976                         }
2977                 }
2978 #ifdef USE_INET6
2979                 else  if (v == 6) {
2980                         if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) {
2981                                 LBUMPD(ipf_stats[0], fr_v6_badttl);
2982                                 fin->fin_flx |= FI_LOWTTL;
2983                         }
2984                 }
2985 #endif
2986         }
2987
2988         if (fin->fin_flx & FI_SHORT) {
2989                 LBUMPD(ipf_stats[out], fr_short);
2990         }
2991
2992         READ_ENTER(&softc->ipf_mutex);
2993
2994         if (!out) {
2995                 switch (fin->fin_v)
2996                 {
2997                 case 4 :
2998                         if (ipf_nat_checkin(fin, &pass) == -1) {
2999                                 goto filterdone;
3000                         }
3001                         break;
3002 #ifdef USE_INET6
3003                 case 6 :
3004                         if (ipf_nat6_checkin(fin, &pass) == -1) {
3005                                 goto filterdone;
3006                         }
3007                         break;
3008 #endif
3009                 default :
3010                         break;
3011                 }
3012         }
3013         /*
3014          * Check auth now.
3015          * If a packet is found in the auth table, then skip checking
3016          * the access lists for permission but we do need to consider
3017          * the result as if it were from the ACL's.  In addition, being
3018          * found in the auth table means it has been seen before, so do
3019          * not pass it through accounting (again), lest it be counted twice.
3020          */
3021         fr = ipf_auth_check(fin, &pass);
3022         if (!out && (fr == NULL))
3023                 (void) ipf_acctpkt(fin, NULL);
3024
3025         if (fr == NULL) {
3026                 if ((fin->fin_flx & FI_FRAG) != 0)
3027                         fr = ipf_frag_known(fin, &pass);
3028
3029                 if (fr == NULL)
3030                         fr = ipf_state_check(fin, &pass);
3031         }
3032
3033         if ((pass & FR_NOMATCH) || (fr == NULL))
3034                 fr = ipf_firewall(fin, &pass);
3035
3036         /*
3037          * If we've asked to track state for this packet, set it up.
3038          * Here rather than ipf_firewall because ipf_checkauth may decide
3039          * to return a packet for "keep state"
3040          */
3041         if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) &&
3042             !(fin->fin_flx & FI_STATE)) {
3043                 if (ipf_state_add(softc, fin, NULL, 0) == 0) {
3044                         LBUMP(ipf_stats[out].fr_ads);
3045                 } else {
3046                         LBUMP(ipf_stats[out].fr_bads);
3047                         if (FR_ISPASS(pass)) {
3048                                 DT(frb_stateadd);
3049                                 pass &= ~FR_CMDMASK;
3050                                 pass |= FR_BLOCK;
3051                                 fin->fin_reason = FRB_STATEADD;
3052                         }
3053                 }
3054         }
3055
3056         fin->fin_fr = fr;
3057         if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) {
3058                 fin->fin_dif = &fr->fr_dif;
3059                 fin->fin_tif = &fr->fr_tifs[fin->fin_rev];
3060         }
3061
3062         /*
3063          * Only count/translate packets which will be passed on, out the
3064          * interface.
3065          */
3066         if (out && FR_ISPASS(pass)) {
3067                 (void) ipf_acctpkt(fin, NULL);
3068
3069                 switch (fin->fin_v)
3070                 {
3071                 case 4 :
3072                         if (ipf_nat_checkout(fin, &pass) == -1) {
3073                                 ;
3074                         } else if ((softc->ipf_update_ipid != 0) && (v == 4)) {
3075                                 if (ipf_updateipid(fin) == -1) {
3076                                         DT(frb_updateipid);
3077                                         LBUMP(ipf_stats[1].fr_ipud);
3078                                         pass &= ~FR_CMDMASK;
3079                                         pass |= FR_BLOCK;
3080                                         fin->fin_reason = FRB_UPDATEIPID;
3081                                 } else {
3082                                         LBUMP(ipf_stats[0].fr_ipud);
3083                                 }
3084                         }
3085                         break;
3086 #ifdef USE_INET6
3087                 case 6 :
3088                         (void) ipf_nat6_checkout(fin, &pass);
3089                         break;
3090 #endif
3091                 default :
3092                         break;
3093                 }
3094         }
3095
3096 filterdone:
3097 #ifdef  IPFILTER_LOG
3098         if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
3099                 (void) ipf_dolog(fin, &pass);
3100         }
3101 #endif
3102
3103         /*
3104          * The FI_STATE flag is cleared here so that calling ipf_state_check
3105          * will work when called from inside of fr_fastroute.  Although
3106          * there is a similar flag, FI_NATED, for NAT, it does have the same
3107          * impact on code execution.
3108          */
3109         fin->fin_flx &= ~FI_STATE;
3110
3111 #if defined(FASTROUTE_RECURSION)
3112         /*
3113          * Up the reference on fr_lock and exit ipf_mutex. The generation of
3114          * a packet below can sometimes cause a recursive call into IPFilter.
3115          * On those platforms where that does happen, we need to hang onto
3116          * the filter rule just in case someone decides to remove or flush it
3117          * in the meantime.
3118          */
3119         if (fr != NULL) {
3120                 MUTEX_ENTER(&fr->fr_lock);
3121                 fr->fr_ref++;
3122                 MUTEX_EXIT(&fr->fr_lock);
3123         }
3124
3125         RWLOCK_EXIT(&softc->ipf_mutex);
3126 #endif
3127
3128         if ((pass & FR_RETMASK) != 0) {
3129                 /*
3130                  * Should we return an ICMP packet to indicate error
3131                  * status passing through the packet filter ?
3132                  * WARNING: ICMP error packets AND TCP RST packets should
3133                  * ONLY be sent in repsonse to incoming packets.  Sending
3134                  * them in response to outbound packets can result in a
3135                  * panic on some operating systems.
3136                  */
3137                 if (!out) {
3138                         if (pass & FR_RETICMP) {
3139                                 int dst;
3140
3141                                 if ((pass & FR_RETMASK) == FR_FAKEICMP)
3142                                         dst = 1;
3143                                 else
3144                                         dst = 0;
3145                                 (void) ipf_send_icmp_err(ICMP_UNREACH, fin,
3146                                                          dst);
3147                                 LBUMP(ipf_stats[0].fr_ret);
3148                         } else if (((pass & FR_RETMASK) == FR_RETRST) &&
3149                                    !(fin->fin_flx & FI_SHORT)) {
3150                                 if (((fin->fin_flx & FI_OOW) != 0) ||
3151                                     (ipf_send_reset(fin) == 0)) {
3152                                         LBUMP(ipf_stats[1].fr_ret);
3153                                 }
3154                         }
3155
3156                         /*
3157                          * When using return-* with auth rules, the auth code
3158                          * takes over disposing of this packet.
3159                          */
3160                         if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
3161                                 DT1(frb_authcapture, fr_info_t *, fin);
3162                                 fin->fin_m = *fin->fin_mp = NULL;
3163                                 fin->fin_reason = FRB_AUTHCAPTURE;
3164                                 m = NULL;
3165                         }
3166                 } else {
3167                         if (pass & FR_RETRST) {
3168                                 fin->fin_error = ECONNRESET;
3169                         }
3170                 }
3171         }
3172
3173         /*
3174          * After the above so that ICMP unreachables and TCP RSTs get
3175          * created properly.
3176          */
3177         if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
3178                 ipf_nat_uncreate(fin);
3179
3180         /*
3181          * If we didn't drop off the bottom of the list of rules (and thus
3182          * the 'current' rule fr is not NULL), then we may have some extra
3183          * instructions about what to do with a packet.
3184          * Once we're finished return to our caller, freeing the packet if
3185          * we are dropping it.
3186          */
3187         if (fr != NULL) {
3188                 frdest_t *fdp;
3189
3190                 /*
3191                  * Generate a duplicated packet first because ipf_fastroute
3192                  * can lead to fin_m being free'd... not good.
3193                  */
3194                 fdp = fin->fin_dif;
3195                 if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
3196                     (fdp->fd_ptr != (void *)-1)) {
3197                         mc = M_COPY(fin->fin_m);
3198                         if (mc != NULL)
3199                                 ipf_fastroute(mc, &mc, fin, fdp);
3200                 }
3201
3202                 fdp = fin->fin_tif;
3203                 if (!out && (pass & FR_FASTROUTE)) {
3204                         /*
3205                          * For fastroute rule, no destination interface defined
3206                          * so pass NULL as the frdest_t parameter
3207                          */
3208                         (void) ipf_fastroute(fin->fin_m, mp, fin, NULL);
3209                         m = *mp = NULL;
3210                 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
3211                            (fdp->fd_ptr != (struct ifnet *)-1)) {
3212                         /* this is for to rules: */
3213                         ipf_fastroute(fin->fin_m, mp, fin, fdp);
3214                         m = *mp = NULL;
3215                 }
3216
3217 #if defined(FASTROUTE_RECURSION)
3218                 (void) ipf_derefrule(softc, &fr);
3219 #endif
3220         }
3221 #if !defined(FASTROUTE_RECURSION)
3222         RWLOCK_EXIT(&softc->ipf_mutex);
3223 #endif
3224
3225 finished:
3226         if (!FR_ISPASS(pass)) {
3227                 LBUMP(ipf_stats[out].fr_block);
3228                 if (*mp != NULL) {
3229 #ifdef _KERNEL
3230                         FREE_MB_T(*mp);
3231 #endif
3232                         m = *mp = NULL;
3233                 }
3234         } else {
3235                 LBUMP(ipf_stats[out].fr_pass);
3236 #if defined(_KERNEL) && defined(__sgi)
3237                 if ((fin->fin_hbuf != NULL) &&
3238                     (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) {
3239                         COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf);
3240                 }
3241 #endif
3242         }
3243
3244         SPL_X(s);
3245
3246 #ifdef _KERNEL
3247         if (FR_ISPASS(pass))
3248                 return 0;
3249         LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
3250         return fin->fin_error;
3251 #else /* _KERNEL */
3252         if (*mp != NULL)
3253                 (*mp)->mb_ifp = fin->fin_ifp;
3254         blockreason = fin->fin_reason;
3255         FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
3256         /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/
3257                 if ((pass & FR_NOMATCH) != 0)
3258                         return 1;
3259
3260         if ((pass & FR_RETMASK) != 0)
3261                 switch (pass & FR_RETMASK)
3262                 {
3263                 case FR_RETRST :
3264                         return 3;
3265                 case FR_RETICMP :
3266                         return 4;
3267                 case FR_FAKEICMP :
3268                         return 5;
3269                 }
3270
3271         switch (pass & FR_CMDMASK)
3272         {
3273         case FR_PASS :
3274                 return 0;
3275         case FR_BLOCK :
3276                 return -1;
3277         case FR_AUTH :
3278                 return -2;
3279         case FR_ACCOUNT :
3280                 return -3;
3281         case FR_PREAUTH :
3282                 return -4;
3283         }
3284         return 2;
3285 #endif /* _KERNEL */
3286 }
3287
3288
3289 #ifdef  IPFILTER_LOG
3290 /* ------------------------------------------------------------------------ */
3291 /* Function:    ipf_dolog                                                   */
3292 /* Returns:     frentry_t* - returns contents of fin_fr (no change made)    */
3293 /* Parameters:  fin(I) - pointer to packet information                      */
3294 /*              passp(IO) - pointer to current/new filter decision (unused) */
3295 /*                                                                          */
3296 /* Checks flags set to see how a packet should be logged, if it is to be    */
3297 /* logged.  Adjust statistics based on its success or not.                  */
3298 /* ------------------------------------------------------------------------ */
3299 frentry_t *
3300 ipf_dolog(fin, passp)
3301         fr_info_t *fin;
3302         u_32_t *passp;
3303 {
3304         ipf_main_softc_t *softc = fin->fin_main_soft;
3305         u_32_t pass;
3306         int out;
3307
3308         out = fin->fin_out;
3309         pass = *passp;
3310
3311         if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
3312                 pass |= FF_LOGNOMATCH;
3313                 LBUMPD(ipf_stats[out], fr_npkl);
3314                 goto logit;
3315
3316         } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
3317             (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) {
3318                 if ((pass & FR_LOGMASK) != FR_LOGP)
3319                         pass |= FF_LOGPASS;
3320                 LBUMPD(ipf_stats[out], fr_ppkl);
3321                 goto logit;
3322
3323         } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
3324                    (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) {
3325                 if ((pass & FR_LOGMASK) != FR_LOGB)
3326                         pass |= FF_LOGBLOCK;
3327                 LBUMPD(ipf_stats[out], fr_bpkl);
3328
3329 logit:
3330                 if (ipf_log_pkt(fin, pass) == -1) {
3331                         /*
3332                          * If the "or-block" option has been used then
3333                          * block the packet if we failed to log it.
3334                          */
3335                         if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) {
3336                                 DT1(frb_logfail2, u_int, pass);
3337                                 pass &= ~FR_CMDMASK;
3338                                 pass |= FR_BLOCK;
3339                                 fin->fin_reason = FRB_LOGFAIL2;
3340                         }
3341                 }
3342                 *passp = pass;
3343         }
3344
3345         return fin->fin_fr;
3346 }
3347 #endif /* IPFILTER_LOG */
3348
3349
3350 /* ------------------------------------------------------------------------ */
3351 /* Function:    ipf_cksum                                                   */
3352 /* Returns:     u_short - IP header checksum                                */
3353 /* Parameters:  addr(I) - pointer to start of buffer to checksum            */
3354 /*              len(I)  - length of buffer in bytes                         */
3355 /*                                                                          */
3356 /* Calculate the two's complement 16 bit checksum of the buffer passed.     */
3357 /*                                                                          */
3358 /* N.B.: addr should be 16bit aligned.                                      */
3359 /* ------------------------------------------------------------------------ */
3360 u_short
3361 ipf_cksum(addr, len)
3362         u_short *addr;
3363         int len;
3364 {
3365         u_32_t sum = 0;
3366
3367         for (sum = 0; len > 1; len -= 2)
3368                 sum += *addr++;
3369
3370         /* mop up an odd byte, if necessary */
3371         if (len == 1)
3372                 sum += *(u_char *)addr;
3373
3374         /*
3375          * add back carry outs from top 16 bits to low 16 bits
3376          */
3377         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
3378         sum += (sum >> 16);                     /* add carry */
3379         return (u_short)(~sum);
3380 }
3381
3382
3383 /* ------------------------------------------------------------------------ */
3384 /* Function:    fr_cksum                                                    */
3385 /* Returns:     u_short - layer 4 checksum                                  */
3386 /* Parameters:  fin(I)     - pointer to packet information                  */
3387 /*              ip(I)      - pointer to IP header                           */
3388 /*              l4proto(I) - protocol to caclulate checksum for             */
3389 /*              l4hdr(I)   - pointer to layer 4 header                      */
3390 /*                                                                          */
3391 /* Calculates the TCP checksum for the packet held in "m", using the data   */
3392 /* in the IP header "ip" to seed it.                                        */
3393 /*                                                                          */
3394 /* NB: This function assumes we've pullup'd enough for all of the IP header */
3395 /* and the TCP header.  We also assume that data blocks aren't allocated in */
3396 /* odd sizes.                                                               */
3397 /*                                                                          */
3398 /* Expects ip_len and ip_off to be in network byte order when called.       */
3399 /* ------------------------------------------------------------------------ */
3400 u_short
3401 fr_cksum(fin, ip, l4proto, l4hdr)
3402         fr_info_t *fin;
3403         ip_t *ip;
3404         int l4proto;
3405         void *l4hdr;
3406 {
3407         u_short *sp, slen, sumsave, *csump;
3408         u_int sum, sum2;
3409         int hlen;
3410         int off;
3411 #ifdef  USE_INET6
3412         ip6_t *ip6;
3413 #endif
3414
3415         csump = NULL;
3416         sumsave = 0;
3417         sp = NULL;
3418         slen = 0;
3419         hlen = 0;
3420         sum = 0;
3421
3422         sum = htons((u_short)l4proto);
3423         /*
3424          * Add up IP Header portion
3425          */
3426 #ifdef  USE_INET6
3427         if (IP_V(ip) == 4) {
3428 #endif
3429                 hlen = IP_HL(ip) << 2;
3430                 off = hlen;
3431                 sp = (u_short *)&ip->ip_src;
3432                 sum += *sp++;   /* ip_src */
3433                 sum += *sp++;
3434                 sum += *sp++;   /* ip_dst */
3435                 sum += *sp++;
3436                 slen = fin->fin_plen - off;
3437                 sum += htons(slen);
3438 #ifdef  USE_INET6
3439         } else if (IP_V(ip) == 6) {
3440                 mb_t *m;
3441
3442                 m = fin->fin_m;
3443                 ip6 = (ip6_t *)ip;
3444                 off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr);
3445                 int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6));
3446                 return(ipf_pcksum6(fin, ip6, off, len));
3447         } else {
3448                 return 0xffff;
3449         }
3450 #endif
3451
3452         switch (l4proto)
3453         {
3454         case IPPROTO_UDP :
3455                 csump = &((udphdr_t *)l4hdr)->uh_sum;
3456                 break;
3457
3458         case IPPROTO_TCP :
3459                 csump = &((tcphdr_t *)l4hdr)->th_sum;
3460                 break;
3461         case IPPROTO_ICMP :
3462                 csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
3463                 sum = 0;        /* Pseudo-checksum is not included */
3464                 break;
3465 #ifdef USE_INET6
3466         case IPPROTO_ICMPV6 :
3467                 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum;
3468                 break;
3469 #endif
3470         default :
3471                 break;
3472         }
3473
3474         if (csump != NULL) {
3475                 sumsave = *csump;
3476                 *csump = 0;
3477         }
3478
3479         sum2 = ipf_pcksum(fin, off, sum);
3480         if (csump != NULL)
3481                 *csump = sumsave;
3482         return sum2;
3483 }
3484
3485
3486 /* ------------------------------------------------------------------------ */
3487 /* Function:    ipf_findgroup                                               */
3488 /* Returns:     frgroup_t * - NULL = group not found, else pointer to group */
3489 /* Parameters:  softc(I) - pointer to soft context main structure           */
3490 /*              group(I) - group name to search for                         */
3491 /*              unit(I)  - device to which this group belongs               */
3492 /*              set(I)   - which set of rules (inactive/inactive) this is   */
3493 /*              fgpp(O)  - pointer to place to store pointer to the pointer */
3494 /*                         to where to add the next (last) group or where   */
3495 /*                         to delete group from.                            */
3496 /*                                                                          */
3497 /* Search amongst the defined groups for a particular group number.         */
3498 /* ------------------------------------------------------------------------ */
3499 frgroup_t *
3500 ipf_findgroup(softc, group, unit, set, fgpp)
3501         ipf_main_softc_t *softc;
3502         char *group;
3503         minor_t unit;
3504         int set;
3505         frgroup_t ***fgpp;
3506 {
3507         frgroup_t *fg, **fgp;
3508
3509         /*
3510          * Which list of groups to search in is dependent on which list of
3511          * rules are being operated on.
3512          */
3513         fgp = &softc->ipf_groups[unit][set];
3514
3515         while ((fg = *fgp) != NULL) {
3516                 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
3517                         break;
3518                 else
3519                         fgp = &fg->fg_next;
3520         }
3521         if (fgpp != NULL)
3522                 *fgpp = fgp;
3523         return fg;
3524 }
3525
3526
3527 /* ------------------------------------------------------------------------ */
3528 /* Function:    ipf_group_add                                               */
3529 /* Returns:     frgroup_t * - NULL == did not create group,                 */
3530 /*                            != NULL == pointer to the group               */
3531 /* Parameters:  softc(I) - pointer to soft context main structure           */
3532 /*              num(I)   - group number to add                              */
3533 /*              head(I)  - rule pointer that is using this as the head      */
3534 /*              flags(I) - rule flags which describe the type of rule it is */
3535 /*              unit(I)  - device to which this group will belong to        */
3536 /*              set(I)   - which set of rules (inactive/inactive) this is   */
3537 /* Write Locks: ipf_mutex                                                   */
3538 /*                                                                          */
3539 /* Add a new group head, or if it already exists, increase the reference    */
3540 /* count to it.                                                             */
3541 /* ------------------------------------------------------------------------ */
3542 frgroup_t *
3543 ipf_group_add(softc, group, head, flags, unit, set)
3544         ipf_main_softc_t *softc;
3545         char *group;
3546         void *head;
3547         u_32_t flags;
3548         minor_t unit;
3549         int set;
3550 {
3551         frgroup_t *fg, **fgp;
3552         u_32_t gflags;
3553
3554         if (group == NULL)
3555                 return NULL;
3556
3557         if (unit == IPL_LOGIPF && *group == '\0')
3558                 return NULL;
3559
3560         fgp = NULL;
3561         gflags = flags & FR_INOUT;
3562
3563         fg = ipf_findgroup(softc, group, unit, set, &fgp);
3564         if (fg != NULL) {
3565                 if (fg->fg_head == NULL && head != NULL)
3566                         fg->fg_head = head;
3567                 if (fg->fg_flags == 0)
3568                         fg->fg_flags = gflags;
3569                 else if (gflags != fg->fg_flags)
3570                         return NULL;
3571                 fg->fg_ref++;
3572                 return fg;
3573         }
3574
3575         KMALLOC(fg, frgroup_t *);
3576         if (fg != NULL) {
3577                 fg->fg_head = head;
3578                 fg->fg_start = NULL;
3579                 fg->fg_next = *fgp;
3580                 bcopy(group, fg->fg_name, strlen(group) + 1);
3581                 fg->fg_flags = gflags;
3582                 fg->fg_ref = 1;
3583                 fg->fg_set = &softc->ipf_groups[unit][set];
3584                 *fgp = fg;
3585         }
3586         return fg;
3587 }
3588
3589
3590 /* ------------------------------------------------------------------------ */
3591 /* Function:    ipf_group_del                                               */
3592 /* Returns:     int      - number of rules deleted                          */
3593 /* Parameters:  softc(I) - pointer to soft context main structure           */
3594 /*              group(I) - group name to delete                             */
3595 /*              fr(I)    - filter rule from which group is referenced       */
3596 /* Write Locks: ipf_mutex                                                   */
3597 /*                                                                          */
3598 /* This function is called whenever a reference to a group is to be dropped */
3599 /* and thus its reference count needs to be lowered and the group free'd if */
3600 /* the reference count reaches zero. Passing in fr is really for the sole   */
3601 /* purpose of knowing when the head rule is being deleted.                  */
3602 /* ------------------------------------------------------------------------ */
3603 void
3604 ipf_group_del(softc, group, fr)
3605         ipf_main_softc_t *softc;
3606         frgroup_t *group;
3607         frentry_t *fr;
3608 {
3609
3610         if (group->fg_head == fr)
3611                 group->fg_head = NULL;
3612
3613         group->fg_ref--;
3614         if ((group->fg_ref == 0) && (group->fg_start == NULL))
3615                 ipf_group_free(group);
3616 }
3617
3618
3619 /* ------------------------------------------------------------------------ */
3620 /* Function:    ipf_group_free                                              */
3621 /* Returns:     Nil                                                         */
3622 /* Parameters:  group(I) - pointer to filter rule group                     */
3623 /*                                                                          */
3624 /* Remove the group from the list of groups and free it.                    */
3625 /* ------------------------------------------------------------------------ */
3626 static void
3627 ipf_group_free(group)
3628         frgroup_t *group;
3629 {
3630         frgroup_t **gp;
3631
3632         for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) {
3633                 if (*gp == group) {
3634                         *gp = group->fg_next;
3635                         break;
3636                 }
3637         }
3638         KFREE(group);
3639 }
3640
3641
3642 /* ------------------------------------------------------------------------ */
3643 /* Function:    ipf_group_flush                                             */
3644 /* Returns:     int      - number of rules flush from group                 */
3645 /* Parameters:  softc(I) - pointer to soft context main structure           */
3646 /* Parameters:  group(I) - pointer to filter rule group                     */
3647 /*                                                                          */
3648 /* Remove all of the rules that currently are listed under the given group. */
3649 /* ------------------------------------------------------------------------ */
3650 static int
3651 ipf_group_flush(softc, group)
3652         ipf_main_softc_t *softc;
3653         frgroup_t *group;
3654 {
3655         int gone = 0;
3656
3657         (void) ipf_flushlist(softc, &gone, &group->fg_start);
3658
3659         return gone;
3660 }
3661
3662
3663 /* ------------------------------------------------------------------------ */
3664 /* Function:    ipf_getrulen                                                */
3665 /* Returns:     frentry_t * - NULL == not found, else pointer to rule n     */
3666 /* Parameters:  softc(I) - pointer to soft context main structure           */
3667 /* Parameters:  unit(I)  - device for which to count the rule's number      */
3668 /*              flags(I) - which set of rules to find the rule in           */
3669 /*              group(I) - group name                                       */
3670 /*              n(I)     - rule number to find                              */
3671 /*                                                                          */
3672 /* Find rule # n in group # g and return a pointer to it.  Return NULl if   */
3673 /* group # g doesn't exist or there are less than n rules in the group.     */
3674 /* ------------------------------------------------------------------------ */
3675 frentry_t *
3676 ipf_getrulen(softc, unit, group, n)
3677         ipf_main_softc_t *softc;
3678         int unit;
3679         char *group;
3680         u_32_t n;
3681 {
3682         frentry_t *fr;
3683         frgroup_t *fg;
3684
3685         fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL);
3686         if (fg == NULL)
3687                 return NULL;
3688         for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--)
3689                 ;
3690         if (n != 0)
3691                 return NULL;
3692         return fr;
3693 }
3694
3695
3696 /* ------------------------------------------------------------------------ */
3697 /* Function:    ipf_flushlist                                               */
3698 /* Returns:     int - >= 0 - number of flushed rules                        */
3699 /* Parameters:  softc(I)   - pointer to soft context main structure         */
3700 /*              nfreedp(O) - pointer to int where flush count is stored     */
3701 /*              listp(I)   - pointer to list to flush pointer               */
3702 /* Write Locks: ipf_mutex                                                   */
3703 /*                                                                          */
3704 /* Recursively flush rules from the list, descending groups as they are     */
3705 /* encountered.  if a rule is the head of a group and it has lost all its   */
3706 /* group members, then also delete the group reference.  nfreedp is needed  */
3707 /* to store the accumulating count of rules removed, whereas the returned   */
3708 /* value is just the number removed from the current list.  The latter is   */
3709 /* needed to correctly adjust reference counts on rules that define groups. */
3710 /*                                                                          */
3711 /* NOTE: Rules not loaded from user space cannot be flushed.                */
3712 /* ------------------------------------------------------------------------ */
3713 static int
3714 ipf_flushlist(softc, nfreedp, listp)
3715         ipf_main_softc_t *softc;
3716         int *nfreedp;
3717         frentry_t **listp;
3718 {
3719         int freed = 0;
3720         frentry_t *fp;
3721
3722         while ((fp = *listp) != NULL) {
3723                 if ((fp->fr_type & FR_T_BUILTIN) ||
3724                     !(fp->fr_flags & FR_COPIED)) {
3725                         listp = &fp->fr_next;
3726                         continue;
3727                 }
3728                 *listp = fp->fr_next;
3729                 if (fp->fr_next != NULL)
3730                         fp->fr_next->fr_pnext = fp->fr_pnext;
3731                 fp->fr_pnext = NULL;
3732
3733                 if (fp->fr_grphead != NULL) {
3734                         freed += ipf_group_flush(softc, fp->fr_grphead);
3735                         fp->fr_names[fp->fr_grhead] = '\0';
3736                 }
3737
3738                 if (fp->fr_icmpgrp != NULL) {
3739                         freed += ipf_group_flush(softc, fp->fr_icmpgrp);
3740                         fp->fr_names[fp->fr_icmphead] = '\0';
3741                 }
3742
3743                 if (fp->fr_srctrack.ht_max_nodes)
3744                         ipf_rb_ht_flush(&fp->fr_srctrack);
3745
3746                 fp->fr_next = NULL;
3747
3748                 ASSERT(fp->fr_ref > 0);
3749                 if (ipf_derefrule(softc, &fp) == 0)
3750                         freed++;
3751         }
3752         *nfreedp += freed;
3753         return freed;
3754 }
3755
3756
3757 /* ------------------------------------------------------------------------ */
3758 /* Function:    ipf_flush                                                   */
3759 /* Returns:     int - >= 0 - number of flushed rules                        */
3760 /* Parameters:  softc(I) - pointer to soft context main structure           */
3761 /*              unit(I)  - device for which to flush rules                  */
3762 /*              flags(I) - which set of rules to flush                      */
3763 /*                                                                          */
3764 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
3765 /* and IPv6) as defined by the value of flags.                              */
3766 /* ------------------------------------------------------------------------ */
3767 int
3768 ipf_flush(softc, unit, flags)
3769         ipf_main_softc_t *softc;
3770         minor_t unit;
3771         int flags;
3772 {
3773         int flushed = 0, set;
3774
3775         WRITE_ENTER(&softc->ipf_mutex);
3776
3777         set = softc->ipf_active;
3778         if ((flags & FR_INACTIVE) == FR_INACTIVE)
3779                 set = 1 - set;
3780
3781         if (flags & FR_OUTQUE) {
3782                 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]);
3783                 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]);
3784         }
3785         if (flags & FR_INQUE) {
3786                 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]);
3787                 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]);
3788         }
3789
3790         flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set],
3791                                     flags & (FR_INQUE|FR_OUTQUE));
3792
3793         RWLOCK_EXIT(&softc->ipf_mutex);
3794
3795         if (unit == IPL_LOGIPF) {
3796                 int tmp;
3797
3798                 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags);
3799                 if (tmp >= 0)
3800                         flushed += tmp;
3801         }
3802         return flushed;
3803 }
3804
3805
3806 /* ------------------------------------------------------------------------ */
3807 /* Function:    ipf_flush_groups                                            */
3808 /* Returns:     int - >= 0 - number of flushed rules                        */
3809 /* Parameters:  softc(I)  - soft context pointerto work with                */
3810 /*              grhead(I) - pointer to the start of the group list to flush */
3811 /*              flags(I)  - which set of rules to flush                     */
3812 /*                                                                          */
3813 /* Walk through all of the groups under the given group head and remove all */
3814 /* of those that match the flags passed in. The for loop here is bit more   */
3815 /* complicated than usual because the removal of a rule with ipf_derefrule  */
3816 /* may end up removing not only the structure pointed to by "fg" but also   */
3817 /* what is fg_next and fg_next after that. So if a filter rule is actually  */
3818 /* removed from the group then it is necessary to start again.              */
3819 /* ------------------------------------------------------------------------ */
3820 static int
3821 ipf_flush_groups(softc, grhead, flags)
3822         ipf_main_softc_t *softc;
3823         frgroup_t **grhead;
3824         int flags;
3825 {
3826         frentry_t *fr, **frp;
3827         frgroup_t *fg, **fgp;
3828         int flushed = 0;
3829         int removed = 0;
3830
3831         for (fgp = grhead; (fg = *fgp) != NULL; ) {
3832                 while ((fg != NULL) && ((fg->fg_flags & flags) == 0))
3833                         fg = fg->fg_next;
3834                 if (fg == NULL)
3835                         break;
3836                 removed = 0;
3837                 frp = &fg->fg_start;
3838                 while ((removed == 0) && ((fr = *frp) != NULL)) {
3839                         if ((fr->fr_flags & flags) == 0) {
3840                                 frp = &fr->fr_next;
3841                         } else {
3842                                 if (fr->fr_next != NULL)
3843                                         fr->fr_next->fr_pnext = fr->fr_pnext;
3844                                 *frp = fr->fr_next;
3845                                 fr->fr_pnext = NULL;
3846                                 fr->fr_next = NULL;
3847                                 (void) ipf_derefrule(softc, &fr);
3848                                 flushed++;
3849                                 removed++;
3850                         }
3851                 }
3852                 if (removed == 0)
3853                         fgp = &fg->fg_next;
3854         }
3855         return flushed;
3856 }
3857
3858
3859 /* ------------------------------------------------------------------------ */
3860 /* Function:    memstr                                                      */
3861 /* Returns:     char *  - NULL if failed, != NULL pointer to matching bytes */
3862 /* Parameters:  src(I)  - pointer to byte sequence to match                 */
3863 /*              dst(I)  - pointer to byte sequence to search                */
3864 /*              slen(I) - match length                                      */
3865 /*              dlen(I) - length available to search in                     */
3866 /*                                                                          */
3867 /* Search dst for a sequence of bytes matching those at src and extend for  */
3868 /* slen bytes.                                                              */
3869 /* ------------------------------------------------------------------------ */
3870 char *
3871 memstr(src, dst, slen, dlen)
3872         const char *src;
3873         char *dst;
3874         size_t slen, dlen;
3875 {
3876         char *s = NULL;
3877
3878         while (dlen >= slen) {
3879                 if (bcmp(src, dst, slen) == 0) {
3880                         s = dst;
3881                         break;
3882                 }
3883                 dst++;
3884                 dlen--;
3885         }
3886         return s;
3887 }
3888 /* ------------------------------------------------------------------------ */
3889 /* Function:    ipf_fixskip                                                 */
3890 /* Returns:     Nil                                                         */
3891 /* Parameters:  listp(IO)    - pointer to start of list with skip rule      */
3892 /*              rp(I)        - rule added/removed with skip in it.          */
3893 /*              addremove(I) - adjustment (-1/+1) to make to skip count,    */
3894 /*                             depending on whether a rule was just added   */
3895 /*                             or removed.                                  */
3896 /*                                                                          */
3897 /* Adjust all the rules in a list which would have skip'd past the position */
3898 /* where we are inserting to skip to the right place given the change.      */
3899 /* ------------------------------------------------------------------------ */
3900 void
3901 ipf_fixskip(listp, rp, addremove)
3902         frentry_t **listp, *rp;
3903         int addremove;
3904 {
3905         int rules, rn;
3906         frentry_t *fp;
3907
3908         rules = 0;
3909         for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next)
3910                 rules++;
3911
3912         if (!fp)
3913                 return;
3914
3915         for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
3916                 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules))
3917                         fp->fr_arg += addremove;
3918 }
3919
3920
3921 #ifdef  _KERNEL
3922 /* ------------------------------------------------------------------------ */
3923 /* Function:    count4bits                                                  */
3924 /* Returns:     int - >= 0 - number of consecutive bits in input            */
3925 /* Parameters:  ip(I) - 32bit IP address                                    */
3926 /*                                                                          */
3927 /* IPv4 ONLY                                                                */
3928 /* count consecutive 1's in bit mask.  If the mask generated by counting    */
3929 /* consecutive 1's is different to that passed, return -1, else return #    */
3930 /* of bits.                                                                 */
3931 /* ------------------------------------------------------------------------ */
3932 int
3933 count4bits(ip)
3934         u_32_t  ip;
3935 {
3936         u_32_t  ipn;
3937         int     cnt = 0, i, j;
3938
3939         ip = ipn = ntohl(ip);
3940         for (i = 32; i; i--, ipn *= 2)
3941                 if (ipn & 0x80000000)
3942                         cnt++;
3943                 else
3944                         break;
3945         ipn = 0;
3946         for (i = 32, j = cnt; i; i--, j--) {
3947                 ipn *= 2;
3948                 if (j > 0)
3949                         ipn++;
3950         }
3951         if (ipn == ip)
3952                 return cnt;
3953         return -1;
3954 }
3955
3956
3957 /* ------------------------------------------------------------------------ */
3958 /* Function:    count6bits                                                  */
3959 /* Returns:     int - >= 0 - number of consecutive bits in input            */
3960 /* Parameters:  msk(I) - pointer to start of IPv6 bitmask                   */
3961 /*                                                                          */
3962 /* IPv6 ONLY                                                                */
3963 /* count consecutive 1's in bit mask.                                       */
3964 /* ------------------------------------------------------------------------ */
3965 # ifdef USE_INET6
3966 int
3967 count6bits(msk)
3968         u_32_t *msk;
3969 {
3970         int i = 0, k;
3971         u_32_t j;
3972
3973         for (k = 3; k >= 0; k--)
3974                 if (msk[k] == 0xffffffff)
3975                         i += 32;
3976                 else {
3977                         for (j = msk[k]; j; j <<= 1)
3978                                 if (j & 0x80000000)
3979                                         i++;
3980                 }
3981         return i;
3982 }
3983 # endif
3984 #endif /* _KERNEL */
3985
3986
3987 /* ------------------------------------------------------------------------ */
3988 /* Function:    ipf_synclist                                                */
3989 /* Returns:     int    - 0 = no failures, else indication of first failure  */
3990 /* Parameters:  fr(I)  - start of filter list to sync interface names for   */
3991 /*              ifp(I) - interface pointer for limiting sync lookups        */
3992 /* Write Locks: ipf_mutex                                                   */
3993 /*                                                                          */
3994 /* Walk through a list of filter rules and resolve any interface names into */
3995 /* pointers.  Where dynamic addresses are used, also update the IP address  */
3996 /* used in the rule.  The interface pointer is used to limit the lookups to */
3997 /* a specific set of matching names if it is non-NULL.                      */
3998 /* Errors can occur when resolving the destination name of to/dup-to fields */
3999 /* when the name points to a pool and that pool doest not exist. If this    */
4000 /* does happen then it is necessary to check if there are any lookup refs   */
4001 /* that need to be dropped before returning with an error.                  */
4002 /* ------------------------------------------------------------------------ */
4003 static int
4004 ipf_synclist(softc, fr, ifp)
4005         ipf_main_softc_t *softc;
4006         frentry_t *fr;
4007         void *ifp;
4008 {
4009         frentry_t *frt, *start = fr;
4010         frdest_t *fdp;
4011         char *name;
4012         int error;
4013         void *ifa;
4014         int v, i;
4015
4016         error = 0;
4017
4018         for (; fr; fr = fr->fr_next) {
4019                 if (fr->fr_family == AF_INET)
4020                         v = 4;
4021                 else if (fr->fr_family == AF_INET6)
4022                         v = 6;
4023                 else
4024                         v = 0;
4025
4026                 /*
4027                  * Lookup all the interface names that are part of the rule.
4028                  */
4029                 for (i = 0; i < 4; i++) {
4030                         if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
4031                                 continue;
4032                         if (fr->fr_ifnames[i] == -1)
4033                                 continue;
4034                         name = FR_NAME(fr, fr_ifnames[i]);
4035                         fr->fr_ifas[i] = ipf_resolvenic(softc, name, v);
4036                 }
4037
4038                 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
4039                         if (fr->fr_satype != FRI_NORMAL &&
4040                             fr->fr_satype != FRI_LOOKUP) {
4041                                 ifa = ipf_resolvenic(softc, fr->fr_names +
4042                                                      fr->fr_sifpidx, v);
4043                                 ipf_ifpaddr(softc, v, fr->fr_satype, ifa,
4044                                             &fr->fr_src6, &fr->fr_smsk6);
4045                         }
4046                         if (fr->fr_datype != FRI_NORMAL &&
4047                             fr->fr_datype != FRI_LOOKUP) {
4048                                 ifa = ipf_resolvenic(softc, fr->fr_names +
4049                                                      fr->fr_sifpidx, v);
4050                                 ipf_ifpaddr(softc, v, fr->fr_datype, ifa,
4051                                             &fr->fr_dst6, &fr->fr_dmsk6);
4052                         }
4053                 }
4054
4055                 fdp = &fr->fr_tifs[0];
4056                 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
4057                         error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
4058                         if (error != 0)
4059                                 goto unwind;
4060                 }
4061
4062                 fdp = &fr->fr_tifs[1];
4063                 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
4064                         error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
4065                         if (error != 0)
4066                                 goto unwind;
4067                 }
4068
4069                 fdp = &fr->fr_dif;
4070                 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
4071                         error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
4072                         if (error != 0)
4073                                 goto unwind;
4074                 }
4075
4076                 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4077                     (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) {
4078                         fr->fr_srcptr = ipf_lookup_res_num(softc,
4079                                                            fr->fr_srctype,
4080                                                            IPL_LOGIPF,
4081                                                            fr->fr_srcnum,
4082                                                            &fr->fr_srcfunc);
4083                 }
4084                 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4085                     (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) {
4086                         fr->fr_dstptr = ipf_lookup_res_num(softc,
4087                                                            fr->fr_dsttype,
4088                                                            IPL_LOGIPF,
4089                                                            fr->fr_dstnum,
4090                                                            &fr->fr_dstfunc);
4091                 }
4092         }
4093         return 0;
4094
4095 unwind:
4096         for (frt = start; frt != fr; fr = fr->fr_next) {
4097                 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4098                     (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL))
4099                                 ipf_lookup_deref(softc, frt->fr_srctype,
4100                                                  frt->fr_srcptr);
4101                 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
4102                     (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL))
4103                                 ipf_lookup_deref(softc, frt->fr_dsttype,
4104                                                  frt->fr_dstptr);
4105         }
4106         return error;
4107 }
4108
4109
4110 /* ------------------------------------------------------------------------ */
4111 /* Function:    ipf_sync                                                    */
4112 /* Returns:     void                                                        */
4113 /* Parameters:  Nil                                                         */
4114 /*                                                                          */
4115 /* ipf_sync() is called when we suspect that the interface list or          */
4116 /* information about interfaces (like IP#) has changed.  Go through all     */
4117 /* filter rules, NAT entries and the state table and check if anything      */
4118 /* needs to be changed/updated.                                             */
4119 /* ------------------------------------------------------------------------ */
4120 int
4121 ipf_sync(softc, ifp)
4122         ipf_main_softc_t *softc;
4123         void *ifp;
4124 {
4125         int i;
4126
4127 # if !SOLARIS
4128         ipf_nat_sync(softc, ifp);
4129         ipf_state_sync(softc, ifp);
4130         ipf_lookup_sync(softc, ifp);
4131 # endif
4132
4133         WRITE_ENTER(&softc->ipf_mutex);
4134         (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp);
4135         (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp);
4136         (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp);
4137         (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp);
4138
4139         for (i = 0; i < IPL_LOGSIZE; i++) {
4140                 frgroup_t *g;
4141
4142                 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next)
4143                         (void) ipf_synclist(softc, g->fg_start, ifp);
4144                 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next)
4145                         (void) ipf_synclist(softc, g->fg_start, ifp);
4146         }
4147         RWLOCK_EXIT(&softc->ipf_mutex);
4148
4149         return 0;
4150 }
4151
4152
4153 /*
4154  * In the functions below, bcopy() is called because the pointer being
4155  * copied _from_ in this instance is a pointer to a char buf (which could
4156  * end up being unaligned) and on the kernel's local stack.
4157  */
4158 /* ------------------------------------------------------------------------ */
4159 /* Function:    copyinptr                                                   */
4160 /* Returns:     int - 0 = success, else failure                             */
4161 /* Parameters:  src(I)  - pointer to the source address                     */
4162 /*              dst(I)  - destination address                               */
4163 /*              size(I) - number of bytes to copy                           */
4164 /*                                                                          */
4165 /* Copy a block of data in from user space, given a pointer to the pointer  */
4166 /* to start copying from (src) and a pointer to where to store it (dst).    */
4167 /* NB: src - pointer to user space pointer, dst - kernel space pointer      */
4168 /* ------------------------------------------------------------------------ */
4169 int
4170 copyinptr(softc, src, dst, size)
4171         ipf_main_softc_t *softc;
4172         void *src, *dst;
4173         size_t size;
4174 {
4175         caddr_t ca;
4176         int error;
4177
4178 # if SOLARIS
4179         error = COPYIN(src, &ca, sizeof(ca));
4180         if (error != 0)
4181                 return error;
4182 # else
4183         bcopy(src, (caddr_t)&ca, sizeof(ca));
4184 # endif
4185         error = COPYIN(ca, dst, size);
4186         if (error != 0) {
4187                 IPFERROR(3);
4188                 error = EFAULT;
4189         }
4190         return error;
4191 }
4192
4193
4194 /* ------------------------------------------------------------------------ */
4195 /* Function:    copyoutptr                                                  */
4196 /* Returns:     int - 0 = success, else failure                             */
4197 /* Parameters:  src(I)  - pointer to the source address                     */
4198 /*              dst(I)  - destination address                               */
4199 /*              size(I) - number of bytes to copy                           */
4200 /*                                                                          */
4201 /* Copy a block of data out to user space, given a pointer to the pointer   */
4202 /* to start copying from (src) and a pointer to where to store it (dst).    */
4203 /* NB: src - kernel space pointer, dst - pointer to user space pointer.     */
4204 /* ------------------------------------------------------------------------ */
4205 int
4206 copyoutptr(softc, src, dst, size)
4207         ipf_main_softc_t *softc;
4208         void *src, *dst;
4209         size_t size;
4210 {
4211         caddr_t ca;
4212         int error;
4213
4214         bcopy(dst, (caddr_t)&ca, sizeof(ca));
4215         error = COPYOUT(src, ca, size);
4216         if (error != 0) {
4217                 IPFERROR(4);
4218                 error = EFAULT;
4219         }
4220         return error;
4221 }
4222
4223
4224 /* ------------------------------------------------------------------------ */
4225 /* Function:    ipf_lock                                                    */
4226 /* Returns:     int      - 0 = success, else error                          */
4227 /* Parameters:  data(I)  - pointer to lock value to set                     */
4228 /*              lockp(O) - pointer to location to store old lock value      */
4229 /*                                                                          */
4230 /* Get the new value for the lock integer, set it and return the old value  */
4231 /* in *lockp.                                                               */
4232 /* ------------------------------------------------------------------------ */
4233 int
4234 ipf_lock(data, lockp)
4235         caddr_t data;
4236         int *lockp;
4237 {
4238         int arg, err;
4239
4240         err = BCOPYIN(data, &arg, sizeof(arg));
4241         if (err != 0)
4242                 return EFAULT;
4243         err = BCOPYOUT(lockp, data, sizeof(*lockp));
4244         if (err != 0)
4245                 return EFAULT;
4246         *lockp = arg;
4247         return 0;
4248 }
4249
4250
4251 /* ------------------------------------------------------------------------ */
4252 /* Function:    ipf_getstat                                                 */
4253 /* Returns:     Nil                                                         */
4254 /* Parameters:  softc(I) - pointer to soft context main structure           */
4255 /*              fiop(I)  - pointer to ipfilter stats structure              */
4256 /*              rev(I)   - version claim by program doing ioctl             */
4257 /*                                                                          */
4258 /* Stores a copy of current pointers, counters, etc, in the friostat        */
4259 /* structure.                                                               */
4260 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the    */
4261 /* program is looking for. This ensure that validation of the version it    */
4262 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will      */
4263 /* allow older binaries to work but kernels without it will not.            */
4264 /* ------------------------------------------------------------------------ */
4265 /*ARGSUSED*/
4266 static void
4267 ipf_getstat(softc, fiop, rev)
4268         ipf_main_softc_t *softc;
4269         friostat_t *fiop;
4270         int rev;
4271 {
4272         int i;
4273
4274         bcopy((char *)softc->ipf_stats, (char *)fiop->f_st,
4275               sizeof(ipf_statistics_t) * 2);
4276         fiop->f_locks[IPL_LOGSTATE] = -1;
4277         fiop->f_locks[IPL_LOGNAT] = -1;
4278         fiop->f_locks[IPL_LOGIPF] = -1;
4279         fiop->f_locks[IPL_LOGAUTH] = -1;
4280
4281         fiop->f_ipf[0][0] = softc->ipf_rules[0][0];
4282         fiop->f_acct[0][0] = softc->ipf_acct[0][0];
4283         fiop->f_ipf[0][1] = softc->ipf_rules[0][1];
4284         fiop->f_acct[0][1] = softc->ipf_acct[0][1];
4285         fiop->f_ipf[1][0] = softc->ipf_rules[1][0];
4286         fiop->f_acct[1][0] = softc->ipf_acct[1][0];
4287         fiop->f_ipf[1][1] = softc->ipf_rules[1][1];
4288         fiop->f_acct[1][1] = softc->ipf_acct[1][1];
4289
4290         fiop->f_ticks = softc->ipf_ticks;
4291         fiop->f_active = softc->ipf_active;
4292         fiop->f_froute[0] = softc->ipf_frouteok[0];
4293         fiop->f_froute[1] = softc->ipf_frouteok[1];
4294         fiop->f_rb_no_mem = softc->ipf_rb_no_mem;
4295         fiop->f_rb_node_max = softc->ipf_rb_node_max;
4296
4297         fiop->f_running = softc->ipf_running;
4298         for (i = 0; i < IPL_LOGSIZE; i++) {
4299                 fiop->f_groups[i][0] = softc->ipf_groups[i][0];
4300                 fiop->f_groups[i][1] = softc->ipf_groups[i][1];
4301         }
4302 #ifdef  IPFILTER_LOG
4303         fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF);
4304         fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF);
4305         fiop->f_logging = 1;
4306 #else
4307         fiop->f_log_ok = 0;
4308         fiop->f_log_fail = 0;
4309         fiop->f_logging = 0;
4310 #endif
4311         fiop->f_defpass = softc->ipf_pass;
4312         fiop->f_features = ipf_features;
4313
4314 #ifdef IPFILTER_COMPAT
4315         sprintf(fiop->f_version, "IP Filter: v%d.%d.%d",
4316                 (rev / 1000000) % 100,
4317                 (rev / 10000) % 100,
4318                 (rev / 100) % 100);
4319 #else
4320         rev = rev;
4321         (void) strncpy(fiop->f_version, ipfilter_version,
4322                        sizeof(fiop->f_version));
4323 #endif
4324 }
4325
4326
4327 #ifdef  USE_INET6
4328 int icmptoicmp6types[ICMP_MAXTYPE+1] = {
4329         ICMP6_ECHO_REPLY,       /* 0: ICMP_ECHOREPLY */
4330         -1,                     /* 1: UNUSED */
4331         -1,                     /* 2: UNUSED */
4332         ICMP6_DST_UNREACH,      /* 3: ICMP_UNREACH */
4333         -1,                     /* 4: ICMP_SOURCEQUENCH */
4334         ND_REDIRECT,            /* 5: ICMP_REDIRECT */
4335         -1,                     /* 6: UNUSED */
4336         -1,                     /* 7: UNUSED */
4337         ICMP6_ECHO_REQUEST,     /* 8: ICMP_ECHO */
4338         -1,                     /* 9: UNUSED */
4339         -1,                     /* 10: UNUSED */
4340         ICMP6_TIME_EXCEEDED,    /* 11: ICMP_TIMXCEED */
4341         ICMP6_PARAM_PROB,       /* 12: ICMP_PARAMPROB */
4342         -1,                     /* 13: ICMP_TSTAMP */
4343         -1,                     /* 14: ICMP_TSTAMPREPLY */
4344         -1,                     /* 15: ICMP_IREQ */
4345         -1,                     /* 16: ICMP_IREQREPLY */
4346         -1,                     /* 17: ICMP_MASKREQ */
4347         -1,                     /* 18: ICMP_MASKREPLY */
4348 };
4349
4350
4351 int     icmptoicmp6unreach[ICMP_MAX_UNREACH] = {
4352         ICMP6_DST_UNREACH_ADDR,         /* 0: ICMP_UNREACH_NET */
4353         ICMP6_DST_UNREACH_ADDR,         /* 1: ICMP_UNREACH_HOST */
4354         -1,                             /* 2: ICMP_UNREACH_PROTOCOL */
4355         ICMP6_DST_UNREACH_NOPORT,       /* 3: ICMP_UNREACH_PORT */
4356         -1,                             /* 4: ICMP_UNREACH_NEEDFRAG */
4357         ICMP6_DST_UNREACH_NOTNEIGHBOR,  /* 5: ICMP_UNREACH_SRCFAIL */
4358         ICMP6_DST_UNREACH_ADDR,         /* 6: ICMP_UNREACH_NET_UNKNOWN */
4359         ICMP6_DST_UNREACH_ADDR,         /* 7: ICMP_UNREACH_HOST_UNKNOWN */
4360         -1,                             /* 8: ICMP_UNREACH_ISOLATED */
4361         ICMP6_DST_UNREACH_ADMIN,        /* 9: ICMP_UNREACH_NET_PROHIB */
4362         ICMP6_DST_UNREACH_ADMIN,        /* 10: ICMP_UNREACH_HOST_PROHIB */
4363         -1,                             /* 11: ICMP_UNREACH_TOSNET */
4364         -1,                             /* 12: ICMP_UNREACH_TOSHOST */
4365         ICMP6_DST_UNREACH_ADMIN,        /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
4366 };
4367 int     icmpreplytype6[ICMP6_MAXTYPE + 1];
4368 #endif
4369
4370 int     icmpreplytype4[ICMP_MAXTYPE + 1];
4371
4372
4373 /* ------------------------------------------------------------------------ */
4374 /* Function:    ipf_matchicmpqueryreply                                     */
4375 /* Returns:     int - 1 if "icmp" is a valid reply to "ic" else 0.          */
4376 /* Parameters:  v(I)    - IP protocol version (4 or 6)                      */
4377 /*              ic(I)   - ICMP information                                  */
4378 /*              icmp(I) - ICMP packet header                                */
4379 /*              rev(I)  - direction (0 = forward/1 = reverse) of packet     */
4380 /*                                                                          */
4381 /* Check if the ICMP packet defined by the header pointed to by icmp is a   */
4382 /* reply to one as described by what's in ic.  If it is a match, return 1,  */
4383 /* else return 0 for no match.                                              */
4384 /* ------------------------------------------------------------------------ */
4385 int
4386 ipf_matchicmpqueryreply(v, ic, icmp, rev)
4387         int v;
4388         icmpinfo_t *ic;
4389         icmphdr_t *icmp;
4390         int rev;
4391 {
4392         int ictype;
4393
4394         ictype = ic->ici_type;
4395
4396         if (v == 4) {
4397                 /*
4398                  * If we matched its type on the way in, then when going out
4399                  * it will still be the same type.
4400                  */
4401                 if ((!rev && (icmp->icmp_type == ictype)) ||
4402                     (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) {
4403                         if (icmp->icmp_type != ICMP_ECHOREPLY)
4404                                 return 1;
4405                         if (icmp->icmp_id == ic->ici_id)
4406                                 return 1;
4407                 }
4408         }
4409 #ifdef  USE_INET6
4410         else if (v == 6) {
4411                 if ((!rev && (icmp->icmp_type == ictype)) ||
4412                     (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) {
4413                         if (icmp->icmp_type != ICMP6_ECHO_REPLY)
4414                                 return 1;
4415                         if (icmp->icmp_id == ic->ici_id)
4416                                 return 1;
4417                 }
4418         }
4419 #endif
4420         return 0;
4421 }
4422
4423
4424 /* ------------------------------------------------------------------------ */
4425 /* Function:    ipf_rule_compare                                            */
4426 /* Parameters:  fr1(I) - first rule structure to compare                    */
4427 /*              fr2(I) - second rule structure to compare                   */
4428 /* Returns:     int    - 0 == rules are the same, else mismatch             */
4429 /*                                                                          */
4430 /* Compare two rules and return 0 if they match or a number indicating      */
4431 /* which of the individual checks failed.                                   */
4432 /* ------------------------------------------------------------------------ */
4433 static int
4434 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2)
4435 {
4436         if (fr1->fr_cksum != fr2->fr_cksum)
4437                 return 1;
4438         if (fr1->fr_size != fr2->fr_size)
4439                 return 2;
4440         if (fr1->fr_dsize != fr2->fr_dsize)
4441                 return 3;
4442         if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func,
4443                  fr1->fr_size - offsetof(struct frentry, fr_func)) != 0)
4444                 return 4;
4445         if (fr1->fr_data && !fr2->fr_data)
4446                 return 5;
4447         if (!fr1->fr_data && fr2->fr_data)
4448                 return 6;
4449         if (fr1->fr_data) {
4450                 if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize))
4451                         return 7;
4452         }
4453         return 0;
4454 }
4455
4456
4457 /* ------------------------------------------------------------------------ */
4458 /* Function:    frrequest                                                   */
4459 /* Returns:     int - 0 == success, > 0 == errno value                      */
4460 /* Parameters:  unit(I)     - device for which this is for                  */
4461 /*              req(I)      - ioctl command (SIOC*)                         */
4462 /*              data(I)     - pointr to ioctl data                          */
4463 /*              set(I)      - 1 or 0 (filter set)                           */
4464 /*              makecopy(I) - flag indicating whether data points to a rule */
4465 /*                            in kernel space & hence doesn't need copying. */
4466 /*                                                                          */
4467 /* This function handles all the requests which operate on the list of      */
4468 /* filter rules.  This includes adding, deleting, insertion.  It is also    */
4469 /* responsible for creating groups when a "head" rule is loaded.  Interface */
4470 /* names are resolved here and other sanity checks are made on the content  */
4471 /* of the rule structure being loaded.  If a rule has user defined timeouts */
4472 /* then make sure they are created and initialised before exiting.          */
4473 /* ------------------------------------------------------------------------ */
4474 int
4475 frrequest(softc, unit, req, data, set, makecopy)
4476         ipf_main_softc_t *softc;
4477         int unit;
4478         ioctlcmd_t req;
4479         int set, makecopy;
4480         caddr_t data;
4481 {
4482         int error = 0, in, family, addrem, need_free = 0;
4483         frentry_t frd, *fp, *f, **fprev, **ftail;
4484         void *ptr, *uptr, *cptr;
4485         u_int *p, *pp;
4486         frgroup_t *fg;
4487         char *group;
4488
4489         ptr = NULL;
4490         cptr = NULL;
4491         fg = NULL;
4492         fp = &frd;
4493         if (makecopy != 0) {
4494                 bzero(fp, sizeof(frd));
4495                 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY);
4496                 if (error) {
4497                         return error;
4498                 }
4499                 if ((fp->fr_type & FR_T_BUILTIN) != 0) {
4500                         IPFERROR(6);
4501                         return EINVAL;
4502                 }
4503                 KMALLOCS(f, frentry_t *, fp->fr_size);
4504                 if (f == NULL) {
4505                         IPFERROR(131);
4506                         return ENOMEM;
4507                 }
4508                 bzero(f, fp->fr_size);
4509                 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY,
4510                                     fp->fr_size);
4511                 if (error) {
4512                         KFREES(f, fp->fr_size);
4513                         return error;
4514                 }
4515
4516                 fp = f;
4517                 f = NULL;
4518                 fp->fr_next = NULL;
4519                 fp->fr_dnext = NULL;
4520                 fp->fr_pnext = NULL;
4521                 fp->fr_pdnext = NULL;
4522                 fp->fr_grp = NULL;
4523                 fp->fr_grphead = NULL;
4524                 fp->fr_icmpgrp = NULL;
4525                 fp->fr_isc = (void *)-1;
4526                 fp->fr_ptr = NULL;
4527                 fp->fr_ref = 0;
4528                 fp->fr_flags |= FR_COPIED;
4529         } else {
4530                 fp = (frentry_t *)data;
4531                 if ((fp->fr_type & FR_T_BUILTIN) == 0) {
4532                         IPFERROR(7);
4533                         return EINVAL;
4534                 }
4535                 fp->fr_flags &= ~FR_COPIED;
4536         }
4537
4538         if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
4539             ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) {
4540                 IPFERROR(8);
4541                 error = EINVAL;
4542                 goto donenolock;
4543         }
4544
4545         family = fp->fr_family;
4546         uptr = fp->fr_data;
4547
4548         if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR ||
4549             req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR)
4550                 addrem = 0;
4551         else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR)
4552                 addrem = 1;
4553         else if (req == (ioctlcmd_t)SIOCZRLST)
4554                 addrem = 2;
4555         else {
4556                 IPFERROR(9);
4557                 error = EINVAL;
4558                 goto donenolock;
4559         }
4560
4561         /*
4562          * Only filter rules for IPv4 or IPv6 are accepted.
4563          */
4564         if (family == AF_INET) {
4565                 /*EMPTY*/;
4566 #ifdef  USE_INET6
4567         } else if (family == AF_INET6) {
4568                 /*EMPTY*/;
4569 #endif
4570         } else if (family != 0) {
4571                 IPFERROR(10);
4572                 error = EINVAL;
4573                 goto donenolock;
4574         }
4575
4576         /*
4577          * If the rule is being loaded from user space, i.e. we had to copy it
4578          * into kernel space, then do not trust the function pointer in the
4579          * rule.
4580          */
4581         if ((makecopy == 1) && (fp->fr_func != NULL)) {
4582                 if (ipf_findfunc(fp->fr_func) == NULL) {
4583                         IPFERROR(11);
4584                         error = ESRCH;
4585                         goto donenolock;
4586                 }
4587
4588                 if (addrem == 0) {
4589                         error = ipf_funcinit(softc, fp);
4590                         if (error != 0)
4591                                 goto donenolock;
4592                 }
4593         }
4594         if ((fp->fr_flags & FR_CALLNOW) &&
4595             ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
4596                 IPFERROR(142);
4597                 error = ESRCH;
4598                 goto donenolock;
4599         }
4600         if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) &&
4601             ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
4602                 IPFERROR(143);
4603                 error = ESRCH;
4604                 goto donenolock;
4605         }
4606
4607         ptr = NULL;
4608         cptr = NULL;
4609
4610         if (FR_ISACCOUNT(fp->fr_flags))
4611                 unit = IPL_LOGCOUNT;
4612
4613         /*
4614          * Check that each group name in the rule has a start index that
4615          * is valid.
4616          */
4617         if (fp->fr_icmphead != -1) {
4618                 if ((fp->fr_icmphead < 0) ||
4619                     (fp->fr_icmphead >= fp->fr_namelen)) {
4620                         IPFERROR(136);
4621                         error = EINVAL;
4622                         goto donenolock;
4623                 }
4624                 if (!strcmp(FR_NAME(fp, fr_icmphead), "0"))
4625                         fp->fr_names[fp->fr_icmphead] = '\0';
4626         }
4627
4628         if (fp->fr_grhead != -1) {
4629                 if ((fp->fr_grhead < 0) ||
4630                     (fp->fr_grhead >= fp->fr_namelen)) {
4631                         IPFERROR(137);
4632                         error = EINVAL;
4633                         goto donenolock;
4634                 }
4635                 if (!strcmp(FR_NAME(fp, fr_grhead), "0"))
4636                         fp->fr_names[fp->fr_grhead] = '\0';
4637         }
4638
4639         if (fp->fr_group != -1) {
4640                 if ((fp->fr_group < 0) ||
4641                     (fp->fr_group >= fp->fr_namelen)) {
4642                         IPFERROR(138);
4643                         error = EINVAL;
4644                         goto donenolock;
4645                 }
4646                 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) {
4647                         /*
4648                          * Allow loading rules that are in groups to cause
4649                          * them to be created if they don't already exit.
4650                          */
4651                         group = FR_NAME(fp, fr_group);
4652                         if (addrem == 0) {
4653                                 fg = ipf_group_add(softc, group, NULL,
4654                                                    fp->fr_flags, unit, set);
4655                                 fp->fr_grp = fg;
4656                         } else {
4657                                 fg = ipf_findgroup(softc, group, unit,
4658                                                    set, NULL);
4659                                 if (fg == NULL) {
4660                                         IPFERROR(12);
4661                                         error = ESRCH;
4662                                         goto donenolock;
4663                                 }
4664                         }
4665
4666                         if (fg->fg_flags == 0) {
4667                                 fg->fg_flags = fp->fr_flags & FR_INOUT;
4668                         } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) {
4669                                 IPFERROR(13);
4670                                 error = ESRCH;
4671                                 goto donenolock;
4672                         }
4673                 }
4674         } else {
4675                 /*
4676                  * If a rule is going to be part of a group then it does
4677                  * not matter whether it is an in or out rule, but if it
4678                  * isn't in a group, then it does...
4679                  */
4680                 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) {
4681                         IPFERROR(14);
4682                         error = EINVAL;
4683                         goto donenolock;
4684                 }
4685         }
4686         in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
4687
4688         /*
4689          * Work out which rule list this change is being applied to.
4690          */
4691         ftail = NULL;
4692         fprev = NULL;
4693         if (unit == IPL_LOGAUTH) {
4694                 if ((fp->fr_tifs[0].fd_ptr != NULL) ||
4695                     (fp->fr_tifs[1].fd_ptr != NULL) ||
4696                     (fp->fr_dif.fd_ptr != NULL) ||
4697                     (fp->fr_flags & FR_FASTROUTE)) {
4698                         softc->ipf_interror = 145;
4699                         error = EINVAL;
4700                         goto donenolock;
4701                 }
4702                 fprev = ipf_auth_rulehead(softc);
4703         } else {
4704                 if (FR_ISACCOUNT(fp->fr_flags))
4705                         fprev = &softc->ipf_acct[in][set];
4706                 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
4707                         fprev = &softc->ipf_rules[in][set];
4708         }
4709         if (fprev == NULL) {
4710                 IPFERROR(15);
4711                 error = ESRCH;
4712                 goto donenolock;
4713         }
4714
4715         if (fg != NULL)
4716                 fprev = &fg->fg_start;
4717
4718         /*
4719          * Copy in extra data for the rule.
4720          */
4721         if (fp->fr_dsize != 0) {
4722                 if (makecopy != 0) {
4723                         KMALLOCS(ptr, void *, fp->fr_dsize);
4724                         if (ptr == NULL) {
4725                                 IPFERROR(16);
4726                                 error = ENOMEM;
4727                                 goto donenolock;
4728                         }
4729
4730                         /*
4731                          * The bcopy case is for when the data is appended
4732                          * to the rule by ipf_in_compat().
4733                          */
4734                         if (uptr >= (void *)fp &&
4735                             uptr < (void *)((char *)fp + fp->fr_size)) {
4736                                 bcopy(uptr, ptr, fp->fr_dsize);
4737                                 error = 0;
4738                         } else {
4739                                 error = COPYIN(uptr, ptr, fp->fr_dsize);
4740                                 if (error != 0) {
4741                                         IPFERROR(17);
4742                                         error = EFAULT;
4743                                         goto donenolock;
4744                                 }
4745                         }
4746                 } else {
4747                         ptr = uptr;
4748                 }
4749                 fp->fr_data = ptr;
4750         } else {
4751                 fp->fr_data = NULL;
4752         }
4753
4754         /*
4755          * Perform per-rule type sanity checks of their members.
4756          * All code after this needs to be aware that allocated memory
4757          * may need to be free'd before exiting.
4758          */
4759         switch (fp->fr_type & ~FR_T_BUILTIN)
4760         {
4761 #if defined(IPFILTER_BPF)
4762         case FR_T_BPFOPC :
4763                 if (fp->fr_dsize == 0) {
4764                         IPFERROR(19);
4765                         error = EINVAL;
4766                         break;
4767                 }
4768                 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
4769                         IPFERROR(20);
4770                         error = EINVAL;
4771                         break;
4772                 }
4773                 break;
4774 #endif
4775         case FR_T_IPF :
4776                 /*
4777                  * Preparation for error case at the bottom of this function.
4778                  */
4779                 if (fp->fr_datype == FRI_LOOKUP)
4780                         fp->fr_dstptr = NULL;
4781                 if (fp->fr_satype == FRI_LOOKUP)
4782                         fp->fr_srcptr = NULL;
4783
4784                 if (fp->fr_dsize != sizeof(fripf_t)) {
4785                         IPFERROR(21);
4786                         error = EINVAL;
4787                         break;
4788                 }
4789
4790                 /*
4791                  * Allowing a rule with both "keep state" and "with oow" is
4792                  * pointless because adding a state entry to the table will
4793                  * fail with the out of window (oow) flag set.
4794                  */
4795                 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) {
4796                         IPFERROR(22);
4797                         error = EINVAL;
4798                         break;
4799                 }
4800
4801                 switch (fp->fr_satype)
4802                 {
4803                 case FRI_BROADCAST :
4804                 case FRI_DYNAMIC :
4805                 case FRI_NETWORK :
4806                 case FRI_NETMASKED :
4807                 case FRI_PEERADDR :
4808                         if (fp->fr_sifpidx < 0) {
4809                                 IPFERROR(23);
4810                                 error = EINVAL;
4811                         }
4812                         break;
4813                 case FRI_LOOKUP :
4814                         fp->fr_srcptr = ipf_findlookup(softc, unit, fp,
4815                                                        &fp->fr_src6,
4816                                                        &fp->fr_smsk6);
4817                         if (fp->fr_srcfunc == NULL) {
4818                                 IPFERROR(132);
4819                                 error = ESRCH;
4820                                 break;
4821                         }
4822                         break;
4823                 case FRI_NORMAL :
4824                         break;
4825                 default :
4826                         IPFERROR(133);
4827                         error = EINVAL;
4828                         break;
4829                 }
4830                 if (error != 0)
4831                         break;
4832
4833                 switch (fp->fr_datype)
4834                 {
4835                 case FRI_BROADCAST :
4836                 case FRI_DYNAMIC :
4837                 case FRI_NETWORK :
4838                 case FRI_NETMASKED :
4839                 case FRI_PEERADDR :
4840                         if (fp->fr_difpidx < 0) {
4841                                 IPFERROR(24);
4842                                 error = EINVAL;
4843                         }
4844                         break;
4845                 case FRI_LOOKUP :
4846                         fp->fr_dstptr = ipf_findlookup(softc, unit, fp,
4847                                                        &fp->fr_dst6,
4848                                                        &fp->fr_dmsk6);
4849                         if (fp->fr_dstfunc == NULL) {
4850                                 IPFERROR(134);
4851                                 error = ESRCH;
4852                         }
4853                         break;
4854                 case FRI_NORMAL :
4855                         break;
4856                 default :
4857                         IPFERROR(135);
4858                         error = EINVAL;
4859                 }
4860                 break;
4861
4862         case FR_T_NONE :
4863         case FR_T_CALLFUNC :
4864         case FR_T_COMPIPF :
4865                 break;
4866
4867         case FR_T_IPFEXPR :
4868                 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) {
4869                         IPFERROR(25);
4870                         error = EINVAL;
4871                 }
4872                 break;
4873
4874         default :
4875                 IPFERROR(26);
4876                 error = EINVAL;
4877                 break;
4878         }
4879         if (error != 0)
4880                 goto donenolock;
4881
4882         if (fp->fr_tif.fd_name != -1) {
4883                 if ((fp->fr_tif.fd_name < 0) ||
4884                     (fp->fr_tif.fd_name >= fp->fr_namelen)) {
4885                         IPFERROR(139);
4886                         error = EINVAL;
4887                         goto donenolock;
4888                 }
4889         }
4890
4891         if (fp->fr_dif.fd_name != -1) {
4892                 if ((fp->fr_dif.fd_name < 0) ||
4893                     (fp->fr_dif.fd_name >= fp->fr_namelen)) {
4894                         IPFERROR(140);
4895                         error = EINVAL;
4896                         goto donenolock;
4897                 }
4898         }
4899
4900         if (fp->fr_rif.fd_name != -1) {
4901                 if ((fp->fr_rif.fd_name < 0) ||
4902                     (fp->fr_rif.fd_name >= fp->fr_namelen)) {
4903                         IPFERROR(141);
4904                         error = EINVAL;
4905                         goto donenolock;
4906                 }
4907         }
4908
4909         /*
4910          * Lookup all the interface names that are part of the rule.
4911          */
4912         error = ipf_synclist(softc, fp, NULL);
4913         if (error != 0)
4914                 goto donenolock;
4915         fp->fr_statecnt = 0;
4916         if (fp->fr_srctrack.ht_max_nodes != 0)
4917                 ipf_rb_ht_init(&fp->fr_srctrack);
4918
4919         /*
4920          * Look for an existing matching filter rule, but don't include the
4921          * next or interface pointer in the comparison (fr_next, fr_ifa).
4922          * This elminates rules which are indentical being loaded.  Checksum
4923          * the constant part of the filter rule to make comparisons quicker
4924          * (this meaning no pointers are included).
4925          */
4926         for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum;
4927              p < pp; p++)
4928                 fp->fr_cksum += *p;
4929         pp = (u_int *)(fp->fr_caddr + fp->fr_dsize);
4930         for (p = (u_int *)fp->fr_data; p < pp; p++)
4931                 fp->fr_cksum += *p;
4932
4933         WRITE_ENTER(&softc->ipf_mutex);
4934
4935         /*
4936          * Now that the filter rule lists are locked, we can walk the
4937          * chain of them without fear.
4938          */
4939         ftail = fprev;
4940         for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) {
4941                 if (fp->fr_collect <= f->fr_collect) {
4942                         ftail = fprev;
4943                         f = NULL;
4944                         break;
4945                 }
4946                 fprev = ftail;
4947         }
4948
4949         for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
4950                 if (ipf_rule_compare(fp, f) == 0)
4951                         break;
4952         }
4953
4954         /*
4955          * If zero'ing statistics, copy current to caller and zero.
4956          */
4957         if (addrem == 2) {
4958                 if (f == NULL) {
4959                         IPFERROR(27);
4960                         error = ESRCH;
4961                 } else {
4962                         /*
4963                          * Copy and reduce lock because of impending copyout.
4964                          * Well we should, but if we do then the atomicity of
4965                          * this call and the correctness of fr_hits and
4966                          * fr_bytes cannot be guaranteed.  As it is, this code
4967                          * only resets them to 0 if they are successfully
4968                          * copied out into user space.
4969                          */
4970                         bcopy((char *)f, (char *)fp, f->fr_size);
4971                         /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */
4972
4973                         /*
4974                          * When we copy this rule back out, set the data
4975                          * pointer to be what it was in user space.
4976                          */
4977                         fp->fr_data = uptr;
4978                         error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY);
4979
4980                         if (error == 0) {
4981                                 if ((f->fr_dsize != 0) && (uptr != NULL))
4982                                         error = COPYOUT(f->fr_data, uptr,
4983                                                         f->fr_dsize);
4984                                         if (error != 0) {
4985                                                 IPFERROR(28);
4986                                                 error = EFAULT;
4987                                         }
4988                                 if (error == 0) {
4989                                         f->fr_hits = 0;
4990                                         f->fr_bytes = 0;
4991                                 }
4992                         }
4993                 }
4994
4995                 if (makecopy != 0) {
4996                         if (ptr != NULL) {
4997                                 KFREES(ptr, fp->fr_dsize);
4998                         }
4999                         KFREES(fp, fp->fr_size);
5000                 }
5001                 RWLOCK_EXIT(&softc->ipf_mutex);
5002                 return error;
5003         }
5004
5005         if (!f) {
5006                 /*
5007                  * At the end of this, ftail must point to the place where the
5008                  * new rule is to be saved/inserted/added.
5009                  * For SIOCAD*FR, this should be the last rule in the group of
5010                  * rules that have equal fr_collect fields.
5011                  * For SIOCIN*FR, ...
5012                  */
5013                 if (req == (ioctlcmd_t)SIOCADAFR ||
5014                     req == (ioctlcmd_t)SIOCADIFR) {
5015
5016                         for (ftail = fprev; (f = *ftail) != NULL; ) {
5017                                 if (f->fr_collect > fp->fr_collect)
5018                                         break;
5019                                 ftail = &f->fr_next;
5020                                 fprev = ftail;
5021                         }
5022                         ftail = fprev;
5023                         f = NULL;
5024                         ptr = NULL;
5025                 } else if (req == (ioctlcmd_t)SIOCINAFR ||
5026                            req == (ioctlcmd_t)SIOCINIFR) {
5027                         while ((f = *fprev) != NULL) {
5028                                 if (f->fr_collect >= fp->fr_collect)
5029                                         break;
5030                                 fprev = &f->fr_next;
5031                         }
5032                         ftail = fprev;
5033                         if (fp->fr_hits != 0) {
5034                                 while (fp->fr_hits && (f = *ftail)) {
5035                                         if (f->fr_collect != fp->fr_collect)
5036                                                 break;
5037                                         fprev = ftail;
5038                                         ftail = &f->fr_next;
5039                                         fp->fr_hits--;
5040                                 }
5041                         }
5042                         f = NULL;
5043                         ptr = NULL;
5044                 }
5045         }
5046
5047         /*
5048          * Request to remove a rule.
5049          */
5050         if (addrem == 1) {
5051                 if (!f) {
5052                         IPFERROR(29);
5053                         error = ESRCH;
5054                 } else {
5055                         /*
5056                          * Do not allow activity from user space to interfere
5057                          * with rules not loaded that way.
5058                          */
5059                         if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
5060                                 IPFERROR(30);
5061                                 error = EPERM;
5062                                 goto done;
5063                         }
5064
5065                         /*
5066                          * Return EBUSY if the rule is being reference by
5067                          * something else (eg state information.)
5068                          */
5069                         if (f->fr_ref > 1) {
5070                                 IPFERROR(31);
5071                                 error = EBUSY;
5072                                 goto done;
5073                         }
5074 #ifdef  IPFILTER_SCAN
5075                         if (f->fr_isctag != -1 &&
5076                             (f->fr_isc != (struct ipscan *)-1))
5077                                 ipf_scan_detachfr(f);
5078 #endif
5079
5080                         if (unit == IPL_LOGAUTH) {
5081                                 error = ipf_auth_precmd(softc, req, f, ftail);
5082                                 goto done;
5083                         }
5084
5085                         ipf_rule_delete(softc, f, unit, set);
5086
5087                         need_free = makecopy;
5088                 }
5089         } else {
5090                 /*
5091                  * Not removing, so we must be adding/inserting a rule.
5092                  */
5093                 if (f != NULL) {
5094                         IPFERROR(32);
5095                         error = EEXIST;
5096                         goto done;
5097                 }
5098                 if (unit == IPL_LOGAUTH) {
5099                         error = ipf_auth_precmd(softc, req, fp, ftail);
5100                         goto done;
5101                 }
5102
5103                 MUTEX_NUKE(&fp->fr_lock);
5104                 MUTEX_INIT(&fp->fr_lock, "filter rule lock");
5105                 if (fp->fr_die != 0)
5106                         ipf_rule_expire_insert(softc, fp, set);
5107
5108                 fp->fr_hits = 0;
5109                 if (makecopy != 0)
5110                         fp->fr_ref = 1;
5111                 fp->fr_pnext = ftail;
5112                 fp->fr_next = *ftail;
5113                 if (fp->fr_next != NULL)
5114                         fp->fr_next->fr_pnext = &fp->fr_next;
5115                 *ftail = fp;
5116                 if (addrem == 0)
5117                         ipf_fixskip(ftail, fp, 1);
5118
5119                 fp->fr_icmpgrp = NULL;
5120                 if (fp->fr_icmphead != -1) {
5121                         group = FR_NAME(fp, fr_icmphead);
5122                         fg = ipf_group_add(softc, group, fp, 0, unit, set);
5123                         fp->fr_icmpgrp = fg;
5124                 }
5125
5126                 fp->fr_grphead = NULL;
5127                 if (fp->fr_grhead != -1) {
5128                         group = FR_NAME(fp, fr_grhead);
5129                         fg = ipf_group_add(softc, group, fp, fp->fr_flags,
5130                                            unit, set);
5131                         fp->fr_grphead = fg;
5132                 }
5133         }
5134 done:
5135         RWLOCK_EXIT(&softc->ipf_mutex);
5136 donenolock:
5137         if (need_free || (error != 0)) {
5138                 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
5139                         if ((fp->fr_satype == FRI_LOOKUP) &&
5140                             (fp->fr_srcptr != NULL))
5141                                 ipf_lookup_deref(softc, fp->fr_srctype,
5142                                                  fp->fr_srcptr);
5143                         if ((fp->fr_datype == FRI_LOOKUP) &&
5144                             (fp->fr_dstptr != NULL))
5145                                 ipf_lookup_deref(softc, fp->fr_dsttype,
5146                                                  fp->fr_dstptr);
5147                 }
5148                 if (fp->fr_grp != NULL) {
5149                         WRITE_ENTER(&softc->ipf_mutex);
5150                         ipf_group_del(softc, fp->fr_grp, fp);
5151                         RWLOCK_EXIT(&softc->ipf_mutex);
5152                 }
5153                 if ((ptr != NULL) && (makecopy != 0)) {
5154                         KFREES(ptr, fp->fr_dsize);
5155                 }
5156                 KFREES(fp, fp->fr_size);
5157         }
5158         return (error);
5159 }
5160
5161
5162 /* ------------------------------------------------------------------------ */
5163 /* Function:   ipf_rule_delete                                              */
5164 /* Returns:    Nil                                                          */
5165 /* Parameters: softc(I) - pointer to soft context main structure            */
5166 /*             f(I)     - pointer to the rule being deleted                 */
5167 /*             ftail(I) - pointer to the pointer to f                       */
5168 /*             unit(I)  - device for which this is for                      */
5169 /*             set(I)   - 1 or 0 (filter set)                               */
5170 /*                                                                          */
5171 /* This function attempts to do what it can to delete a filter rule: remove */
5172 /* it from any linked lists and remove any groups it is responsible for.    */
5173 /* But in the end, removing a rule can only drop the reference count - we   */
5174 /* must use that as the guide for whether or not it can be freed.           */
5175 /* ------------------------------------------------------------------------ */
5176 static void
5177 ipf_rule_delete(softc, f, unit, set)
5178         ipf_main_softc_t *softc;
5179         frentry_t *f;
5180         int unit, set;
5181 {
5182
5183         /*
5184          * If fr_pdnext is set, then the rule is on the expire list, so
5185          * remove it from there.
5186          */
5187         if (f->fr_pdnext != NULL) {
5188                 *f->fr_pdnext = f->fr_dnext;
5189                 if (f->fr_dnext != NULL)
5190                         f->fr_dnext->fr_pdnext = f->fr_pdnext;
5191                 f->fr_pdnext = NULL;
5192                 f->fr_dnext = NULL;
5193         }
5194
5195         ipf_fixskip(f->fr_pnext, f, -1);
5196         if (f->fr_pnext != NULL)
5197                 *f->fr_pnext = f->fr_next;
5198         if (f->fr_next != NULL)
5199                 f->fr_next->fr_pnext = f->fr_pnext;
5200         f->fr_pnext = NULL;
5201         f->fr_next = NULL;
5202
5203         (void) ipf_derefrule(softc, &f);
5204 }
5205
5206 /* ------------------------------------------------------------------------ */
5207 /* Function:   ipf_rule_expire_insert                                       */
5208 /* Returns:    Nil                                                          */
5209 /* Parameters: softc(I) - pointer to soft context main structure            */
5210 /*             f(I)     - pointer to rule to be added to expire list        */
5211 /*             set(I)   - 1 or 0 (filter set)                               */
5212 /*                                                                          */
5213 /* If the new rule has a given expiration time, insert it into the list of  */
5214 /* expiring rules with the ones to be removed first added to the front of   */
5215 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */
5216 /* expiration interval checks.                                              */
5217 /* ------------------------------------------------------------------------ */
5218 static void
5219 ipf_rule_expire_insert(softc, f, set)
5220         ipf_main_softc_t *softc;
5221         frentry_t *f;
5222         int set;
5223 {
5224         frentry_t *fr;
5225
5226         /*
5227          */
5228
5229         f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die);
5230         for (fr = softc->ipf_rule_explist[set]; fr != NULL;
5231              fr = fr->fr_dnext) {
5232                 if (f->fr_die < fr->fr_die)
5233                         break;
5234                 if (fr->fr_dnext == NULL) {
5235                         /*
5236                          * We've got to the last rule and everything
5237                          * wanted to be expired before this new node,
5238                          * so we have to tack it on the end...
5239                          */
5240                         fr->fr_dnext = f;
5241                         f->fr_pdnext = &fr->fr_dnext;
5242                         fr = NULL;
5243                         break;
5244                 }
5245         }
5246
5247         if (softc->ipf_rule_explist[set] == NULL) {
5248                 softc->ipf_rule_explist[set] = f;
5249                 f->fr_pdnext = &softc->ipf_rule_explist[set];
5250         } else if (fr != NULL) {
5251                 f->fr_dnext = fr;
5252                 f->fr_pdnext = fr->fr_pdnext;
5253                 fr->fr_pdnext = &f->fr_dnext;
5254         }
5255 }
5256
5257
5258 /* ------------------------------------------------------------------------ */
5259 /* Function:   ipf_findlookup                                               */
5260 /* Returns:    NULL = failure, else success                                 */
5261 /* Parameters: softc(I) - pointer to soft context main structure            */
5262 /*             unit(I)  - ipf device we want to find match for              */
5263 /*             fp(I)    - rule for which lookup is for                      */
5264 /*             addrp(I) - pointer to lookup information in address struct   */
5265 /*             maskp(O) - pointer to lookup information for storage         */
5266 /*                                                                          */
5267 /* When using pools and hash tables to store addresses for matching in      */
5268 /* rules, it is necessary to resolve both the object referred to by the     */
5269 /* name or address (and return that pointer) and also provide the means by  */
5270 /* which to determine if an address belongs to that object to make the      */
5271 /* packet matching quicker.                                                 */
5272 /* ------------------------------------------------------------------------ */
5273 static void *
5274 ipf_findlookup(softc, unit, fr, addrp, maskp)
5275         ipf_main_softc_t *softc;
5276         int unit;
5277         frentry_t *fr;
5278         i6addr_t *addrp, *maskp;
5279 {
5280         void *ptr = NULL;
5281
5282         switch (addrp->iplookupsubtype)
5283         {
5284         case 0 :
5285                 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype,
5286                                          addrp->iplookupnum,
5287                                          &maskp->iplookupfunc);
5288                 break;
5289         case 1 :
5290                 if (addrp->iplookupname < 0)
5291                         break;
5292                 if (addrp->iplookupname >= fr->fr_namelen)
5293                         break;
5294                 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype,
5295                                           fr->fr_names + addrp->iplookupname,
5296                                           &maskp->iplookupfunc);
5297                 break;
5298         default :
5299                 break;
5300         }
5301
5302         return ptr;
5303 }
5304
5305
5306 /* ------------------------------------------------------------------------ */
5307 /* Function:    ipf_funcinit                                                */
5308 /* Returns:     int - 0 == success, else ESRCH: cannot resolve rule details */
5309 /* Parameters:  softc(I) - pointer to soft context main structure           */
5310 /*              fr(I)    - pointer to filter rule                           */
5311 /*                                                                          */
5312 /* If a rule is a call rule, then check if the function it points to needs  */
5313 /* an init function to be called now the rule has been loaded.              */
5314 /* ------------------------------------------------------------------------ */
5315 static int
5316 ipf_funcinit(softc, fr)
5317         ipf_main_softc_t *softc;
5318         frentry_t *fr;
5319 {
5320         ipfunc_resolve_t *ft;
5321         int err;
5322
5323         IPFERROR(34);
5324         err = ESRCH;
5325
5326         for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5327                 if (ft->ipfu_addr == fr->fr_func) {
5328                         err = 0;
5329                         if (ft->ipfu_init != NULL)
5330                                 err = (*ft->ipfu_init)(softc, fr);
5331                         break;
5332                 }
5333         return err;
5334 }
5335
5336
5337 /* ------------------------------------------------------------------------ */
5338 /* Function:    ipf_funcfini                                                */
5339 /* Returns:     Nil                                                         */
5340 /* Parameters:  softc(I) - pointer to soft context main structure           */
5341 /*              fr(I)    - pointer to filter rule                           */
5342 /*                                                                          */
5343 /* For a given filter rule, call the matching "fini" function if the rule   */
5344 /* is using a known function that would have resulted in the "init" being   */
5345 /* called for ealier.                                                       */
5346 /* ------------------------------------------------------------------------ */
5347 static void
5348 ipf_funcfini(softc, fr)
5349         ipf_main_softc_t *softc;
5350         frentry_t *fr;
5351 {
5352         ipfunc_resolve_t *ft;
5353
5354         for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5355                 if (ft->ipfu_addr == fr->fr_func) {
5356                         if (ft->ipfu_fini != NULL)
5357                                 (void) (*ft->ipfu_fini)(softc, fr);
5358                         break;
5359                 }
5360 }
5361
5362
5363 /* ------------------------------------------------------------------------ */
5364 /* Function:    ipf_findfunc                                                */
5365 /* Returns:     ipfunc_t - pointer to function if found, else NULL          */
5366 /* Parameters:  funcptr(I) - function pointer to lookup                     */
5367 /*                                                                          */
5368 /* Look for a function in the table of known functions.                     */
5369 /* ------------------------------------------------------------------------ */
5370 static ipfunc_t
5371 ipf_findfunc(funcptr)
5372         ipfunc_t funcptr;
5373 {
5374         ipfunc_resolve_t *ft;
5375
5376         for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5377                 if (ft->ipfu_addr == funcptr)
5378                         return funcptr;
5379         return NULL;
5380 }
5381
5382
5383 /* ------------------------------------------------------------------------ */
5384 /* Function:    ipf_resolvefunc                                             */
5385 /* Returns:     int - 0 == success, else error                              */
5386 /* Parameters:  data(IO) - ioctl data pointer to ipfunc_resolve_t struct    */
5387 /*                                                                          */
5388 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */
5389 /* This will either be the function name (if the pointer is set) or the     */
5390 /* function pointer if the name is set.  When found, fill in the other one  */
5391 /* so that the entire, complete, structure can be copied back to user space.*/
5392 /* ------------------------------------------------------------------------ */
5393 int
5394 ipf_resolvefunc(softc, data)
5395         ipf_main_softc_t *softc;
5396         void *data;
5397 {
5398         ipfunc_resolve_t res, *ft;
5399         int error;
5400
5401         error = BCOPYIN(data, &res, sizeof(res));
5402         if (error != 0) {
5403                 IPFERROR(123);
5404                 return EFAULT;
5405         }
5406
5407         if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
5408                 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5409                         if (strncmp(res.ipfu_name, ft->ipfu_name,
5410                                     sizeof(res.ipfu_name)) == 0) {
5411                                 res.ipfu_addr = ft->ipfu_addr;
5412                                 res.ipfu_init = ft->ipfu_init;
5413                                 if (COPYOUT(&res, data, sizeof(res)) != 0) {
5414                                         IPFERROR(35);
5415                                         return EFAULT;
5416                                 }
5417                                 return 0;
5418                         }
5419         }
5420         if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
5421                 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
5422                         if (ft->ipfu_addr == res.ipfu_addr) {
5423                                 (void) strncpy(res.ipfu_name, ft->ipfu_name,
5424                                                sizeof(res.ipfu_name));
5425                                 res.ipfu_init = ft->ipfu_init;
5426                                 if (COPYOUT(&res, data, sizeof(res)) != 0) {
5427                                         IPFERROR(36);
5428                                         return EFAULT;
5429                                 }
5430                                 return 0;
5431                         }
5432         }
5433         IPFERROR(37);
5434         return ESRCH;
5435 }
5436
5437
5438 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
5439      !defined(__FreeBSD__)) || \
5440     FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
5441     OPENBSD_LT_REV(200006)
5442 /*
5443  * From: NetBSD
5444  * ppsratecheck(): packets (or events) per second limitation.
5445  */
5446 int
5447 ppsratecheck(lasttime, curpps, maxpps)
5448         struct timeval *lasttime;
5449         int *curpps;
5450         int maxpps;     /* maximum pps allowed */
5451 {
5452         struct timeval tv, delta;
5453         int rv;
5454
5455         GETKTIME(&tv);
5456
5457         delta.tv_sec = tv.tv_sec - lasttime->tv_sec;
5458         delta.tv_usec = tv.tv_usec - lasttime->tv_usec;
5459         if (delta.tv_usec < 0) {
5460                 delta.tv_sec--;
5461                 delta.tv_usec += 1000000;
5462         }
5463
5464         /*
5465          * check for 0,0 is so that the message will be seen at least once.
5466          * if more than one second have passed since the last update of
5467          * lasttime, reset the counter.
5468          *
5469          * we do increment *curpps even in *curpps < maxpps case, as some may
5470          * try to use *curpps for stat purposes as well.
5471          */
5472         if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
5473             delta.tv_sec >= 1) {
5474                 *lasttime = tv;
5475                 *curpps = 0;
5476                 rv = 1;
5477         } else if (maxpps < 0)
5478                 rv = 1;
5479         else if (*curpps < maxpps)
5480                 rv = 1;
5481         else
5482                 rv = 0;
5483         *curpps = *curpps + 1;
5484
5485         return (rv);
5486 }
5487 #endif
5488
5489
5490 /* ------------------------------------------------------------------------ */
5491 /* Function:    ipf_derefrule                                               */
5492 /* Returns:     int   - 0 == rule freed up, else rule not freed             */
5493 /* Parameters:  fr(I) - pointer to filter rule                              */
5494 /*                                                                          */
5495 /* Decrement the reference counter to a rule by one.  If it reaches zero,   */
5496 /* free it and any associated storage space being used by it.               */
5497 /* ------------------------------------------------------------------------ */
5498 int
5499 ipf_derefrule(softc, frp)
5500         ipf_main_softc_t *softc;
5501         frentry_t **frp;
5502 {
5503         frentry_t *fr;
5504         frdest_t *fdp;
5505
5506         fr = *frp;
5507         *frp = NULL;
5508
5509         MUTEX_ENTER(&fr->fr_lock);
5510         fr->fr_ref--;
5511         if (fr->fr_ref == 0) {
5512                 MUTEX_EXIT(&fr->fr_lock);
5513                 MUTEX_DESTROY(&fr->fr_lock);
5514
5515                 ipf_funcfini(softc, fr);
5516
5517                 fdp = &fr->fr_tif;
5518                 if (fdp->fd_type == FRD_DSTLIST)
5519                         ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5520
5521                 fdp = &fr->fr_rif;
5522                 if (fdp->fd_type == FRD_DSTLIST)
5523                         ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5524
5525                 fdp = &fr->fr_dif;
5526                 if (fdp->fd_type == FRD_DSTLIST)
5527                         ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
5528
5529                 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
5530                     fr->fr_satype == FRI_LOOKUP)
5531                         ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr);
5532                 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
5533                     fr->fr_datype == FRI_LOOKUP)
5534                         ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr);
5535
5536                 if (fr->fr_grp != NULL)
5537                         ipf_group_del(softc, fr->fr_grp, fr);
5538
5539                 if (fr->fr_grphead != NULL)
5540                         ipf_group_del(softc, fr->fr_grphead, fr);
5541
5542                 if (fr->fr_icmpgrp != NULL)
5543                         ipf_group_del(softc, fr->fr_icmpgrp, fr);
5544
5545                 if ((fr->fr_flags & FR_COPIED) != 0) {
5546                         if (fr->fr_dsize) {
5547                                 KFREES(fr->fr_data, fr->fr_dsize);
5548                         }
5549                         KFREES(fr, fr->fr_size);
5550                         return 0;
5551                 }
5552                 return 1;
5553         } else {
5554                 MUTEX_EXIT(&fr->fr_lock);
5555         }
5556         return -1;
5557 }
5558
5559
5560 /* ------------------------------------------------------------------------ */
5561 /* Function:    ipf_grpmapinit                                              */
5562 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
5563 /* Parameters:  fr(I) - pointer to rule to find hash table for              */
5564 /*                                                                          */
5565 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr.  */
5566 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap.                 */
5567 /* ------------------------------------------------------------------------ */
5568 static int
5569 ipf_grpmapinit(softc, fr)
5570         ipf_main_softc_t *softc;
5571         frentry_t *fr;
5572 {
5573         char name[FR_GROUPLEN];
5574         iphtable_t *iph;
5575
5576 #if defined(SNPRINTF) && defined(_KERNEL)
5577         SNPRINTF(name, sizeof(name), "%d", fr->fr_arg);
5578 #else
5579         (void) sprintf(name, "%d", fr->fr_arg);
5580 #endif
5581         iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name);
5582         if (iph == NULL) {
5583                 IPFERROR(38);
5584                 return ESRCH;
5585         }
5586         if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) {
5587                 IPFERROR(39);
5588                 return ESRCH;
5589         }
5590         iph->iph_ref++;
5591         fr->fr_ptr = iph;
5592         return 0;
5593 }
5594
5595
5596 /* ------------------------------------------------------------------------ */
5597 /* Function:    ipf_grpmapfini                                              */
5598 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
5599 /* Parameters:  softc(I) - pointer to soft context main structure           */
5600 /*              fr(I)    - pointer to rule to release hash table for        */
5601 /*                                                                          */
5602 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */
5603 /* be called to undo what ipf_grpmapinit caused to be done.                 */
5604 /* ------------------------------------------------------------------------ */
5605 static int
5606 ipf_grpmapfini(softc, fr)
5607         ipf_main_softc_t *softc;
5608         frentry_t *fr;
5609 {
5610         iphtable_t *iph;
5611         iph = fr->fr_ptr;
5612         if (iph != NULL)
5613                 ipf_lookup_deref(softc, IPLT_HASH, iph);
5614         return 0;
5615 }
5616
5617
5618 /* ------------------------------------------------------------------------ */
5619 /* Function:    ipf_srcgrpmap                                               */
5620 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
5621 /* Parameters:  fin(I)    - pointer to packet information                   */
5622 /*              passp(IO) - pointer to current/new filter decision (unused) */
5623 /*                                                                          */
5624 /* Look for a rule group head in a hash table, using the source address as  */
5625 /* the key, and descend into that group and continue matching rules against */
5626 /* the packet.                                                              */
5627 /* ------------------------------------------------------------------------ */
5628 frentry_t *
5629 ipf_srcgrpmap(fin, passp)
5630         fr_info_t *fin;
5631         u_32_t *passp;
5632 {
5633         frgroup_t *fg;
5634         void *rval;
5635
5636         rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
5637                                  &fin->fin_src);
5638         if (rval == NULL)
5639                 return NULL;
5640
5641         fg = rval;
5642         fin->fin_fr = fg->fg_start;
5643         (void) ipf_scanlist(fin, *passp);
5644         return fin->fin_fr;
5645 }
5646
5647
5648 /* ------------------------------------------------------------------------ */
5649 /* Function:    ipf_dstgrpmap                                               */
5650 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
5651 /* Parameters:  fin(I)    - pointer to packet information                   */
5652 /*              passp(IO) - pointer to current/new filter decision (unused) */
5653 /*                                                                          */
5654 /* Look for a rule group head in a hash table, using the destination        */
5655 /* address as the key, and descend into that group and continue matching    */
5656 /* rules against  the packet.                                               */
5657 /* ------------------------------------------------------------------------ */
5658 frentry_t *
5659 ipf_dstgrpmap(fin, passp)
5660         fr_info_t *fin;
5661         u_32_t *passp;
5662 {
5663         frgroup_t *fg;
5664         void *rval;
5665
5666         rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
5667                                  &fin->fin_dst);
5668         if (rval == NULL)
5669                 return NULL;
5670
5671         fg = rval;
5672         fin->fin_fr = fg->fg_start;
5673         (void) ipf_scanlist(fin, *passp);
5674         return fin->fin_fr;
5675 }
5676
5677 /*
5678  * Queue functions
5679  * ===============
5680  * These functions manage objects on queues for efficient timeouts.  There
5681  * are a number of system defined queues as well as user defined timeouts.
5682  * It is expected that a lock is held in the domain in which the queue
5683  * belongs (i.e. either state or NAT) when calling any of these functions
5684  * that prevents ipf_freetimeoutqueue() from being called at the same time
5685  * as any other.
5686  */
5687
5688
5689 /* ------------------------------------------------------------------------ */
5690 /* Function:    ipf_addtimeoutqueue                                         */
5691 /* Returns:     struct ifqtq * - NULL if malloc fails, else pointer to      */
5692 /*                               timeout queue with given interval.         */
5693 /* Parameters:  parent(I)  - pointer to pointer to parent node of this list */
5694 /*                           of interface queues.                           */
5695 /*              seconds(I) - timeout value in seconds for this queue.       */
5696 /*                                                                          */
5697 /* This routine first looks for a timeout queue that matches the interval   */
5698 /* being requested.  If it finds one, increments the reference counter and  */
5699 /* returns a pointer to it.  If none are found, it allocates a new one and  */
5700 /* inserts it at the top of the list.                                       */
5701 /*                                                                          */
5702 /* Locking.                                                                 */
5703 /* It is assumed that the caller of this function has an appropriate lock   */
5704 /* held (exclusively) in the domain that encompases 'parent'.               */
5705 /* ------------------------------------------------------------------------ */
5706 ipftq_t *
5707 ipf_addtimeoutqueue(softc, parent, seconds)
5708         ipf_main_softc_t *softc;
5709         ipftq_t **parent;
5710         u_int seconds;
5711 {
5712         ipftq_t *ifq;
5713         u_int period;
5714
5715         period = seconds * IPF_HZ_DIVIDE;
5716
5717         MUTEX_ENTER(&softc->ipf_timeoutlock);
5718         for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
5719                 if (ifq->ifq_ttl == period) {
5720                         /*
5721                          * Reset the delete flag, if set, so the structure
5722                          * gets reused rather than freed and reallocated.
5723                          */
5724                         MUTEX_ENTER(&ifq->ifq_lock);
5725                         ifq->ifq_flags &= ~IFQF_DELETE;
5726                         ifq->ifq_ref++;
5727                         MUTEX_EXIT(&ifq->ifq_lock);
5728                         MUTEX_EXIT(&softc->ipf_timeoutlock);
5729
5730                         return ifq;
5731                 }
5732         }
5733
5734         KMALLOC(ifq, ipftq_t *);
5735         if (ifq != NULL) {
5736                 MUTEX_NUKE(&ifq->ifq_lock);
5737                 IPFTQ_INIT(ifq, period, "ipftq mutex");
5738                 ifq->ifq_next = *parent;
5739                 ifq->ifq_pnext = parent;
5740                 ifq->ifq_flags = IFQF_USER;
5741                 ifq->ifq_ref++;
5742                 *parent = ifq;
5743                 softc->ipf_userifqs++;
5744         }
5745         MUTEX_EXIT(&softc->ipf_timeoutlock);
5746         return ifq;
5747 }
5748
5749
5750 /* ------------------------------------------------------------------------ */
5751 /* Function:    ipf_deletetimeoutqueue                                      */
5752 /* Returns:     int    - new reference count value of the timeout queue     */
5753 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
5754 /* Locks:       ifq->ifq_lock                                               */
5755 /*                                                                          */
5756 /* This routine must be called when we're discarding a pointer to a timeout */
5757 /* queue object, taking care of the reference counter.                      */
5758 /*                                                                          */
5759 /* Now that this just sets a DELETE flag, it requires the expire code to    */
5760 /* check the list of user defined timeout queues and call the free function */
5761 /* below (currently commented out) to stop memory leaking.  It is done this */
5762 /* way because the locking may not be sufficient to safely do a free when   */
5763 /* this function is called.                                                 */
5764 /* ------------------------------------------------------------------------ */
5765 int
5766 ipf_deletetimeoutqueue(ifq)
5767         ipftq_t *ifq;
5768 {
5769
5770         ifq->ifq_ref--;
5771         if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) {
5772                 ifq->ifq_flags |= IFQF_DELETE;
5773         }
5774
5775         return ifq->ifq_ref;
5776 }
5777
5778
5779 /* ------------------------------------------------------------------------ */
5780 /* Function:    ipf_freetimeoutqueue                                        */
5781 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
5782 /* Returns:     Nil                                                         */
5783 /*                                                                          */
5784 /* Locking:                                                                 */
5785 /* It is assumed that the caller of this function has an appropriate lock   */
5786 /* held (exclusively) in the domain that encompases the callers "domain".   */
5787 /* The ifq_lock for this structure should not be held.                      */
5788 /*                                                                          */
5789 /* Remove a user defined timeout queue from the list of queues it is in and */
5790 /* tidy up after this is done.                                              */
5791 /* ------------------------------------------------------------------------ */
5792 void
5793 ipf_freetimeoutqueue(softc, ifq)
5794         ipf_main_softc_t *softc;
5795         ipftq_t *ifq;
5796 {
5797
5798         if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
5799             ((ifq->ifq_flags & IFQF_USER) == 0)) {
5800                 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
5801                        (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
5802                        ifq->ifq_ref);
5803                 return;
5804         }
5805
5806         /*
5807          * Remove from its position in the list.
5808          */
5809         *ifq->ifq_pnext = ifq->ifq_next;
5810         if (ifq->ifq_next != NULL)
5811                 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
5812         ifq->ifq_next = NULL;
5813         ifq->ifq_pnext = NULL;
5814
5815         MUTEX_DESTROY(&ifq->ifq_lock);
5816         ATOMIC_DEC(softc->ipf_userifqs);
5817         KFREE(ifq);
5818 }
5819
5820
5821 /* ------------------------------------------------------------------------ */
5822 /* Function:    ipf_deletequeueentry                                        */
5823 /* Returns:     Nil                                                         */
5824 /* Parameters:  tqe(I) - timeout queue entry to delete                      */
5825 /*                                                                          */
5826 /* Remove a tail queue entry from its queue and make it an orphan.          */
5827 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */
5828 /* queue is correct.  We can't, however, call ipf_freetimeoutqueue because  */
5829 /* the correct lock(s) may not be held that would make it safe to do so.    */
5830 /* ------------------------------------------------------------------------ */
5831 void
5832 ipf_deletequeueentry(tqe)
5833         ipftqent_t *tqe;
5834 {
5835         ipftq_t *ifq;
5836
5837         ifq = tqe->tqe_ifq;
5838
5839         MUTEX_ENTER(&ifq->ifq_lock);
5840
5841         if (tqe->tqe_pnext != NULL) {
5842                 *tqe->tqe_pnext = tqe->tqe_next;
5843                 if (tqe->tqe_next != NULL)
5844                         tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5845                 else    /* we must be the tail anyway */
5846                         ifq->ifq_tail = tqe->tqe_pnext;
5847
5848                 tqe->tqe_pnext = NULL;
5849                 tqe->tqe_ifq = NULL;
5850         }
5851
5852         (void) ipf_deletetimeoutqueue(ifq);
5853         ASSERT(ifq->ifq_ref > 0);
5854
5855         MUTEX_EXIT(&ifq->ifq_lock);
5856 }
5857
5858
5859 /* ------------------------------------------------------------------------ */
5860 /* Function:    ipf_queuefront                                              */
5861 /* Returns:     Nil                                                         */
5862 /* Parameters:  tqe(I) - pointer to timeout queue entry                     */
5863 /*                                                                          */
5864 /* Move a queue entry to the front of the queue, if it isn't already there. */
5865 /* ------------------------------------------------------------------------ */
5866 void
5867 ipf_queuefront(tqe)
5868         ipftqent_t *tqe;
5869 {
5870         ipftq_t *ifq;
5871
5872         ifq = tqe->tqe_ifq;
5873         if (ifq == NULL)
5874                 return;
5875
5876         MUTEX_ENTER(&ifq->ifq_lock);
5877         if (ifq->ifq_head != tqe) {
5878                 *tqe->tqe_pnext = tqe->tqe_next;
5879                 if (tqe->tqe_next)
5880                         tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5881                 else
5882                         ifq->ifq_tail = tqe->tqe_pnext;
5883
5884                 tqe->tqe_next = ifq->ifq_head;
5885                 ifq->ifq_head->tqe_pnext = &tqe->tqe_next;
5886                 ifq->ifq_head = tqe;
5887                 tqe->tqe_pnext = &ifq->ifq_head;
5888         }
5889         MUTEX_EXIT(&ifq->ifq_lock);
5890 }
5891
5892
5893 /* ------------------------------------------------------------------------ */
5894 /* Function:    ipf_queueback                                               */
5895 /* Returns:     Nil                                                         */
5896 /* Parameters:  ticks(I) - ipf tick time to use with this call              */
5897 /*              tqe(I)   - pointer to timeout queue entry                   */
5898 /*                                                                          */
5899 /* Move a queue entry to the back of the queue, if it isn't already there.  */
5900 /* We use use ticks to calculate the expiration and mark for when we last   */
5901 /* touched the structure.                                                   */
5902 /* ------------------------------------------------------------------------ */
5903 void
5904 ipf_queueback(ticks, tqe)
5905         u_long ticks;
5906         ipftqent_t *tqe;
5907 {
5908         ipftq_t *ifq;
5909
5910         ifq = tqe->tqe_ifq;
5911         if (ifq == NULL)
5912                 return;
5913         tqe->tqe_die = ticks + ifq->ifq_ttl;
5914         tqe->tqe_touched = ticks;
5915
5916         MUTEX_ENTER(&ifq->ifq_lock);
5917         if (tqe->tqe_next != NULL) {            /* at the end already ? */
5918                 /*
5919                  * Remove from list
5920                  */
5921                 *tqe->tqe_pnext = tqe->tqe_next;
5922                 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5923
5924                 /*
5925                  * Make it the last entry.
5926                  */
5927                 tqe->tqe_next = NULL;
5928                 tqe->tqe_pnext = ifq->ifq_tail;
5929                 *ifq->ifq_tail = tqe;
5930                 ifq->ifq_tail = &tqe->tqe_next;
5931         }
5932         MUTEX_EXIT(&ifq->ifq_lock);
5933 }
5934
5935
5936 /* ------------------------------------------------------------------------ */
5937 /* Function:    ipf_queueappend                                             */
5938 /* Returns:     Nil                                                         */
5939 /* Parameters:  ticks(I)  - ipf tick time to use with this call             */
5940 /*              tqe(I)    - pointer to timeout queue entry                  */
5941 /*              ifq(I)    - pointer to timeout queue                        */
5942 /*              parent(I) - owing object pointer                            */
5943 /*                                                                          */
5944 /* Add a new item to this queue and put it on the very end.                 */
5945 /* We use use ticks to calculate the expiration and mark for when we last   */
5946 /* touched the structure.                                                   */
5947 /* ------------------------------------------------------------------------ */
5948 void
5949 ipf_queueappend(ticks, tqe, ifq, parent)
5950         u_long ticks;
5951         ipftqent_t *tqe;
5952         ipftq_t *ifq;
5953         void *parent;
5954 {
5955
5956         MUTEX_ENTER(&ifq->ifq_lock);
5957         tqe->tqe_parent = parent;
5958         tqe->tqe_pnext = ifq->ifq_tail;
5959         *ifq->ifq_tail = tqe;
5960         ifq->ifq_tail = &tqe->tqe_next;
5961         tqe->tqe_next = NULL;
5962         tqe->tqe_ifq = ifq;
5963         tqe->tqe_die = ticks + ifq->ifq_ttl;
5964         tqe->tqe_touched = ticks;
5965         ifq->ifq_ref++;
5966         MUTEX_EXIT(&ifq->ifq_lock);
5967 }
5968
5969
5970 /* ------------------------------------------------------------------------ */
5971 /* Function:    ipf_movequeue                                               */
5972 /* Returns:     Nil                                                         */
5973 /* Parameters:  tq(I)   - pointer to timeout queue information              */
5974 /*              oifp(I) - old timeout queue entry was on                    */
5975 /*              nifp(I) - new timeout queue to put entry on                 */
5976 /*                                                                          */
5977 /* Move a queue entry from one timeout queue to another timeout queue.      */
5978 /* If it notices that the current entry is already last and does not need   */
5979 /* to move queue, the return.                                               */
5980 /* ------------------------------------------------------------------------ */
5981 void
5982 ipf_movequeue(ticks, tqe, oifq, nifq)
5983         u_long ticks;
5984         ipftqent_t *tqe;
5985         ipftq_t *oifq, *nifq;
5986 {
5987
5988         /*
5989          * If the queue hasn't changed and we last touched this entry at the
5990          * same ipf time, then we're not going to achieve anything by either
5991          * changing the ttl or moving it on the queue.
5992          */
5993         if (oifq == nifq && tqe->tqe_touched == ticks)
5994                 return;
5995
5996         /*
5997          * For any of this to be outside the lock, there is a risk that two
5998          * packets entering simultaneously, with one changing to a different
5999          * queue and one not, could end up with things in a bizarre state.
6000          */
6001         MUTEX_ENTER(&oifq->ifq_lock);
6002
6003         tqe->tqe_touched = ticks;
6004         tqe->tqe_die = ticks + nifq->ifq_ttl;
6005         /*
6006          * Is the operation here going to be a no-op ?
6007          */
6008         if (oifq == nifq) {
6009                 if ((tqe->tqe_next == NULL) ||
6010                     (tqe->tqe_next->tqe_die == tqe->tqe_die)) {
6011                         MUTEX_EXIT(&oifq->ifq_lock);
6012                         return;
6013                 }
6014         }
6015
6016         /*
6017          * Remove from the old queue
6018          */
6019         *tqe->tqe_pnext = tqe->tqe_next;
6020         if (tqe->tqe_next)
6021                 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
6022         else
6023                 oifq->ifq_tail = tqe->tqe_pnext;
6024         tqe->tqe_next = NULL;
6025
6026         /*
6027          * If we're moving from one queue to another, release the
6028          * lock on the old queue and get a lock on the new queue.
6029          * For user defined queues, if we're moving off it, call
6030          * delete in case it can now be freed.
6031          */
6032         if (oifq != nifq) {
6033                 tqe->tqe_ifq = NULL;
6034
6035                 (void) ipf_deletetimeoutqueue(oifq);
6036
6037                 MUTEX_EXIT(&oifq->ifq_lock);
6038
6039                 MUTEX_ENTER(&nifq->ifq_lock);
6040
6041                 tqe->tqe_ifq = nifq;
6042                 nifq->ifq_ref++;
6043         }
6044
6045         /*
6046          * Add to the bottom of the new queue
6047          */
6048         tqe->tqe_pnext = nifq->ifq_tail;
6049         *nifq->ifq_tail = tqe;
6050         nifq->ifq_tail = &tqe->tqe_next;
6051         MUTEX_EXIT(&nifq->ifq_lock);
6052 }
6053
6054
6055 /* ------------------------------------------------------------------------ */
6056 /* Function:    ipf_updateipid                                              */
6057 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
6058 /* Parameters:  fin(I) - pointer to packet information                      */
6059 /*                                                                          */
6060 /* When we are doing NAT, change the IP of every packet to represent a      */
6061 /* single sequence of packets coming from the host, hiding any host         */
6062 /* specific sequencing that might otherwise be revealed.  If the packet is  */
6063 /* a fragment, then store the 'new' IPid in the fragment cache and look up  */
6064 /* the fragment cache for non-leading fragments.  If a non-leading fragment */
6065 /* has no match in the cache, return an error.                              */
6066 /* ------------------------------------------------------------------------ */
6067 static int
6068 ipf_updateipid(fin)
6069         fr_info_t *fin;
6070 {
6071         u_short id, ido, sums;
6072         u_32_t sumd, sum;
6073         ip_t *ip;
6074
6075         if (fin->fin_off != 0) {
6076                 sum = ipf_frag_ipidknown(fin);
6077                 if (sum == 0xffffffff)
6078                         return -1;
6079                 sum &= 0xffff;
6080                 id = (u_short)sum;
6081         } else {
6082                 id = ipf_nextipid(fin);
6083                 if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0)
6084                         (void) ipf_frag_ipidnew(fin, (u_32_t)id);
6085         }
6086
6087         ip = fin->fin_ip;
6088         ido = ntohs(ip->ip_id);
6089         if (id == ido)
6090                 return 0;
6091         ip->ip_id = htons(id);
6092         CALC_SUMD(ido, id, sumd);       /* DESTRUCTIVE MACRO! id,ido change */
6093         sum = (~ntohs(ip->ip_sum)) & 0xffff;
6094         sum += sumd;
6095         sum = (sum >> 16) + (sum & 0xffff);
6096         sum = (sum >> 16) + (sum & 0xffff);
6097         sums = ~(u_short)sum;
6098         ip->ip_sum = htons(sums);
6099         return 0;
6100 }
6101
6102
6103 #ifdef  NEED_FRGETIFNAME
6104 /* ------------------------------------------------------------------------ */
6105 /* Function:    ipf_getifname                                               */
6106 /* Returns:     char *    - pointer to interface name                       */
6107 /* Parameters:  ifp(I)    - pointer to network interface                    */
6108 /*              buffer(O) - pointer to where to store interface name        */
6109 /*                                                                          */
6110 /* Constructs an interface name in the buffer passed.  The buffer passed is */
6111 /* expected to be at least LIFNAMSIZ in bytes big.  If buffer is passed in  */
6112 /* as a NULL pointer then return a pointer to a static array.               */
6113 /* ------------------------------------------------------------------------ */
6114 char *
6115 ipf_getifname(ifp, buffer)
6116         struct ifnet *ifp;
6117         char *buffer;
6118 {
6119         static char namebuf[LIFNAMSIZ];
6120 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
6121      defined(__sgi) || defined(linux) || defined(_AIX51) || \
6122      (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
6123         int unit, space;
6124         char temp[20];
6125         char *s;
6126 # endif
6127
6128         if (buffer == NULL)
6129                 buffer = namebuf;
6130         (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ);
6131         buffer[LIFNAMSIZ - 1] = '\0';
6132 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
6133      defined(__sgi) || defined(_AIX51) || \
6134      (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
6135         for (s = buffer; *s; s++)
6136                 ;
6137         unit = ifp->if_unit;
6138         space = LIFNAMSIZ - (s - buffer);
6139         if ((space > 0) && (unit >= 0)) {
6140 #  if defined(SNPRINTF) && defined(_KERNEL)
6141                 SNPRINTF(temp, sizeof(temp), "%d", unit);
6142 #  else
6143                 (void) sprintf(temp, "%d", unit);
6144 #  endif
6145                 (void) strncpy(s, temp, space);
6146         }
6147 # endif
6148         return buffer;
6149 }
6150 #endif
6151
6152
6153 /* ------------------------------------------------------------------------ */
6154 /* Function:    ipf_ioctlswitch                                             */
6155 /* Returns:     int     - -1 continue processing, else ioctl return value   */
6156 /* Parameters:  unit(I) - device unit opened                                */
6157 /*              data(I) - pointer to ioctl data                             */
6158 /*              cmd(I)  - ioctl command                                     */
6159 /*              mode(I) - mode value                                        */
6160 /*              uid(I)  - uid making the ioctl call                         */
6161 /*              ctx(I)  - pointer to context data                           */
6162 /*                                                                          */
6163 /* Based on the value of unit, call the appropriate ioctl handler or return */
6164 /* EIO if ipfilter is not running.   Also checks if write perms are req'd   */
6165 /* for the device in order to execute the ioctl.  A special case is made    */
6166 /* SIOCIPFINTERROR so that the same code isn't required in every handler.   */
6167 /* The context data pointer is passed through as this is used as the key    */
6168 /* for locating a matching token for continued access for walking lists,    */
6169 /* etc.                                                                     */
6170 /* ------------------------------------------------------------------------ */
6171 int
6172 ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, ctx)
6173         ipf_main_softc_t *softc;
6174         int unit, mode, uid;
6175         ioctlcmd_t cmd;
6176         void *data, *ctx;
6177 {
6178         int error = 0;
6179
6180         switch (cmd)
6181         {
6182         case SIOCIPFINTERROR :
6183                 error = BCOPYOUT(&softc->ipf_interror, data,
6184                                  sizeof(softc->ipf_interror));
6185                 if (error != 0) {
6186                         IPFERROR(40);
6187                         error = EFAULT;
6188                 }
6189                 return error;
6190         default :
6191                 break;
6192         }
6193
6194         switch (unit)
6195         {
6196         case IPL_LOGIPF :
6197                 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx);
6198                 break;
6199         case IPL_LOGNAT :
6200                 if (softc->ipf_running > 0) {
6201                         error = ipf_nat_ioctl(softc, data, cmd, mode,
6202                                               uid, ctx);
6203                 } else {
6204                         IPFERROR(42);
6205                         error = EIO;
6206                 }
6207                 break;
6208         case IPL_LOGSTATE :
6209                 if (softc->ipf_running > 0) {
6210                         error = ipf_state_ioctl(softc, data, cmd, mode,
6211                                                 uid, ctx);
6212                 } else {
6213                         IPFERROR(43);
6214                         error = EIO;
6215                 }
6216                 break;
6217         case IPL_LOGAUTH :
6218                 if (softc->ipf_running > 0) {
6219                         error = ipf_auth_ioctl(softc, data, cmd, mode,
6220                                                uid, ctx);
6221                 } else {
6222                         IPFERROR(44);
6223                         error = EIO;
6224                 }
6225                 break;
6226         case IPL_LOGSYNC :
6227                 if (softc->ipf_running > 0) {
6228                         error = ipf_sync_ioctl(softc, data, cmd, mode,
6229                                                uid, ctx);
6230                 } else {
6231                         error = EIO;
6232                         IPFERROR(45);
6233                 }
6234                 break;
6235         case IPL_LOGSCAN :
6236 #ifdef IPFILTER_SCAN
6237                 if (softc->ipf_running > 0)
6238                         error = ipf_scan_ioctl(softc, data, cmd, mode,
6239                                                uid, ctx);
6240                 else
6241 #endif
6242                 {
6243                         error = EIO;
6244                         IPFERROR(46);
6245                 }
6246                 break;
6247         case IPL_LOGLOOKUP :
6248                 if (softc->ipf_running > 0) {
6249                         error = ipf_lookup_ioctl(softc, data, cmd, mode,
6250                                                  uid, ctx);
6251                 } else {
6252                         error = EIO;
6253                         IPFERROR(47);
6254                 }
6255                 break;
6256         default :
6257                 IPFERROR(48);
6258                 error = EIO;
6259                 break;
6260         }
6261
6262         return error;
6263 }
6264
6265
6266 /*
6267  * This array defines the expected size of objects coming into the kernel
6268  * for the various recognised object types. The first column is flags (see
6269  * below), 2nd column is current size, 3rd column is the version number of
6270  * when the current size became current.
6271  * Flags:
6272  * 1 = minimum size, not absolute size
6273  */
6274 static  int     ipf_objbytes[IPFOBJ_COUNT][3] = {
6275         { 1,    sizeof(struct frentry),         5010000 },      /* 0 */
6276         { 1,    sizeof(struct friostat),        5010000 },
6277         { 0,    sizeof(struct fr_info),         5010000 },
6278         { 0,    sizeof(struct ipf_authstat),    4010100 },
6279         { 0,    sizeof(struct ipfrstat),        5010000 },
6280         { 1,    sizeof(struct ipnat),           5010000 },      /* 5 */
6281         { 0,    sizeof(struct natstat),         5010000 },
6282         { 0,    sizeof(struct ipstate_save),    5010000 },
6283         { 1,    sizeof(struct nat_save),        5010000 },
6284         { 0,    sizeof(struct natlookup),       5010000 },
6285         { 1,    sizeof(struct ipstate),         5010000 },      /* 10 */
6286         { 0,    sizeof(struct ips_stat),        5010000 },
6287         { 0,    sizeof(struct frauth),          5010000 },
6288         { 0,    sizeof(struct ipftune),         4010100 },
6289         { 0,    sizeof(struct nat),             5010000 },
6290         { 0,    sizeof(struct ipfruleiter),     4011400 },      /* 15 */
6291         { 0,    sizeof(struct ipfgeniter),      4011400 },
6292         { 0,    sizeof(struct ipftable),        4011400 },
6293         { 0,    sizeof(struct ipflookupiter),   4011400 },
6294         { 0,    sizeof(struct ipftq) * IPF_TCP_NSTATES },
6295         { 1,    0,                              0       }, /* IPFEXPR */
6296         { 0,    0,                              0       }, /* PROXYCTL */
6297         { 0,    sizeof (struct fripf),          5010000 }
6298 };
6299
6300
6301 /* ------------------------------------------------------------------------ */
6302 /* Function:    ipf_inobj                                                   */
6303 /* Returns:     int     - 0 = success, else failure                         */
6304 /* Parameters:  softc(I) - soft context pointerto work with                 */
6305 /*              data(I)  - pointer to ioctl data                            */
6306 /*              objp(O)  - where to store ipfobj structure                  */
6307 /*              ptr(I)   - pointer to data to copy out                      */
6308 /*              type(I)  - type of structure being moved                    */
6309 /*                                                                          */
6310 /* Copy in the contents of what the ipfobj_t points to.  In future, we      */
6311 /* add things to check for version numbers, sizes, etc, to make it backward */
6312 /* compatible at the ABI for user land.                                     */
6313 /* If objp is not NULL then we assume that the caller wants to see what is  */
6314 /* in the ipfobj_t structure being copied in. As an example, this can tell  */
6315 /* the caller what version of ipfilter the ioctl program was written to.    */
6316 /* ------------------------------------------------------------------------ */
6317 int
6318 ipf_inobj(softc, data, objp, ptr, type)
6319         ipf_main_softc_t *softc;
6320         void *data;
6321         ipfobj_t *objp;
6322         void *ptr;
6323         int type;
6324 {
6325         ipfobj_t obj;
6326         int error;
6327         int size;
6328
6329         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6330                 IPFERROR(49);
6331                 return EINVAL;
6332         }
6333
6334         if (objp == NULL)
6335                 objp = &obj;
6336         error = BCOPYIN(data, objp, sizeof(*objp));
6337         if (error != 0) {
6338                 IPFERROR(124);
6339                 return EFAULT;
6340         }
6341
6342         if (objp->ipfo_type != type) {
6343                 IPFERROR(50);
6344                 return EINVAL;
6345         }
6346
6347         if (objp->ipfo_rev >= ipf_objbytes[type][2]) {
6348                 if ((ipf_objbytes[type][0] & 1) != 0) {
6349                         if (objp->ipfo_size < ipf_objbytes[type][1]) {
6350                                 IPFERROR(51);
6351                                 return EINVAL;
6352                         }
6353                         size =  ipf_objbytes[type][1];
6354                 } else if (objp->ipfo_size == ipf_objbytes[type][1]) {
6355                         size =  objp->ipfo_size;
6356                 } else {
6357                         IPFERROR(52);
6358                         return EINVAL;
6359                 }
6360                 error = COPYIN(objp->ipfo_ptr, ptr, size);
6361                 if (error != 0) {
6362                         IPFERROR(55);
6363                         error = EFAULT;
6364                 }
6365         } else {
6366 #ifdef  IPFILTER_COMPAT
6367                 error = ipf_in_compat(softc, objp, ptr, 0);
6368 #else
6369                 IPFERROR(54);
6370                 error = EINVAL;
6371 #endif
6372         }
6373         return error;
6374 }
6375
6376
6377 /* ------------------------------------------------------------------------ */
6378 /* Function:    ipf_inobjsz                                                 */
6379 /* Returns:     int     - 0 = success, else failure                         */
6380 /* Parameters:  softc(I) - soft context pointerto work with                 */
6381 /*              data(I)  - pointer to ioctl data                            */
6382 /*              ptr(I)   - pointer to store real data in                    */
6383 /*              type(I)  - type of structure being moved                    */
6384 /*              sz(I)    - size of data to copy                             */
6385 /*                                                                          */
6386 /* As per ipf_inobj, except the size of the object to copy in is passed in  */
6387 /* but it must not be smaller than the size defined for the type and the    */
6388 /* type must allow for varied sized objects.  The extra requirement here is */
6389 /* that sz must match the size of the object being passed in - this is not  */
6390 /* not possible nor required in ipf_inobj().                                */
6391 /* ------------------------------------------------------------------------ */
6392 int
6393 ipf_inobjsz(softc, data, ptr, type, sz)
6394         ipf_main_softc_t *softc;
6395         void *data;
6396         void *ptr;
6397         int type, sz;
6398 {
6399         ipfobj_t obj;
6400         int error;
6401
6402         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6403                 IPFERROR(56);
6404                 return EINVAL;
6405         }
6406
6407         error = BCOPYIN(data, &obj, sizeof(obj));
6408         if (error != 0) {
6409                 IPFERROR(125);
6410                 return EFAULT;
6411         }
6412
6413         if (obj.ipfo_type != type) {
6414                 IPFERROR(58);
6415                 return EINVAL;
6416         }
6417
6418         if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6419                 if (((ipf_objbytes[type][0] & 1) == 0) ||
6420                     (sz < ipf_objbytes[type][1])) {
6421                         IPFERROR(57);
6422                         return EINVAL;
6423                 }
6424                 error = COPYIN(obj.ipfo_ptr, ptr, sz);
6425                 if (error != 0) {
6426                         IPFERROR(61);
6427                         error = EFAULT;
6428                 }
6429         } else {
6430 #ifdef  IPFILTER_COMPAT
6431                 error = ipf_in_compat(softc, &obj, ptr, sz);
6432 #else
6433                 IPFERROR(60);
6434                 error = EINVAL;
6435 #endif
6436         }
6437         return error;
6438 }
6439
6440
6441 /* ------------------------------------------------------------------------ */
6442 /* Function:    ipf_outobjsz                                                */
6443 /* Returns:     int     - 0 = success, else failure                         */
6444 /* Parameters:  data(I) - pointer to ioctl data                             */
6445 /*              ptr(I)  - pointer to store real data in                     */
6446 /*              type(I) - type of structure being moved                     */
6447 /*              sz(I)   - size of data to copy                              */
6448 /*                                                                          */
6449 /* As per ipf_outobj, except the size of the object to copy out is passed in*/
6450 /* but it must not be smaller than the size defined for the type and the    */
6451 /* type must allow for varied sized objects.  The extra requirement here is */
6452 /* that sz must match the size of the object being passed in - this is not  */
6453 /* not possible nor required in ipf_outobj().                               */
6454 /* ------------------------------------------------------------------------ */
6455 int
6456 ipf_outobjsz(softc, data, ptr, type, sz)
6457         ipf_main_softc_t *softc;
6458         void *data;
6459         void *ptr;
6460         int type, sz;
6461 {
6462         ipfobj_t obj;
6463         int error;
6464
6465         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6466                 IPFERROR(62);
6467                 return EINVAL;
6468         }
6469
6470         error = BCOPYIN(data, &obj, sizeof(obj));
6471         if (error != 0) {
6472                 IPFERROR(127);
6473                 return EFAULT;
6474         }
6475
6476         if (obj.ipfo_type != type) {
6477                 IPFERROR(63);
6478                 return EINVAL;
6479         }
6480
6481         if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6482                 if (((ipf_objbytes[type][0] & 1) == 0) ||
6483                     (sz < ipf_objbytes[type][1])) {
6484                         IPFERROR(146);
6485                         return EINVAL;
6486                 }
6487                 error = COPYOUT(ptr, obj.ipfo_ptr, sz);
6488                 if (error != 0) {
6489                         IPFERROR(66);
6490                         error = EFAULT;
6491                 }
6492         } else {
6493 #ifdef  IPFILTER_COMPAT
6494                 error = ipf_out_compat(softc, &obj, ptr);
6495 #else
6496                 IPFERROR(65);
6497                 error = EINVAL;
6498 #endif
6499         }
6500         return error;
6501 }
6502
6503
6504 /* ------------------------------------------------------------------------ */
6505 /* Function:    ipf_outobj                                                  */
6506 /* Returns:     int     - 0 = success, else failure                         */
6507 /* Parameters:  data(I) - pointer to ioctl data                             */
6508 /*              ptr(I)  - pointer to store real data in                     */
6509 /*              type(I) - type of structure being moved                     */
6510 /*                                                                          */
6511 /* Copy out the contents of what ptr is to where ipfobj points to.  In      */
6512 /* future, we add things to check for version numbers, sizes, etc, to make  */
6513 /* it backward  compatible at the ABI for user land.                        */
6514 /* ------------------------------------------------------------------------ */
6515 int
6516 ipf_outobj(softc, data, ptr, type)
6517         ipf_main_softc_t *softc;
6518         void *data;
6519         void *ptr;
6520         int type;
6521 {
6522         ipfobj_t obj;
6523         int error;
6524
6525         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6526                 IPFERROR(67);
6527                 return EINVAL;
6528         }
6529
6530         error = BCOPYIN(data, &obj, sizeof(obj));
6531         if (error != 0) {
6532                 IPFERROR(126);
6533                 return EFAULT;
6534         }
6535
6536         if (obj.ipfo_type != type) {
6537                 IPFERROR(68);
6538                 return EINVAL;
6539         }
6540
6541         if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
6542                 if ((ipf_objbytes[type][0] & 1) != 0) {
6543                         if (obj.ipfo_size < ipf_objbytes[type][1]) {
6544                                 IPFERROR(69);
6545                                 return EINVAL;
6546                         }
6547                 } else if (obj.ipfo_size != ipf_objbytes[type][1]) {
6548                         IPFERROR(70);
6549                         return EINVAL;
6550                 }
6551
6552                 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
6553                 if (error != 0) {
6554                         IPFERROR(73);
6555                         error = EFAULT;
6556                 }
6557         } else {
6558 #ifdef  IPFILTER_COMPAT
6559                 error = ipf_out_compat(softc, &obj, ptr);
6560 #else
6561                 IPFERROR(72);
6562                 error = EINVAL;
6563 #endif
6564         }
6565         return error;
6566 }
6567
6568
6569 /* ------------------------------------------------------------------------ */
6570 /* Function:    ipf_outobjk                                                 */
6571 /* Returns:     int     - 0 = success, else failure                         */
6572 /* Parameters:  obj(I)  - pointer to data description structure             */
6573 /*              ptr(I)  - pointer to kernel data to copy out                */
6574 /*                                                                          */
6575 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/
6576 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */
6577 /* already populated with information and now we just need to use it.       */
6578 /* There is no need for this function to have a "type" parameter as there   */
6579 /* is no point in validating information that comes from the kernel with    */
6580 /* itself.                                                                  */
6581 /* ------------------------------------------------------------------------ */
6582 int
6583 ipf_outobjk(softc, obj, ptr)
6584         ipf_main_softc_t *softc;
6585         ipfobj_t *obj;
6586         void *ptr;
6587 {
6588         int type = obj->ipfo_type;
6589         int error;
6590
6591         if ((type < 0) || (type >= IPFOBJ_COUNT)) {
6592                 IPFERROR(147);
6593                 return EINVAL;
6594         }
6595
6596         if (obj->ipfo_rev >= ipf_objbytes[type][2]) {
6597                 if ((ipf_objbytes[type][0] & 1) != 0) {
6598                         if (obj->ipfo_size < ipf_objbytes[type][1]) {
6599                                 IPFERROR(148);
6600                                 return EINVAL;
6601                         }
6602
6603                 } else if (obj->ipfo_size != ipf_objbytes[type][1]) {
6604                         IPFERROR(149);
6605                         return EINVAL;
6606                 }
6607
6608                 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size);
6609                 if (error != 0) {
6610                         IPFERROR(150);
6611                         error = EFAULT;
6612                 }
6613         } else {
6614 #ifdef  IPFILTER_COMPAT
6615                 error = ipf_out_compat(softc, obj, ptr);
6616 #else
6617                 IPFERROR(151);
6618                 error = EINVAL;
6619 #endif
6620         }
6621         return error;
6622 }
6623
6624
6625 /* ------------------------------------------------------------------------ */
6626 /* Function:    ipf_checkl4sum                                              */
6627 /* Returns:     int     - 0 = good, -1 = bad, 1 = cannot check              */
6628 /* Parameters:  fin(I) - pointer to packet information                      */
6629 /*                                                                          */
6630 /* If possible, calculate the layer 4 checksum for the packet.  If this is  */
6631 /* not possible, return without indicating a failure or success but in a    */
6632 /* way that is ditinguishable. This function should only be called by the   */
6633 /* ipf_checkv6sum() for each platform.                                      */
6634 /* ------------------------------------------------------------------------ */
6635 INLINE int
6636 ipf_checkl4sum(fin)
6637         fr_info_t *fin;
6638 {
6639         u_short sum, hdrsum, *csump;
6640         udphdr_t *udp;
6641         int dosum;
6642
6643         /*
6644          * If the TCP packet isn't a fragment, isn't too short and otherwise
6645          * isn't already considered "bad", then validate the checksum.  If
6646          * this check fails then considered the packet to be "bad".
6647          */
6648         if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0)
6649                 return 1;
6650
6651         DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p);
6652         if (fin->fin_out == 1) {
6653                 fin->fin_cksum = FI_CK_SUMOK;
6654                 return 0;
6655         }
6656
6657         csump = NULL;
6658         hdrsum = 0;
6659         dosum = 0;
6660         sum = 0;
6661
6662         switch (fin->fin_p)
6663         {
6664         case IPPROTO_TCP :
6665                 csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
6666                 dosum = 1;
6667                 break;
6668
6669         case IPPROTO_UDP :
6670                 udp = fin->fin_dp;
6671                 if (udp->uh_sum != 0) {
6672                         csump = &udp->uh_sum;
6673                         dosum = 1;
6674                 }
6675                 break;
6676
6677 #ifdef USE_INET6
6678         case IPPROTO_ICMPV6 :
6679                 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum;
6680                 dosum = 1;
6681                 break;
6682 #endif
6683
6684         case IPPROTO_ICMP :
6685                 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
6686                 dosum = 1;
6687                 break;
6688
6689         default :
6690                 return 1;
6691                 /*NOTREACHED*/
6692         }
6693
6694         if (csump != NULL)
6695                 hdrsum = *csump;
6696
6697         if (dosum) {
6698                 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp);
6699         }
6700 #if !defined(_KERNEL)
6701         if (sum == hdrsum) {
6702                 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
6703         } else {
6704                 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
6705         }
6706 #endif
6707         DT2(l4sums, u_short, hdrsum, u_short, sum);
6708 #ifdef USE_INET6
6709         if (hdrsum == sum || (sum == 0 && fin->fin_p == IPPROTO_ICMPV6)) {
6710 #else
6711         if (hdrsum == sum) {
6712 #endif
6713                 fin->fin_cksum = FI_CK_SUMOK;
6714                 return 0;
6715         }
6716         fin->fin_cksum = FI_CK_BAD;
6717         return -1;
6718 }
6719
6720
6721 /* ------------------------------------------------------------------------ */
6722 /* Function:    ipf_ifpfillv4addr                                           */
6723 /* Returns:     int     - 0 = address update, -1 = address not updated      */
6724 /* Parameters:  atype(I)   - type of network address update to perform      */
6725 /*              sin(I)     - pointer to source of address information       */
6726 /*              mask(I)    - pointer to source of netmask information       */
6727 /*              inp(I)     - pointer to destination address store           */
6728 /*              inpmask(I) - pointer to destination netmask store           */
6729 /*                                                                          */
6730 /* Given a type of network address update (atype) to perform, copy          */
6731 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
6732 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
6733 /* which case the operation fails.  For all values of atype other than      */
6734 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
6735 /* value.                                                                   */
6736 /* ------------------------------------------------------------------------ */
6737 int
6738 ipf_ifpfillv4addr(atype, sin, mask, inp, inpmask)
6739         int atype;
6740         struct sockaddr_in *sin, *mask;
6741         struct in_addr *inp, *inpmask;
6742 {
6743         if (inpmask != NULL && atype != FRI_NETMASKED)
6744                 inpmask->s_addr = 0xffffffff;
6745
6746         if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
6747                 if (atype == FRI_NETMASKED) {
6748                         if (inpmask == NULL)
6749                                 return -1;
6750                         inpmask->s_addr = mask->sin_addr.s_addr;
6751                 }
6752                 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr;
6753         } else {
6754                 inp->s_addr = sin->sin_addr.s_addr;
6755         }
6756         return 0;
6757 }
6758
6759
6760 #ifdef  USE_INET6
6761 /* ------------------------------------------------------------------------ */
6762 /* Function:    ipf_ifpfillv6addr                                           */
6763 /* Returns:     int     - 0 = address update, -1 = address not updated      */
6764 /* Parameters:  atype(I)   - type of network address update to perform      */
6765 /*              sin(I)     - pointer to source of address information       */
6766 /*              mask(I)    - pointer to source of netmask information       */
6767 /*              inp(I)     - pointer to destination address store           */
6768 /*              inpmask(I) - pointer to destination netmask store           */
6769 /*                                                                          */
6770 /* Given a type of network address update (atype) to perform, copy          */
6771 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
6772 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
6773 /* which case the operation fails.  For all values of atype other than      */
6774 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
6775 /* value.                                                                   */
6776 /* ------------------------------------------------------------------------ */
6777 int
6778 ipf_ifpfillv6addr(atype, sin, mask, inp, inpmask)
6779         int atype;
6780         struct sockaddr_in6 *sin, *mask;
6781         i6addr_t *inp, *inpmask;
6782 {
6783         i6addr_t *src, *and;
6784
6785         src = (i6addr_t *)&sin->sin6_addr;
6786         and = (i6addr_t *)&mask->sin6_addr;
6787
6788         if (inpmask != NULL && atype != FRI_NETMASKED) {
6789                 inpmask->i6[0] = 0xffffffff;
6790                 inpmask->i6[1] = 0xffffffff;
6791                 inpmask->i6[2] = 0xffffffff;
6792                 inpmask->i6[3] = 0xffffffff;
6793         }
6794
6795         if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
6796                 if (atype == FRI_NETMASKED) {
6797                         if (inpmask == NULL)
6798                                 return -1;
6799                         inpmask->i6[0] = and->i6[0];
6800                         inpmask->i6[1] = and->i6[1];
6801                         inpmask->i6[2] = and->i6[2];
6802                         inpmask->i6[3] = and->i6[3];
6803                 }
6804
6805                 inp->i6[0] = src->i6[0] & and->i6[0];
6806                 inp->i6[1] = src->i6[1] & and->i6[1];
6807                 inp->i6[2] = src->i6[2] & and->i6[2];
6808                 inp->i6[3] = src->i6[3] & and->i6[3];
6809         } else {
6810                 inp->i6[0] = src->i6[0];
6811                 inp->i6[1] = src->i6[1];
6812                 inp->i6[2] = src->i6[2];
6813                 inp->i6[3] = src->i6[3];
6814         }
6815         return 0;
6816 }
6817 #endif
6818
6819
6820 /* ------------------------------------------------------------------------ */
6821 /* Function:    ipf_matchtag                                                */
6822 /* Returns:     0 == mismatch, 1 == match.                                  */
6823 /* Parameters:  tag1(I) - pointer to first tag to compare                   */
6824 /*              tag2(I) - pointer to second tag to compare                  */
6825 /*                                                                          */
6826 /* Returns true (non-zero) or false(0) if the two tag structures can be     */
6827 /* considered to be a match or not match, respectively.  The tag is 16      */
6828 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so    */
6829 /* compare the ints instead, for speed. tag1 is the master of the           */
6830 /* comparison.  This function should only be called with both tag1 and tag2 */
6831 /* as non-NULL pointers.                                                    */
6832 /* ------------------------------------------------------------------------ */
6833 int
6834 ipf_matchtag(tag1, tag2)
6835         ipftag_t *tag1, *tag2;
6836 {
6837         if (tag1 == tag2)
6838                 return 1;
6839
6840         if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0))
6841                 return 1;
6842
6843         if ((tag1->ipt_num[0] == tag2->ipt_num[0]) &&
6844             (tag1->ipt_num[1] == tag2->ipt_num[1]) &&
6845             (tag1->ipt_num[2] == tag2->ipt_num[2]) &&
6846             (tag1->ipt_num[3] == tag2->ipt_num[3]))
6847                 return 1;
6848         return 0;
6849 }
6850
6851
6852 /* ------------------------------------------------------------------------ */
6853 /* Function:    ipf_coalesce                                                */
6854 /* Returns:     1 == success, -1 == failure, 0 == no change                 */
6855 /* Parameters:  fin(I) - pointer to packet information                      */
6856 /*                                                                          */
6857 /* Attempt to get all of the packet data into a single, contiguous buffer.  */
6858 /* If this call returns a failure then the buffers have also been freed.    */
6859 /* ------------------------------------------------------------------------ */
6860 int
6861 ipf_coalesce(fin)
6862         fr_info_t *fin;
6863 {
6864
6865         if ((fin->fin_flx & FI_COALESCE) != 0)
6866                 return 1;
6867
6868         /*
6869          * If the mbuf pointers indicate that there is no mbuf to work with,
6870          * return but do not indicate success or failure.
6871          */
6872         if (fin->fin_m == NULL || fin->fin_mp == NULL)
6873                 return 0;
6874
6875 #if defined(_KERNEL)
6876         if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
6877                 ipf_main_softc_t *softc = fin->fin_main_soft;
6878
6879                 DT1(frb_coalesce, fr_info_t *, fin);
6880                 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces);
6881 # ifdef MENTAT
6882                 FREE_MB_T(*fin->fin_mp);
6883 # endif
6884                 fin->fin_reason = FRB_COALESCE;
6885                 *fin->fin_mp = NULL;
6886                 fin->fin_m = NULL;
6887                 return -1;
6888         }
6889 #else
6890         fin = fin;      /* LINT */
6891 #endif
6892         return 1;
6893 }
6894
6895
6896 /*
6897  * The following table lists all of the tunable variables that can be
6898  * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt.  The format of each row
6899  * in the table below is as follows:
6900  *
6901  * pointer to value, name of value, minimum, maximum, size of the value's
6902  *     container, value attribute flags
6903  *
6904  * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED
6905  * means the value can only be written to when IPFilter is loaded but disabled.
6906  * The obvious implication is if neither of these are set then the value can be
6907  * changed at any time without harm.
6908  */
6909
6910
6911 /* ------------------------------------------------------------------------ */
6912 /* Function:    ipf_tune_findbycookie                                       */
6913 /* Returns:     NULL = search failed, else pointer to tune struct           */
6914 /* Parameters:  cookie(I) - cookie value to search for amongst tuneables    */
6915 /*              next(O)   - pointer to place to store the cookie for the    */
6916 /*                          "next" tuneable, if it is desired.              */
6917 /*                                                                          */
6918 /* This function is used to walk through all of the existing tunables with  */
6919 /* successive calls.  It searches the known tunables for the one which has  */
6920 /* a matching value for "cookie" - ie its address.  When returning a match, */
6921 /* the next one to be found may be returned inside next.                    */
6922 /* ------------------------------------------------------------------------ */
6923 static ipftuneable_t *
6924 ipf_tune_findbycookie(ptop, cookie, next)
6925         ipftuneable_t **ptop;
6926         void *cookie, **next;
6927 {
6928         ipftuneable_t *ta, **tap;
6929
6930         for (ta = *ptop; ta->ipft_name != NULL; ta++)
6931                 if (ta == cookie) {
6932                         if (next != NULL) {
6933                                 /*
6934                                  * If the next entry in the array has a name
6935                                  * present, then return a pointer to it for
6936                                  * where to go next, else return a pointer to
6937                                  * the dynaminc list as a key to search there
6938                                  * next.  This facilitates a weak linking of
6939                                  * the two "lists" together.
6940                                  */
6941                                 if ((ta + 1)->ipft_name != NULL)
6942                                         *next = ta + 1;
6943                                 else
6944                                         *next = ptop;
6945                         }
6946                         return ta;
6947                 }
6948
6949         for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next)
6950                 if (tap == cookie) {
6951                         if (next != NULL)
6952                                 *next = &ta->ipft_next;
6953                         return ta;
6954                 }
6955
6956         if (next != NULL)
6957                 *next = NULL;
6958         return NULL;
6959 }
6960
6961
6962 /* ------------------------------------------------------------------------ */
6963 /* Function:    ipf_tune_findbyname                                         */
6964 /* Returns:     NULL = search failed, else pointer to tune struct           */
6965 /* Parameters:  name(I) - name of the tuneable entry to find.               */
6966 /*                                                                          */
6967 /* Search the static array of tuneables and the list of dynamic tuneables   */
6968 /* for an entry with a matching name.  If we can find one, return a pointer */
6969 /* to the matching structure.                                               */
6970 /* ------------------------------------------------------------------------ */
6971 static ipftuneable_t *
6972 ipf_tune_findbyname(top, name)
6973         ipftuneable_t *top;
6974         const char *name;
6975 {
6976         ipftuneable_t *ta;
6977
6978         for (ta = top; ta != NULL; ta = ta->ipft_next)
6979                 if (!strcmp(ta->ipft_name, name)) {
6980                         return ta;
6981                 }
6982
6983         return NULL;
6984 }
6985
6986
6987 /* ------------------------------------------------------------------------ */
6988 /* Function:    ipf_tune_add_array                                          */
6989 /* Returns:     int - 0 == success, else failure                            */
6990 /* Parameters:  newtune - pointer to new tune array to add to tuneables     */
6991 /*                                                                          */
6992 /* Appends tune structures from the array passed in (newtune) to the end of */
6993 /* the current list of "dynamic" tuneable parameters.                       */
6994 /* If any entry to be added is already present (by name) then the operation */
6995 /* is aborted - entries that have been added are removed before returning.  */
6996 /* An entry with no name (NULL) is used as the indication that the end of   */
6997 /* the array has been reached.                                              */
6998 /* ------------------------------------------------------------------------ */
6999 int
7000 ipf_tune_add_array(softc, newtune)
7001         ipf_main_softc_t *softc;
7002         ipftuneable_t *newtune;
7003 {
7004         ipftuneable_t *nt, *dt;
7005         int error = 0;
7006
7007         for (nt = newtune; nt->ipft_name != NULL; nt++) {
7008                 error = ipf_tune_add(softc, nt);
7009                 if (error != 0) {
7010                         for (dt = newtune; dt != nt; dt++) {
7011                                 (void) ipf_tune_del(softc, dt);
7012                         }
7013                 }
7014         }
7015
7016         return error;
7017 }
7018
7019
7020 /* ------------------------------------------------------------------------ */
7021 /* Function:    ipf_tune_array_link                                         */
7022 /* Returns:     0 == success, -1 == failure                                 */
7023 /* Parameters:  softc(I) - soft context pointerto work with                 */
7024 /*              array(I) - pointer to an array of tuneables                 */
7025 /*                                                                          */
7026 /* Given an array of tunables (array), append them to the current list of   */
7027 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the  */
7028 /* the array for being appended to the list, initialise all of the next     */
7029 /* pointers so we don't need to walk parts of it with ++ and others with    */
7030 /* next. The array is expected to have an entry with a NULL name as the     */
7031 /* terminator. Trying to add an array with no non-NULL names will return as */
7032 /* a failure.                                                               */
7033 /* ------------------------------------------------------------------------ */
7034 int
7035 ipf_tune_array_link(softc, array)
7036         ipf_main_softc_t *softc;
7037         ipftuneable_t *array;
7038 {
7039         ipftuneable_t *t, **p;
7040
7041         t = array;
7042         if (t->ipft_name == NULL)
7043                 return -1;
7044
7045         for (; t[1].ipft_name != NULL; t++)
7046                 t[0].ipft_next = &t[1];
7047         t->ipft_next = NULL;
7048
7049         /*
7050          * Since a pointer to the last entry isn't kept, we need to find it
7051          * each time we want to add new variables to the list.
7052          */
7053         for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
7054                 if (t->ipft_name == NULL)
7055                         break;
7056         *p = array;
7057
7058         return 0;
7059 }
7060
7061
7062 /* ------------------------------------------------------------------------ */
7063 /* Function:    ipf_tune_array_unlink                                       */
7064 /* Returns:     0 == success, -1 == failure                                 */
7065 /* Parameters:  softc(I) - soft context pointerto work with                 */
7066 /*              array(I) - pointer to an array of tuneables                 */
7067 /*                                                                          */
7068 /* ------------------------------------------------------------------------ */
7069 int
7070 ipf_tune_array_unlink(softc, array)
7071         ipf_main_softc_t *softc;
7072         ipftuneable_t *array;
7073 {
7074         ipftuneable_t *t, **p;
7075
7076         for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
7077                 if (t == array)
7078                         break;
7079         if (t == NULL)
7080                 return -1;
7081
7082         for (; t[1].ipft_name != NULL; t++)
7083                 ;
7084
7085         *p = t->ipft_next;
7086
7087         return 0;
7088 }
7089
7090
7091 /* ------------------------------------------------------------------------ */
7092 /* Function:   ipf_tune_array_copy                                          */
7093 /* Returns:    NULL = failure, else pointer to new array                    */
7094 /* Parameters: base(I)     - pointer to structure base                      */
7095 /*             size(I)     - size of the array at template                  */
7096 /*             template(I) - original array to copy                         */
7097 /*                                                                          */
7098 /* Allocate memory for a new set of tuneable values and copy everything     */
7099 /* from template into the new region of memory.  The new region is full of  */
7100 /* uninitialised pointers (ipft_next) so set them up.  Now, ipftp_offset... */
7101 /*                                                                          */
7102 /* NOTE: the following assumes that sizeof(long) == sizeof(void *)          */
7103 /* In the array template, ipftp_offset is the offset (in bytes) of the      */
7104 /* location of the tuneable value inside the structure pointed to by base.  */
7105 /* As ipftp_offset is a union over the pointers to the tuneable values, if  */
7106 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in   */
7107 /* ipftp_void that points to the stored value.                              */
7108 /* ------------------------------------------------------------------------ */
7109 ipftuneable_t *
7110 ipf_tune_array_copy(base, size, template)
7111         void *base;
7112         size_t size;
7113         ipftuneable_t *template;
7114 {
7115         ipftuneable_t *copy;
7116         int i;
7117
7118
7119         KMALLOCS(copy, ipftuneable_t *, size);
7120         if (copy == NULL) {
7121                 return NULL;
7122         }
7123         bcopy(template, copy, size);
7124
7125         for (i = 0; copy[i].ipft_name; i++) {
7126                 copy[i].ipft_una.ipftp_offset += (u_long)base;
7127                 copy[i].ipft_next = copy + i + 1;
7128         }
7129
7130         return copy;
7131 }
7132
7133
7134 /* ------------------------------------------------------------------------ */
7135 /* Function:    ipf_tune_add                                                */
7136 /* Returns:     int - 0 == success, else failure                            */
7137 /* Parameters:  newtune - pointer to new tune entry to add to tuneables     */
7138 /*                                                                          */
7139 /* Appends tune structures from the array passed in (newtune) to the end of */
7140 /* the current list of "dynamic" tuneable parameters.  Once added, the      */
7141 /* owner of the object is not expected to ever change "ipft_next".          */
7142 /* ------------------------------------------------------------------------ */
7143 int
7144 ipf_tune_add(softc, newtune)
7145         ipf_main_softc_t *softc;
7146         ipftuneable_t *newtune;
7147 {
7148         ipftuneable_t *ta, **tap;
7149
7150         ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name);
7151         if (ta != NULL) {
7152                 IPFERROR(74);
7153                 return EEXIST;
7154         }
7155
7156         for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next)
7157                 ;
7158
7159         newtune->ipft_next = NULL;
7160         *tap = newtune;
7161         return 0;
7162 }
7163
7164
7165 /* ------------------------------------------------------------------------ */
7166 /* Function:    ipf_tune_del                                                */
7167 /* Returns:     int - 0 == success, else failure                            */
7168 /* Parameters:  oldtune - pointer to tune entry to remove from the list of  */
7169 /*                        current dynamic tuneables                         */
7170 /*                                                                          */
7171 /* Search for the tune structure, by pointer, in the list of those that are */
7172 /* dynamically added at run time.  If found, adjust the list so that this   */
7173 /* structure is no longer part of it.                                       */
7174 /* ------------------------------------------------------------------------ */
7175 int
7176 ipf_tune_del(softc, oldtune)
7177         ipf_main_softc_t *softc;
7178         ipftuneable_t *oldtune;
7179 {
7180         ipftuneable_t *ta, **tap;
7181         int error = 0;
7182
7183         for (tap = &softc->ipf_tuners; (ta = *tap) != NULL;
7184              tap = &ta->ipft_next) {
7185                 if (ta == oldtune) {
7186                         *tap = oldtune->ipft_next;
7187                         oldtune->ipft_next = NULL;
7188                         break;
7189                 }
7190         }
7191
7192         if (ta == NULL) {
7193                 error = ESRCH;
7194                 IPFERROR(75);
7195         }
7196         return error;
7197 }
7198
7199
7200 /* ------------------------------------------------------------------------ */
7201 /* Function:    ipf_tune_del_array                                          */
7202 /* Returns:     int - 0 == success, else failure                            */
7203 /* Parameters:  oldtune - pointer to tuneables array                        */
7204 /*                                                                          */
7205 /* Remove each tuneable entry in the array from the list of "dynamic"       */
7206 /* tunables.  If one entry should fail to be found, an error will be        */
7207 /* returned and no further ones removed.                                    */
7208 /* An entry with a NULL name is used as the indicator of the last entry in  */
7209 /* the array.                                                               */
7210 /* ------------------------------------------------------------------------ */
7211 int
7212 ipf_tune_del_array(softc, oldtune)
7213         ipf_main_softc_t *softc;
7214         ipftuneable_t *oldtune;
7215 {
7216         ipftuneable_t *ot;
7217         int error = 0;
7218
7219         for (ot = oldtune; ot->ipft_name != NULL; ot++) {
7220                 error = ipf_tune_del(softc, ot);
7221                 if (error != 0)
7222                         break;
7223         }
7224
7225         return error;
7226
7227 }
7228
7229
7230 /* ------------------------------------------------------------------------ */
7231 /* Function:    ipf_tune                                                    */
7232 /* Returns:     int - 0 == success, else failure                            */
7233 /* Parameters:  cmd(I)  - ioctl command number                              */
7234 /*              data(I) - pointer to ioctl data structure                   */
7235 /*                                                                          */
7236 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET.  These  */
7237 /* three ioctls provide the means to access and control global variables    */
7238 /* within IPFilter, allowing (for example) timeouts and table sizes to be   */
7239 /* changed without rebooting, reloading or recompiling.  The initialisation */
7240 /* and 'destruction' routines of the various components of ipfilter are all */
7241 /* each responsible for handling their own values being too big.            */
7242 /* ------------------------------------------------------------------------ */
7243 int
7244 ipf_ipftune(softc, cmd, data)
7245         ipf_main_softc_t *softc;
7246         ioctlcmd_t cmd;
7247         void *data;
7248 {
7249         ipftuneable_t *ta;
7250         ipftune_t tu;
7251         void *cookie;
7252         int error;
7253
7254         error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE);
7255         if (error != 0)
7256                 return error;
7257
7258         tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
7259         cookie = tu.ipft_cookie;
7260         ta = NULL;
7261
7262         switch (cmd)
7263         {
7264         case SIOCIPFGETNEXT :
7265                 /*
7266                  * If cookie is non-NULL, assume it to be a pointer to the last
7267                  * entry we looked at, so find it (if possible) and return a
7268                  * pointer to the next one after it.  The last entry in the
7269                  * the table is a NULL entry, so when we get to it, set cookie
7270                  * to NULL and return that, indicating end of list, erstwhile
7271                  * if we come in with cookie set to NULL, we are starting anew
7272                  * at the front of the list.
7273                  */
7274                 if (cookie != NULL) {
7275                         ta = ipf_tune_findbycookie(&softc->ipf_tuners,
7276                                                    cookie, &tu.ipft_cookie);
7277                 } else {
7278                         ta = softc->ipf_tuners;
7279                         tu.ipft_cookie = ta + 1;
7280                 }
7281                 if (ta != NULL) {
7282                         /*
7283                          * Entry found, but does the data pointed to by that
7284                          * row fit in what we can return?
7285                          */
7286                         if (ta->ipft_sz > sizeof(tu.ipft_un)) {
7287                                 IPFERROR(76);
7288                                 return EINVAL;
7289                         }
7290
7291                         tu.ipft_vlong = 0;
7292                         if (ta->ipft_sz == sizeof(u_long))
7293                                 tu.ipft_vlong = *ta->ipft_plong;
7294                         else if (ta->ipft_sz == sizeof(u_int))
7295                                 tu.ipft_vint = *ta->ipft_pint;
7296                         else if (ta->ipft_sz == sizeof(u_short))
7297                                 tu.ipft_vshort = *ta->ipft_pshort;
7298                         else if (ta->ipft_sz == sizeof(u_char))
7299                                 tu.ipft_vchar = *ta->ipft_pchar;
7300
7301                         tu.ipft_sz = ta->ipft_sz;
7302                         tu.ipft_min = ta->ipft_min;
7303                         tu.ipft_max = ta->ipft_max;
7304                         tu.ipft_flags = ta->ipft_flags;
7305                         bcopy(ta->ipft_name, tu.ipft_name,
7306                               MIN(sizeof(tu.ipft_name),
7307                                   strlen(ta->ipft_name) + 1));
7308                 }
7309                 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7310                 break;
7311
7312         case SIOCIPFGET :
7313         case SIOCIPFSET :
7314                 /*
7315                  * Search by name or by cookie value for a particular entry
7316                  * in the tuning paramter table.
7317                  */
7318                 IPFERROR(77);
7319                 error = ESRCH;
7320                 if (cookie != NULL) {
7321                         ta = ipf_tune_findbycookie(&softc->ipf_tuners,
7322                                                    cookie, NULL);
7323                         if (ta != NULL)
7324                                 error = 0;
7325                 } else if (tu.ipft_name[0] != '\0') {
7326                         ta = ipf_tune_findbyname(softc->ipf_tuners,
7327                                                  tu.ipft_name);
7328                         if (ta != NULL)
7329                                 error = 0;
7330                 }
7331                 if (error != 0)
7332                         break;
7333
7334                 if (cmd == (ioctlcmd_t)SIOCIPFGET) {
7335                         /*
7336                          * Fetch the tuning parameters for a particular value
7337                          */
7338                         tu.ipft_vlong = 0;
7339                         if (ta->ipft_sz == sizeof(u_long))
7340                                 tu.ipft_vlong = *ta->ipft_plong;
7341                         else if (ta->ipft_sz == sizeof(u_int))
7342                                 tu.ipft_vint = *ta->ipft_pint;
7343                         else if (ta->ipft_sz == sizeof(u_short))
7344                                 tu.ipft_vshort = *ta->ipft_pshort;
7345                         else if (ta->ipft_sz == sizeof(u_char))
7346                                 tu.ipft_vchar = *ta->ipft_pchar;
7347                         tu.ipft_cookie = ta;
7348                         tu.ipft_sz = ta->ipft_sz;
7349                         tu.ipft_min = ta->ipft_min;
7350                         tu.ipft_max = ta->ipft_max;
7351                         tu.ipft_flags = ta->ipft_flags;
7352                         error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7353
7354                 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
7355                         /*
7356                          * Set an internal parameter.  The hard part here is
7357                          * getting the new value safely and correctly out of
7358                          * the kernel (given we only know its size, not type.)
7359                          */
7360                         u_long in;
7361
7362                         if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
7363                             (softc->ipf_running > 0)) {
7364                                 IPFERROR(78);
7365                                 error = EBUSY;
7366                                 break;
7367                         }
7368
7369                         in = tu.ipft_vlong;
7370                         if (in < ta->ipft_min || in > ta->ipft_max) {
7371                                 IPFERROR(79);
7372                                 error = EINVAL;
7373                                 break;
7374                         }
7375
7376                         if (ta->ipft_func != NULL) {
7377                                 SPL_INT(s);
7378
7379                                 SPL_NET(s);
7380                                 error = (*ta->ipft_func)(softc, ta,
7381                                                          &tu.ipft_un);
7382                                 SPL_X(s);
7383
7384                         } else if (ta->ipft_sz == sizeof(u_long)) {
7385                                 tu.ipft_vlong = *ta->ipft_plong;
7386                                 *ta->ipft_plong = in;
7387
7388                         } else if (ta->ipft_sz == sizeof(u_int)) {
7389                                 tu.ipft_vint = *ta->ipft_pint;
7390                                 *ta->ipft_pint = (u_int)(in & 0xffffffff);
7391
7392                         } else if (ta->ipft_sz == sizeof(u_short)) {
7393                                 tu.ipft_vshort = *ta->ipft_pshort;
7394                                 *ta->ipft_pshort = (u_short)(in & 0xffff);
7395
7396                         } else if (ta->ipft_sz == sizeof(u_char)) {
7397                                 tu.ipft_vchar = *ta->ipft_pchar;
7398                                 *ta->ipft_pchar = (u_char)(in & 0xff);
7399                         }
7400                         error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
7401                 }
7402                 break;
7403
7404         default :
7405                 IPFERROR(80);
7406                 error = EINVAL;
7407                 break;
7408         }
7409
7410         return error;
7411 }
7412
7413
7414 /* ------------------------------------------------------------------------ */
7415 /* Function:    ipf_zerostats                                               */
7416 /* Returns:     int - 0 = success, else failure                             */
7417 /* Parameters:  data(O) - pointer to pointer for copying data back to       */
7418 /*                                                                          */
7419 /* Copies the current statistics out to userspace and then zero's the       */
7420 /* current ones in the kernel. The lock is only held across the bzero() as  */
7421 /* the copyout may result in paging (ie network activity.)                  */
7422 /* ------------------------------------------------------------------------ */
7423 int
7424 ipf_zerostats(softc, data)
7425         ipf_main_softc_t *softc;
7426         caddr_t data;
7427 {
7428         friostat_t fio;
7429         ipfobj_t obj;
7430         int error;
7431
7432         error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT);
7433         if (error != 0)
7434                 return error;
7435         ipf_getstat(softc, &fio, obj.ipfo_rev);
7436         error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT);
7437         if (error != 0)
7438                 return error;
7439
7440         WRITE_ENTER(&softc->ipf_mutex);
7441         bzero(&softc->ipf_stats, sizeof(softc->ipf_stats));
7442         RWLOCK_EXIT(&softc->ipf_mutex);
7443
7444         return 0;
7445 }
7446
7447
7448 /* ------------------------------------------------------------------------ */
7449 /* Function:    ipf_resolvedest                                             */
7450 /* Returns:     Nil                                                         */
7451 /* Parameters:  softc(I) - pointer to soft context main structure           */
7452 /*              base(I)  - where strings are stored                         */
7453 /*              fdp(IO)  - pointer to destination information to resolve    */
7454 /*              v(I)     - IP protocol version to match                     */
7455 /*                                                                          */
7456 /* Looks up an interface name in the frdest structure pointed to by fdp and */
7457 /* if a matching name can be found for the particular IP protocol version   */
7458 /* then store the interface pointer in the frdest struct.  If no match is   */
7459 /* found, then set the interface pointer to be -1 as NULL is considered to  */
7460 /* indicate there is no information at all in the structure.                */
7461 /* ------------------------------------------------------------------------ */
7462 int
7463 ipf_resolvedest(softc, base, fdp, v)
7464         ipf_main_softc_t *softc;
7465         char *base;
7466         frdest_t *fdp;
7467         int v;
7468 {
7469         int errval = 0;
7470         void *ifp;
7471
7472         ifp = NULL;
7473
7474         if (fdp->fd_name != -1) {
7475                 if (fdp->fd_type == FRD_DSTLIST) {
7476                         ifp = ipf_lookup_res_name(softc, IPL_LOGIPF,
7477                                                   IPLT_DSTLIST,
7478                                                   base + fdp->fd_name,
7479                                                   NULL);
7480                         if (ifp == NULL) {
7481                                 IPFERROR(144);
7482                                 errval = ESRCH;
7483                         }
7484                 } else {
7485                         ifp = GETIFP(base + fdp->fd_name, v);
7486                         if (ifp == NULL)
7487                                 ifp = (void *)-1;
7488                 }
7489         }
7490         fdp->fd_ptr = ifp;
7491
7492         if ((ifp != NULL) && (ifp != (void *)-1)) {
7493                 fdp->fd_local = ipf_deliverlocal(softc, v, ifp, &fdp->fd_ip6);
7494         }
7495
7496         return errval;
7497 }
7498
7499
7500 /* ------------------------------------------------------------------------ */
7501 /* Function:    ipf_resolvenic                                              */
7502 /* Returns:     void* - NULL = wildcard name, -1 = failed to find NIC, else */
7503 /*                      pointer to interface structure for NIC              */
7504 /* Parameters:  softc(I)- pointer to soft context main structure            */
7505 /*              name(I) - complete interface name                           */
7506 /*              v(I)    - IP protocol version                               */
7507 /*                                                                          */
7508 /* Look for a network interface structure that firstly has a matching name  */
7509 /* to that passed in and that is also being used for that IP protocol       */
7510 /* version (necessary on some platforms where there are separate listings   */
7511 /* for both IPv4 and IPv6 on the same physical NIC.                         */
7512 /* ------------------------------------------------------------------------ */
7513 void *
7514 ipf_resolvenic(softc, name, v)
7515         ipf_main_softc_t *softc;
7516         char *name;
7517         int v;
7518 {
7519         void *nic;
7520
7521         softc = softc;  /* gcc -Wextra */
7522         if (name[0] == '\0')
7523                 return NULL;
7524
7525         if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) {
7526                 return NULL;
7527         }
7528
7529         nic = GETIFP(name, v);
7530         if (nic == NULL)
7531                 nic = (void *)-1;
7532         return nic;
7533 }
7534
7535
7536 /* ------------------------------------------------------------------------ */
7537 /* Function:    ipf_token_expire                                            */
7538 /* Returns:     None.                                                       */
7539 /* Parameters:  softc(I) - pointer to soft context main structure           */
7540 /*                                                                          */
7541 /* This function is run every ipf tick to see if there are any tokens that  */
7542 /* have been held for too long and need to be freed up.                     */
7543 /* ------------------------------------------------------------------------ */
7544 void
7545 ipf_token_expire(softc)
7546         ipf_main_softc_t *softc;
7547 {
7548         ipftoken_t *it;
7549
7550         WRITE_ENTER(&softc->ipf_tokens);
7551         while ((it = softc->ipf_token_head) != NULL) {
7552                 if (it->ipt_die > softc->ipf_ticks)
7553                         break;
7554
7555                 ipf_token_deref(softc, it);
7556         }
7557         RWLOCK_EXIT(&softc->ipf_tokens);
7558 }
7559
7560
7561 /* ------------------------------------------------------------------------ */
7562 /* Function:    ipf_token_flush                                             */
7563 /* Returns:     None.                                                       */
7564 /* Parameters:  softc(I) - pointer to soft context main structure           */
7565 /*                                                                          */
7566 /* Loop through all of the existing tokens and call deref to see if they    */
7567 /* can be freed. Normally a function like this might just loop on           */
7568 /* ipf_token_head but there is a chance that a token might have a ref count */
7569 /* of greater than one and in that case the the reference would drop twice  */
7570 /* by code that is only entitled to drop it once.                           */
7571 /* ------------------------------------------------------------------------ */
7572 static void
7573 ipf_token_flush(softc)
7574         ipf_main_softc_t *softc;
7575 {
7576         ipftoken_t *it, *next;
7577
7578         WRITE_ENTER(&softc->ipf_tokens);
7579         for (it = softc->ipf_token_head; it != NULL; it = next) {
7580                 next = it->ipt_next;
7581                 (void) ipf_token_deref(softc, it);
7582         }
7583         RWLOCK_EXIT(&softc->ipf_tokens);
7584 }
7585
7586
7587 /* ------------------------------------------------------------------------ */
7588 /* Function:    ipf_token_del                                               */
7589 /* Returns:     int     - 0 = success, else error                           */
7590 /* Parameters:  softc(I)- pointer to soft context main structure            */
7591 /*              type(I) - the token type to match                           */
7592 /*              uid(I)  - uid owning the token                              */
7593 /*              ptr(I)  - context pointer for the token                     */
7594 /*                                                                          */
7595 /* This function looks for a a token in the current list that matches up    */
7596 /* the fields (type, uid, ptr).  If none is found, ESRCH is returned, else  */
7597 /* call ipf_token_dewref() to remove it from the list. In the event that    */
7598 /* the token has a reference held elsewhere, setting ipt_complete to 2      */
7599 /* enables debugging to distinguish between the two paths that ultimately   */
7600 /* lead to a token to be deleted.                                           */
7601 /* ------------------------------------------------------------------------ */
7602 int
7603 ipf_token_del(softc, type, uid, ptr)
7604         ipf_main_softc_t *softc;
7605         int type, uid;
7606         void *ptr;
7607 {
7608         ipftoken_t *it;
7609         int error;
7610
7611         IPFERROR(82);
7612         error = ESRCH;
7613
7614         WRITE_ENTER(&softc->ipf_tokens);
7615         for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
7616                 if (ptr == it->ipt_ctx && type == it->ipt_type &&
7617                     uid == it->ipt_uid) {
7618                         it->ipt_complete = 2;
7619                         ipf_token_deref(softc, it);
7620                         error = 0;
7621                         break;
7622                 }
7623         }
7624         RWLOCK_EXIT(&softc->ipf_tokens);
7625
7626         return error;
7627 }
7628
7629
7630 /* ------------------------------------------------------------------------ */
7631 /* Function:    ipf_token_mark_complete                                     */
7632 /* Returns:     None.                                                       */
7633 /* Parameters:  token(I) - pointer to token structure                       */
7634 /*                                                                          */
7635 /* Mark a token as being ineligable for being found with ipf_token_find.    */
7636 /* ------------------------------------------------------------------------ */
7637 void
7638 ipf_token_mark_complete(token)
7639         ipftoken_t *token;
7640 {
7641         if (token->ipt_complete == 0)
7642                 token->ipt_complete = 1;
7643 }
7644
7645
7646 /* ------------------------------------------------------------------------ */
7647 /* Function:    ipf_token_find                                               */
7648 /* Returns:     ipftoken_t * - NULL if no memory, else pointer to token     */
7649 /* Parameters:  softc(I)- pointer to soft context main structure            */
7650 /*              type(I) - the token type to match                           */
7651 /*              uid(I)  - uid owning the token                              */
7652 /*              ptr(I)  - context pointer for the token                     */
7653 /*                                                                          */
7654 /* This function looks for a live token in the list of current tokens that  */
7655 /* matches the tuple (type, uid, ptr).  If one cannot be found then one is  */
7656 /* allocated.  If one is found then it is moved to the top of the list of   */
7657 /* currently active tokens.                                                 */
7658 /* ------------------------------------------------------------------------ */
7659 ipftoken_t *
7660 ipf_token_find(softc, type, uid, ptr)
7661         ipf_main_softc_t *softc;
7662         int type, uid;
7663         void *ptr;
7664 {
7665         ipftoken_t *it, *new;
7666
7667         KMALLOC(new, ipftoken_t *);
7668         if (new != NULL)
7669                 bzero((char *)new, sizeof(*new));
7670
7671         WRITE_ENTER(&softc->ipf_tokens);
7672         for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
7673                 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
7674                     (uid == it->ipt_uid) && (it->ipt_complete < 2))
7675                         break;
7676         }
7677
7678         if (it == NULL) {
7679                 it = new;
7680                 new = NULL;
7681                 if (it == NULL) {
7682                         RWLOCK_EXIT(&softc->ipf_tokens);
7683                         return NULL;
7684                 }
7685                 it->ipt_ctx = ptr;
7686                 it->ipt_uid = uid;
7687                 it->ipt_type = type;
7688                 it->ipt_ref = 1;
7689         } else {
7690                 if (new != NULL) {
7691                         KFREE(new);
7692                         new = NULL;
7693                 }
7694
7695                 if (it->ipt_complete > 0)
7696                         it = NULL;
7697                 else
7698                         ipf_token_unlink(softc, it);
7699         }
7700
7701         if (it != NULL) {
7702                 it->ipt_pnext = softc->ipf_token_tail;
7703                 *softc->ipf_token_tail = it;
7704                 softc->ipf_token_tail = &it->ipt_next;
7705                 it->ipt_next = NULL;
7706                 it->ipt_ref++;
7707
7708                 it->ipt_die = softc->ipf_ticks + 20;
7709         }
7710
7711         RWLOCK_EXIT(&softc->ipf_tokens);
7712
7713         return it;
7714 }
7715
7716
7717 /* ------------------------------------------------------------------------ */
7718 /* Function:    ipf_token_unlink                                            */
7719 /* Returns:     None.                                                       */
7720 /* Parameters:  softc(I) - pointer to soft context main structure           */
7721 /*              token(I) - pointer to token structure                       */
7722 /* Write Locks: ipf_tokens                                                  */
7723 /*                                                                          */
7724 /* This function unlinks a token structure from the linked list of tokens   */
7725 /* that "own" it.  The head pointer never needs to be explicitly adjusted   */
7726 /* but the tail does due to the linked list implementation.                 */
7727 /* ------------------------------------------------------------------------ */
7728 static void
7729 ipf_token_unlink(softc, token)
7730         ipf_main_softc_t *softc;
7731         ipftoken_t *token;
7732 {
7733
7734         if (softc->ipf_token_tail == &token->ipt_next)
7735                 softc->ipf_token_tail = token->ipt_pnext;
7736
7737         *token->ipt_pnext = token->ipt_next;
7738         if (token->ipt_next != NULL)
7739                 token->ipt_next->ipt_pnext = token->ipt_pnext;
7740         token->ipt_next = NULL;
7741         token->ipt_pnext = NULL;
7742 }
7743
7744
7745 /* ------------------------------------------------------------------------ */
7746 /* Function:    ipf_token_deref                                             */
7747 /* Returns:     int      - 0 == token freed, else reference count           */
7748 /* Parameters:  softc(I) - pointer to soft context main structure           */
7749 /*              token(I) - pointer to token structure                       */
7750 /* Write Locks: ipf_tokens                                                  */
7751 /*                                                                          */
7752 /* Drop the reference count on the token structure and if it drops to zero, */
7753 /* call the dereference function for the token type because it is then      */
7754 /* possible to free the token data structure.                               */
7755 /* ------------------------------------------------------------------------ */
7756 int
7757 ipf_token_deref(softc, token)
7758         ipf_main_softc_t *softc;
7759         ipftoken_t *token;
7760 {
7761         void *data, **datap;
7762
7763         ASSERT(token->ipt_ref > 0);
7764         token->ipt_ref--;
7765         if (token->ipt_ref > 0)
7766                 return token->ipt_ref;
7767
7768         data = token->ipt_data;
7769         datap = &data;
7770
7771         if ((data != NULL) && (data != (void *)-1)) {
7772                 switch (token->ipt_type)
7773                 {
7774                 case IPFGENITER_IPF :
7775                         (void) ipf_derefrule(softc, (frentry_t **)datap);
7776                         break;
7777                 case IPFGENITER_IPNAT :
7778                         WRITE_ENTER(&softc->ipf_nat);
7779                         ipf_nat_rule_deref(softc, (ipnat_t **)datap);
7780                         RWLOCK_EXIT(&softc->ipf_nat);
7781                         break;
7782                 case IPFGENITER_NAT :
7783                         ipf_nat_deref(softc, (nat_t **)datap);
7784                         break;
7785                 case IPFGENITER_STATE :
7786                         ipf_state_deref(softc, (ipstate_t **)datap);
7787                         break;
7788                 case IPFGENITER_FRAG :
7789                         ipf_frag_pkt_deref(softc, (ipfr_t **)datap);
7790                         break;
7791                 case IPFGENITER_NATFRAG :
7792                         ipf_frag_nat_deref(softc, (ipfr_t **)datap);
7793                         break;
7794                 case IPFGENITER_HOSTMAP :
7795                         WRITE_ENTER(&softc->ipf_nat);
7796                         ipf_nat_hostmapdel(softc, (hostmap_t **)datap);
7797                         RWLOCK_EXIT(&softc->ipf_nat);
7798                         break;
7799                 default :
7800                         ipf_lookup_iterderef(softc, token->ipt_type, data);
7801                         break;
7802                 }
7803         }
7804
7805         ipf_token_unlink(softc, token);
7806         KFREE(token);
7807         return 0;
7808 }
7809
7810
7811 /* ------------------------------------------------------------------------ */
7812 /* Function:    ipf_nextrule                                                */
7813 /* Returns:     frentry_t * - NULL == no more rules, else pointer to next   */
7814 /* Parameters:  softc(I)    - pointer to soft context main structure        */
7815 /*              fr(I)       - pointer to filter rule                        */
7816 /*              out(I)      - 1 == out rules, 0 == input rules              */
7817 /*                                                                          */
7818 /* Starting with "fr", find the next rule to visit. This includes visiting  */
7819 /* the list of rule groups if either fr is NULL (empty list) or it is the   */
7820 /* last rule in the list. When walking rule lists, it is either input or    */
7821 /* output rules that are returned, never both.                              */
7822 /* ------------------------------------------------------------------------ */
7823 static frentry_t *
7824 ipf_nextrule(softc, active, unit, fr, out)
7825         ipf_main_softc_t *softc;
7826         int active, unit;
7827         frentry_t *fr;
7828         int out;
7829 {
7830         frentry_t *next;
7831         frgroup_t *fg;
7832
7833         if (fr != NULL && fr->fr_group != -1) {
7834                 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group,
7835                                    unit, active, NULL);
7836                 if (fg != NULL)
7837                         fg = fg->fg_next;
7838         } else {
7839                 fg = softc->ipf_groups[unit][active];
7840         }
7841
7842         while (fg != NULL) {
7843                 next = fg->fg_start;
7844                 while (next != NULL) {
7845                         if (out) {
7846                                 if (next->fr_flags & FR_OUTQUE)
7847                                         return next;
7848                         } else if (next->fr_flags & FR_INQUE) {
7849                                 return next;
7850                         }
7851                         next = next->fr_next;
7852                 }
7853                 if (next == NULL)
7854                         fg = fg->fg_next;
7855         }
7856
7857         return NULL;
7858 }
7859
7860 /* ------------------------------------------------------------------------ */
7861 /* Function:    ipf_getnextrule                                             */
7862 /* Returns:     int - 0 = success, else error                               */
7863 /* Parameters:  softc(I)- pointer to soft context main structure            */
7864 /*              t(I)   - pointer to destination information to resolve      */
7865 /*              ptr(I) - pointer to ipfobj_t to copyin from user space      */
7866 /*                                                                          */
7867 /* This function's first job is to bring in the ipfruleiter_t structure via */
7868 /* the ipfobj_t structure to determine what should be the next rule to      */
7869 /* return. Once the ipfruleiter_t has been brought in, it then tries to     */
7870 /* find the 'next rule'.  This may include searching rule group lists or    */
7871 /* just be as simple as looking at the 'next' field in the rule structure.  */
7872 /* When we have found the rule to return, increase its reference count and  */
7873 /* if we used an existing rule to get here, decrease its reference count.   */
7874 /* ------------------------------------------------------------------------ */
7875 int
7876 ipf_getnextrule(softc, t, ptr)
7877         ipf_main_softc_t *softc;
7878         ipftoken_t *t;
7879         void *ptr;
7880 {
7881         frentry_t *fr, *next, zero;
7882         ipfruleiter_t it;
7883         int error, out;
7884         frgroup_t *fg;
7885         ipfobj_t obj;
7886         int predict;
7887         char *dst;
7888         int unit;
7889
7890         if (t == NULL || ptr == NULL) {
7891                 IPFERROR(84);
7892                 return EFAULT;
7893         }
7894
7895         error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER);
7896         if (error != 0)
7897                 return error;
7898
7899         if ((it.iri_inout < 0) || (it.iri_inout > 3)) {
7900                 IPFERROR(85);
7901                 return EINVAL;
7902         }
7903         if ((it.iri_active != 0) && (it.iri_active != 1)) {
7904                 IPFERROR(86);
7905                 return EINVAL;
7906         }
7907         if (it.iri_nrules == 0) {
7908                 IPFERROR(87);
7909                 return ENOSPC;
7910         }
7911         if (it.iri_rule == NULL) {
7912                 IPFERROR(88);
7913                 return EFAULT;
7914         }
7915
7916         fg = NULL;
7917         fr = t->ipt_data;
7918         if ((it.iri_inout & F_OUT) != 0)
7919                 out = 1;
7920         else
7921                 out = 0;
7922         if ((it.iri_inout & F_ACIN) != 0)
7923                 unit = IPL_LOGCOUNT;
7924         else
7925                 unit = IPL_LOGIPF;
7926
7927         READ_ENTER(&softc->ipf_mutex);
7928         if (fr == NULL) {
7929                 if (*it.iri_group == '\0') {
7930                         if (unit == IPL_LOGCOUNT) {
7931                                 next = softc->ipf_acct[out][it.iri_active];
7932                         } else {
7933                                 next = softc->ipf_rules[out][it.iri_active];
7934                         }
7935                         if (next == NULL)
7936                                 next = ipf_nextrule(softc, it.iri_active,
7937                                                     unit, NULL, out);
7938                 } else {
7939                         fg = ipf_findgroup(softc, it.iri_group, unit,
7940                                            it.iri_active, NULL);
7941                         if (fg != NULL)
7942                                 next = fg->fg_start;
7943                         else
7944                                 next = NULL;
7945                 }
7946         } else {
7947                 next = fr->fr_next;
7948                 if (next == NULL)
7949                         next = ipf_nextrule(softc, it.iri_active, unit,
7950                                             fr, out);
7951         }
7952
7953         if (next != NULL && next->fr_next != NULL)
7954                 predict = 1;
7955         else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL)
7956                 predict = 1;
7957         else
7958                 predict = 0;
7959
7960         if (fr != NULL)
7961                 (void) ipf_derefrule(softc, &fr);
7962
7963         obj.ipfo_type = IPFOBJ_FRENTRY;
7964         dst = (char *)it.iri_rule;
7965
7966         if (next != NULL) {
7967                 obj.ipfo_size = next->fr_size;
7968                 MUTEX_ENTER(&next->fr_lock);
7969                 next->fr_ref++;
7970                 MUTEX_EXIT(&next->fr_lock);
7971                 t->ipt_data = next;
7972         } else {
7973                 obj.ipfo_size = sizeof(frentry_t);
7974                 bzero(&zero, sizeof(zero));
7975                 next = &zero;
7976                 t->ipt_data = NULL;
7977         }
7978         it.iri_rule = predict ? next : NULL;
7979         if (predict == 0)
7980                 ipf_token_mark_complete(t);
7981
7982         RWLOCK_EXIT(&softc->ipf_mutex);
7983
7984         obj.ipfo_ptr = dst;
7985         error = ipf_outobjk(softc, &obj, next);
7986         if (error == 0 && t->ipt_data != NULL) {
7987                 dst += obj.ipfo_size;
7988                 if (next->fr_data != NULL) {
7989                         ipfobj_t dobj;
7990
7991                         if (next->fr_type == FR_T_IPFEXPR)
7992                                 dobj.ipfo_type = IPFOBJ_IPFEXPR;
7993                         else
7994                                 dobj.ipfo_type = IPFOBJ_FRIPF;
7995                         dobj.ipfo_size = next->fr_dsize;
7996                         dobj.ipfo_rev = obj.ipfo_rev;
7997                         dobj.ipfo_ptr = dst;
7998                         error = ipf_outobjk(softc, &dobj, next->fr_data);
7999                 }
8000         }
8001
8002         if ((fr != NULL) && (next == &zero))
8003                 (void) ipf_derefrule(softc, &fr);
8004
8005         return error;
8006 }
8007
8008
8009 /* ------------------------------------------------------------------------ */
8010 /* Function:    ipf_frruleiter                                              */
8011 /* Returns:     int - 0 = success, else error                               */
8012 /* Parameters:  softc(I)- pointer to soft context main structure            */
8013 /*              data(I) - the token type to match                           */
8014 /*              uid(I)  - uid owning the token                              */
8015 /*              ptr(I)  - context pointer for the token                     */
8016 /*                                                                          */
8017 /* This function serves as a stepping stone between ipf_ipf_ioctl and       */
8018 /* ipf_getnextrule.  It's role is to find the right token in the kernel for */
8019 /* the process doing the ioctl and use that to ask for the next rule.       */
8020 /* ------------------------------------------------------------------------ */
8021 static int
8022 ipf_frruleiter(softc, data, uid, ctx)
8023         ipf_main_softc_t *softc;
8024         void *data, *ctx;
8025         int uid;
8026 {
8027         ipftoken_t *token;
8028         ipfruleiter_t it;
8029         ipfobj_t obj;
8030         int error;
8031
8032         token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx);
8033         if (token != NULL) {
8034                 error = ipf_getnextrule(softc, token, data);
8035                 WRITE_ENTER(&softc->ipf_tokens);
8036                 ipf_token_deref(softc, token);
8037                 RWLOCK_EXIT(&softc->ipf_tokens);
8038         } else {
8039                 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER);
8040                 if (error != 0)
8041                         return error;
8042                 it.iri_rule = NULL;
8043                 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER);
8044         }
8045
8046         return error;
8047 }
8048
8049
8050 /* ------------------------------------------------------------------------ */
8051 /* Function:    ipf_geniter                                                 */
8052 /* Returns:     int - 0 = success, else error                               */
8053 /* Parameters:  softc(I) - pointer to soft context main structure           */
8054 /*              token(I) - pointer to ipftoken_t structure                  */
8055 /*              itp(I)   - pointer to iterator data                         */
8056 /*                                                                          */
8057 /* Decide which iterator function to call using information passed through  */
8058 /* the ipfgeniter_t structure at itp.                                       */
8059 /* ------------------------------------------------------------------------ */
8060 static int
8061 ipf_geniter(softc, token, itp)
8062         ipf_main_softc_t *softc;
8063         ipftoken_t *token;
8064         ipfgeniter_t *itp;
8065 {
8066         int error;
8067
8068         switch (itp->igi_type)
8069         {
8070         case IPFGENITER_FRAG :
8071                 error = ipf_frag_pkt_next(softc, token, itp);
8072                 break;
8073         default :
8074                 IPFERROR(92);
8075                 error = EINVAL;
8076                 break;
8077         }
8078
8079         return error;
8080 }
8081
8082
8083 /* ------------------------------------------------------------------------ */
8084 /* Function:    ipf_genericiter                                             */
8085 /* Returns:     int - 0 = success, else error                               */
8086 /* Parameters:  softc(I)- pointer to soft context main structure            */
8087 /*              data(I) - the token type to match                           */
8088 /*              uid(I)  - uid owning the token                              */
8089 /*              ptr(I)  - context pointer for the token                     */
8090 /*                                                                          */
8091 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role   */
8092 /* ------------------------------------------------------------------------ */
8093 int
8094 ipf_genericiter(softc, data, uid, ctx)
8095         ipf_main_softc_t *softc;
8096         void *data, *ctx;
8097         int uid;
8098 {
8099         ipftoken_t *token;
8100         ipfgeniter_t iter;
8101         int error;
8102
8103         error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER);
8104         if (error != 0)
8105                 return error;
8106
8107         token = ipf_token_find(softc, iter.igi_type, uid, ctx);
8108         if (token != NULL) {
8109                 token->ipt_subtype = iter.igi_type;
8110                 error = ipf_geniter(softc, token, &iter);
8111                 WRITE_ENTER(&softc->ipf_tokens);
8112                 ipf_token_deref(softc, token);
8113                 RWLOCK_EXIT(&softc->ipf_tokens);
8114         } else {
8115                 IPFERROR(93);
8116                 error = 0;
8117         }
8118
8119         return error;
8120 }
8121
8122
8123 /* ------------------------------------------------------------------------ */
8124 /* Function:    ipf_ipf_ioctl                                               */
8125 /* Returns:     int - 0 = success, else error                               */
8126 /* Parameters:  softc(I)- pointer to soft context main structure           */
8127 /*              data(I) - the token type to match                           */
8128 /*              cmd(I)  - the ioctl command number                          */
8129 /*              mode(I) - mode flags for the ioctl                          */
8130 /*              uid(I)  - uid owning the token                              */
8131 /*              ptr(I)  - context pointer for the token                     */
8132 /*                                                                          */
8133 /* This function handles all of the ioctl command that are actually isssued */
8134 /* to the /dev/ipl device.                                                  */
8135 /* ------------------------------------------------------------------------ */
8136 int
8137 ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx)
8138         ipf_main_softc_t *softc;
8139         caddr_t data;
8140         ioctlcmd_t cmd;
8141         int mode, uid;
8142         void *ctx;
8143 {
8144         friostat_t fio;
8145         int error, tmp;
8146         ipfobj_t obj;
8147         SPL_INT(s);
8148
8149         switch (cmd)
8150         {
8151         case SIOCFRENB :
8152                 if (!(mode & FWRITE)) {
8153                         IPFERROR(94);
8154                         error = EPERM;
8155                 } else {
8156                         error = BCOPYIN(data, &tmp, sizeof(tmp));
8157                         if (error != 0) {
8158                                 IPFERROR(95);
8159                                 error = EFAULT;
8160                                 break;
8161                         }
8162
8163                         WRITE_ENTER(&softc->ipf_global);
8164                         if (tmp) {
8165                                 if (softc->ipf_running > 0)
8166                                         error = 0;
8167                                 else
8168                                         error = ipfattach(softc);
8169                                 if (error == 0)
8170                                         softc->ipf_running = 1;
8171                                 else
8172                                         (void) ipfdetach(softc);
8173                         } else {
8174                                 if (softc->ipf_running == 1)
8175                                         error = ipfdetach(softc);
8176                                 else
8177                                         error = 0;
8178                                 if (error == 0)
8179                                         softc->ipf_running = -1;
8180                         }
8181                         RWLOCK_EXIT(&softc->ipf_global);
8182                 }
8183                 break;
8184
8185         case SIOCIPFSET :
8186                 if (!(mode & FWRITE)) {
8187                         IPFERROR(96);
8188                         error = EPERM;
8189                         break;
8190                 }
8191                 /* FALLTHRU */
8192         case SIOCIPFGETNEXT :
8193         case SIOCIPFGET :
8194                 error = ipf_ipftune(softc, cmd, (void *)data);
8195                 break;
8196
8197         case SIOCSETFF :
8198                 if (!(mode & FWRITE)) {
8199                         IPFERROR(97);
8200                         error = EPERM;
8201                 } else {
8202                         error = BCOPYIN(data, &softc->ipf_flags,
8203                                         sizeof(softc->ipf_flags));
8204                         if (error != 0) {
8205                                 IPFERROR(98);
8206                                 error = EFAULT;
8207                         }
8208                 }
8209                 break;
8210
8211         case SIOCGETFF :
8212                 error = BCOPYOUT(&softc->ipf_flags, data,
8213                                  sizeof(softc->ipf_flags));
8214                 if (error != 0) {
8215                         IPFERROR(99);
8216                         error = EFAULT;
8217                 }
8218                 break;
8219
8220         case SIOCFUNCL :
8221                 error = ipf_resolvefunc(softc, (void *)data);
8222                 break;
8223
8224         case SIOCINAFR :
8225         case SIOCRMAFR :
8226         case SIOCADAFR :
8227         case SIOCZRLST :
8228                 if (!(mode & FWRITE)) {
8229                         IPFERROR(100);
8230                         error = EPERM;
8231                 } else {
8232                         error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
8233                                           softc->ipf_active, 1);
8234                 }
8235                 break;
8236
8237         case SIOCINIFR :
8238         case SIOCRMIFR :
8239         case SIOCADIFR :
8240                 if (!(mode & FWRITE)) {
8241                         IPFERROR(101);
8242                         error = EPERM;
8243                 } else {
8244                         error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
8245                                           1 - softc->ipf_active, 1);
8246                 }
8247                 break;
8248
8249         case SIOCSWAPA :
8250                 if (!(mode & FWRITE)) {
8251                         IPFERROR(102);
8252                         error = EPERM;
8253                 } else {
8254                         WRITE_ENTER(&softc->ipf_mutex);
8255                         error = BCOPYOUT(&softc->ipf_active, data,
8256                                          sizeof(softc->ipf_active));
8257                         if (error != 0) {
8258                                 IPFERROR(103);
8259                                 error = EFAULT;
8260                         } else {
8261                                 softc->ipf_active = 1 - softc->ipf_active;
8262                         }
8263                         RWLOCK_EXIT(&softc->ipf_mutex);
8264                 }
8265                 break;
8266
8267         case SIOCGETFS :
8268                 error = ipf_inobj(softc, (void *)data, &obj, &fio,
8269                                   IPFOBJ_IPFSTAT);
8270                 if (error != 0)
8271                         break;
8272                 ipf_getstat(softc, &fio, obj.ipfo_rev);
8273                 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT);
8274                 break;
8275
8276         case SIOCFRZST :
8277                 if (!(mode & FWRITE)) {
8278                         IPFERROR(104);
8279                         error = EPERM;
8280                 } else
8281                         error = ipf_zerostats(softc, (caddr_t)data);
8282                 break;
8283
8284         case SIOCIPFFL :
8285                 if (!(mode & FWRITE)) {
8286                         IPFERROR(105);
8287                         error = EPERM;
8288                 } else {
8289                         error = BCOPYIN(data, &tmp, sizeof(tmp));
8290                         if (!error) {
8291                                 tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
8292                                 error = BCOPYOUT(&tmp, data, sizeof(tmp));
8293                                 if (error != 0) {
8294                                         IPFERROR(106);
8295                                         error = EFAULT;
8296                                 }
8297                         } else {
8298                                 IPFERROR(107);
8299                                 error = EFAULT;
8300                         }
8301                 }
8302                 break;
8303
8304 #ifdef USE_INET6
8305         case SIOCIPFL6 :
8306                 if (!(mode & FWRITE)) {
8307                         IPFERROR(108);
8308                         error = EPERM;
8309                 } else {
8310                         error = BCOPYIN(data, &tmp, sizeof(tmp));
8311                         if (!error) {
8312                                 tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
8313                                 error = BCOPYOUT(&tmp, data, sizeof(tmp));
8314                                 if (error != 0) {
8315                                         IPFERROR(109);
8316                                         error = EFAULT;
8317                                 }
8318                         } else {
8319                                 IPFERROR(110);
8320                                 error = EFAULT;
8321                         }
8322                 }
8323                 break;
8324 #endif
8325
8326         case SIOCSTLCK :
8327                 if (!(mode & FWRITE)) {
8328                         IPFERROR(122);
8329                         error = EPERM;
8330                 } else {
8331                         error = BCOPYIN(data, &tmp, sizeof(tmp));
8332                         if (error == 0) {
8333                                 ipf_state_setlock(softc->ipf_state_soft, tmp);
8334                                 ipf_nat_setlock(softc->ipf_nat_soft, tmp);
8335                                 ipf_frag_setlock(softc->ipf_frag_soft, tmp);
8336                                 ipf_auth_setlock(softc->ipf_auth_soft, tmp);
8337                         } else {
8338                                 IPFERROR(111);
8339                                 error = EFAULT;
8340                         }
8341                 }
8342                 break;
8343
8344 #ifdef  IPFILTER_LOG
8345         case SIOCIPFFB :
8346                 if (!(mode & FWRITE)) {
8347                         IPFERROR(112);
8348                         error = EPERM;
8349                 } else {
8350                         tmp = ipf_log_clear(softc, IPL_LOGIPF);
8351                         error = BCOPYOUT(&tmp, data, sizeof(tmp));
8352                         if (error) {
8353                                 IPFERROR(113);
8354                                 error = EFAULT;
8355                         }
8356                 }
8357                 break;
8358 #endif /* IPFILTER_LOG */
8359
8360         case SIOCFRSYN :
8361                 if (!(mode & FWRITE)) {
8362                         IPFERROR(114);
8363                         error = EPERM;
8364                 } else {
8365                         WRITE_ENTER(&softc->ipf_global);
8366 #if (defined(MENTAT) && defined(_KERNEL)) && !defined(INSTANCES)
8367                         error = ipfsync();
8368 #else
8369                         ipf_sync(softc, NULL);
8370                         error = 0;
8371 #endif
8372                         RWLOCK_EXIT(&softc->ipf_global);
8373
8374                 }
8375                 break;
8376
8377         case SIOCGFRST :
8378                 error = ipf_outobj(softc, (void *)data,
8379                                    ipf_frag_stats(softc->ipf_frag_soft),
8380                                    IPFOBJ_FRAGSTAT);
8381                 break;
8382
8383 #ifdef  IPFILTER_LOG
8384         case FIONREAD :
8385                 tmp = ipf_log_bytesused(softc, IPL_LOGIPF);
8386                 error = BCOPYOUT(&tmp, data, sizeof(tmp));
8387                 break;
8388 #endif
8389
8390         case SIOCIPFITER :
8391                 SPL_SCHED(s);
8392                 error = ipf_frruleiter(softc, data, uid, ctx);
8393                 SPL_X(s);
8394                 break;
8395
8396         case SIOCGENITER :
8397                 SPL_SCHED(s);
8398                 error = ipf_genericiter(softc, data, uid, ctx);
8399                 SPL_X(s);
8400                 break;
8401
8402         case SIOCIPFDELTOK :
8403                 error = BCOPYIN(data, &tmp, sizeof(tmp));
8404                 if (error == 0) {
8405                         SPL_SCHED(s);
8406                         error = ipf_token_del(softc, tmp, uid, ctx);
8407                         SPL_X(s);
8408                 }
8409                 break;
8410
8411         default :
8412                 IPFERROR(115);
8413                 error = EINVAL;
8414                 break;
8415         }
8416
8417         return error;
8418 }
8419
8420
8421 /* ------------------------------------------------------------------------ */
8422 /* Function:    ipf_decaps                                                  */
8423 /* Returns:     int        - -1 == decapsulation failed, else bit mask of   */
8424 /*                           flags indicating packet filtering decision.    */
8425 /* Parameters:  fin(I)     - pointer to packet information                  */
8426 /*              pass(I)    - IP protocol version to match                   */
8427 /*              l5proto(I) - layer 5 protocol to decode UDP data as.        */
8428 /*                                                                          */
8429 /* This function is called for packets that are wrapt up in other packets,  */
8430 /* for example, an IP packet that is the entire data segment for another IP */
8431 /* packet.  If the basic constraints for this are satisfied, change the     */
8432 /* buffer to point to the start of the inner packet and start processing    */
8433 /* rules belonging to the head group this rule specifies.                   */
8434 /* ------------------------------------------------------------------------ */
8435 u_32_t
8436 ipf_decaps(fin, pass, l5proto)
8437         fr_info_t *fin;
8438         u_32_t pass;
8439         int l5proto;
8440 {
8441         fr_info_t fin2, *fino = NULL;
8442         int elen, hlen, nh;
8443         grehdr_t gre;
8444         ip_t *ip;
8445         mb_t *m;
8446
8447         if ((fin->fin_flx & FI_COALESCE) == 0)
8448                 if (ipf_coalesce(fin) == -1)
8449                         goto cantdecaps;
8450
8451         m = fin->fin_m;
8452         hlen = fin->fin_hlen;
8453
8454         switch (fin->fin_p)
8455         {
8456         case IPPROTO_UDP :
8457                 /*
8458                  * In this case, the specific protocol being decapsulated
8459                  * inside UDP frames comes from the rule.
8460                  */
8461                 nh = fin->fin_fr->fr_icode;
8462                 break;
8463
8464         case IPPROTO_GRE :      /* 47 */
8465                 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre));
8466                 hlen += sizeof(grehdr_t);
8467                 if (gre.gr_R|gre.gr_s)
8468                         goto cantdecaps;
8469                 if (gre.gr_C)
8470                         hlen += 4;
8471                 if (gre.gr_K)
8472                         hlen += 4;
8473                 if (gre.gr_S)
8474                         hlen += 4;
8475
8476                 nh = IPPROTO_IP;
8477
8478                 /*
8479                  * If the routing options flag is set, validate that it is
8480                  * there and bounce over it.
8481                  */
8482 #if 0
8483                 /* This is really heavy weight and lots of room for error, */
8484                 /* so for now, put it off and get the simple stuff right.  */
8485                 if (gre.gr_R) {
8486                         u_char off, len, *s;
8487                         u_short af;
8488                         int end;
8489
8490                         end = 0;
8491                         s = fin->fin_dp;
8492                         s += hlen;
8493                         aplen = fin->fin_plen - hlen;
8494                         while (aplen > 3) {
8495                                 af = (s[0] << 8) | s[1];
8496                                 off = s[2];
8497                                 len = s[3];
8498                                 aplen -= 4;
8499                                 s += 4;
8500                                 if (af == 0 && len == 0) {
8501                                         end = 1;
8502                                         break;
8503                                 }
8504                                 if (aplen < len)
8505                                         break;
8506                                 s += len;
8507                                 aplen -= len;
8508                         }
8509                         if (end != 1)
8510                                 goto cantdecaps;
8511                         hlen = s - (u_char *)fin->fin_dp;
8512                 }
8513 #endif
8514                 break;
8515
8516 #ifdef IPPROTO_IPIP
8517         case IPPROTO_IPIP :     /* 4 */
8518 #endif
8519                 nh = IPPROTO_IP;
8520                 break;
8521
8522         default :       /* Includes ESP, AH is special for IPv4 */
8523                 goto cantdecaps;
8524         }
8525
8526         switch (nh)
8527         {
8528         case IPPROTO_IP :
8529         case IPPROTO_IPV6 :
8530                 break;
8531         default :
8532                 goto cantdecaps;
8533         }
8534
8535         bcopy((char *)fin, (char *)&fin2, sizeof(fin2));
8536         fino = fin;
8537         fin = &fin2;
8538         elen = hlen;
8539 #if defined(MENTAT) && defined(_KERNEL)
8540         m->b_rptr += elen;
8541 #else
8542         m->m_data += elen;
8543         m->m_len -= elen;
8544 #endif
8545         fin->fin_plen -= elen;
8546
8547         ip = (ip_t *)((char *)fin->fin_ip + elen);
8548
8549         /*
8550          * Make sure we have at least enough data for the network layer
8551          * header.
8552          */
8553         if (IP_V(ip) == 4)
8554                 hlen = IP_HL(ip) << 2;
8555 #ifdef USE_INET6
8556         else if (IP_V(ip) == 6)
8557                 hlen = sizeof(ip6_t);
8558 #endif
8559         else
8560                 goto cantdecaps2;
8561
8562         if (fin->fin_plen < hlen)
8563                 goto cantdecaps2;
8564
8565         fin->fin_dp = (char *)ip + hlen;
8566
8567         if (IP_V(ip) == 4) {
8568                 /*
8569                  * Perform IPv4 header checksum validation.
8570                  */
8571                 if (ipf_cksum((u_short *)ip, hlen))
8572                         goto cantdecaps2;
8573         }
8574
8575         if (ipf_makefrip(hlen, ip, fin) == -1) {
8576 cantdecaps2:
8577                 if (m != NULL) {
8578 #if defined(MENTAT) && defined(_KERNEL)
8579                         m->b_rptr -= elen;
8580 #else
8581                         m->m_data -= elen;
8582                         m->m_len += elen;
8583 #endif
8584                 }
8585 cantdecaps:
8586                 DT1(frb_decapfrip, fr_info_t *, fin);
8587                 pass &= ~FR_CMDMASK;
8588                 pass |= FR_BLOCK|FR_QUICK;
8589                 fin->fin_reason = FRB_DECAPFRIP;
8590                 return -1;
8591         }
8592
8593         pass = ipf_scanlist(fin, pass);
8594
8595         /*
8596          * Copy the packet filter "result" fields out of the fr_info_t struct
8597          * that is local to the decapsulation processing and back into the
8598          * one we were called with.
8599          */
8600         fino->fin_flx = fin->fin_flx;
8601         fino->fin_rev = fin->fin_rev;
8602         fino->fin_icode = fin->fin_icode;
8603         fino->fin_rule = fin->fin_rule;
8604         (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN);
8605         fino->fin_fr = fin->fin_fr;
8606         fino->fin_error = fin->fin_error;
8607         fino->fin_mp = fin->fin_mp;
8608         fino->fin_m = fin->fin_m;
8609         m = fin->fin_m;
8610         if (m != NULL) {
8611 #if defined(MENTAT) && defined(_KERNEL)
8612                 m->b_rptr -= elen;
8613 #else
8614                 m->m_data -= elen;
8615                 m->m_len += elen;
8616 #endif
8617         }
8618         return pass;
8619 }
8620
8621
8622 /* ------------------------------------------------------------------------ */
8623 /* Function:    ipf_matcharray_load                                         */
8624 /* Returns:     int         - 0 = success, else error                       */
8625 /* Parameters:  softc(I)    - pointer to soft context main structure        */
8626 /*              data(I)     - pointer to ioctl data                         */
8627 /*              objp(I)     - ipfobj_t structure to load data into          */
8628 /*              arrayptr(I) - pointer to location to store array pointer    */
8629 /*                                                                          */
8630 /* This function loads in a mathing array through the ipfobj_t struct that  */
8631 /* describes it.  Sanity checking and array size limitations are enforced   */
8632 /* in this function to prevent userspace from trying to load in something   */
8633 /* that is insanely big.  Once the size of the array is known, the memory   */
8634 /* required is malloc'd and returned through changing *arrayptr.  The       */
8635 /* contents of the array are verified before returning.  Only in the event  */
8636 /* of a successful call is the caller required to free up the malloc area.  */
8637 /* ------------------------------------------------------------------------ */
8638 int
8639 ipf_matcharray_load(softc, data, objp, arrayptr)
8640         ipf_main_softc_t *softc;
8641         caddr_t data;
8642         ipfobj_t *objp;
8643         int **arrayptr;
8644 {
8645         int arraysize, *array, error;
8646
8647         *arrayptr = NULL;
8648
8649         error = BCOPYIN(data, objp, sizeof(*objp));
8650         if (error != 0) {
8651                 IPFERROR(116);
8652                 return EFAULT;
8653         }
8654
8655         if (objp->ipfo_type != IPFOBJ_IPFEXPR) {
8656                 IPFERROR(117);
8657                 return EINVAL;
8658         }
8659
8660         if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) ||
8661             (objp->ipfo_size > 1024)) {
8662                 IPFERROR(118);
8663                 return EINVAL;
8664         }
8665
8666         arraysize = objp->ipfo_size * sizeof(*array);
8667         KMALLOCS(array, int *, arraysize);
8668         if (array == NULL) {
8669                 IPFERROR(119);
8670                 return ENOMEM;
8671         }
8672
8673         error = COPYIN(objp->ipfo_ptr, array, arraysize);
8674         if (error != 0) {
8675                 KFREES(array, arraysize);
8676                 IPFERROR(120);
8677                 return EFAULT;
8678         }
8679
8680         if (ipf_matcharray_verify(array, arraysize) != 0) {
8681                 KFREES(array, arraysize);
8682                 IPFERROR(121);
8683                 return EINVAL;
8684         }
8685
8686         *arrayptr = array;
8687         return 0;
8688 }
8689
8690
8691 /* ------------------------------------------------------------------------ */
8692 /* Function:    ipf_matcharray_verify                                       */
8693 /* Returns:     Nil                                                         */
8694 /* Parameters:  array(I)     - pointer to matching array                    */
8695 /*              arraysize(I) - number of elements in the array              */
8696 /*                                                                          */
8697 /* Verify the contents of a matching array by stepping through each element */
8698 /* in it.  The actual commands in the array are not verified for            */
8699 /* correctness, only that all of the sizes are correctly within limits.     */
8700 /* ------------------------------------------------------------------------ */
8701 int
8702 ipf_matcharray_verify(array, arraysize)
8703         int *array, arraysize;
8704 {
8705         int i, nelem, maxidx;
8706         ipfexp_t *e;
8707
8708         nelem = arraysize / sizeof(*array);
8709
8710         /*
8711          * Currently, it makes no sense to have an array less than 6
8712          * elements long - the initial size at the from, a single operation
8713          * (minimum 4 in length) and a trailer, for a total of 6.
8714          */
8715         if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) {
8716                 return -1;
8717         }
8718
8719         /*
8720          * Verify the size of data pointed to by array with how long
8721          * the array claims to be itself.
8722          */
8723         if (array[0] * sizeof(*array) != arraysize) {
8724                 return -1;
8725         }
8726
8727         maxidx = nelem - 1;
8728         /*
8729          * The last opcode in this array should be an IPF_EXP_END.
8730          */
8731         if (array[maxidx] != IPF_EXP_END) {
8732                 return -1;
8733         }
8734
8735         for (i = 1; i < maxidx; ) {
8736                 e = (ipfexp_t *)(array + i);
8737
8738                 /*
8739                  * The length of the bits to check must be at least 1
8740                  * (or else there is nothing to comapre with!) and it
8741                  * cannot exceed the length of the data present.
8742                  */
8743                 if ((e->ipfe_size < 1 ) ||
8744                     (e->ipfe_size + i > maxidx)) {
8745                         return -1;
8746                 }
8747                 i += e->ipfe_size;
8748         }
8749         return 0;
8750 }
8751
8752
8753 /* ------------------------------------------------------------------------ */
8754 /* Function:    ipf_fr_matcharray                                           */
8755 /* Returns:     int      - 0 = match failed, else positive match            */
8756 /* Parameters:  fin(I)   - pointer to packet information                    */
8757 /*              array(I) - pointer to matching array                        */
8758 /*                                                                          */
8759 /* This function is used to apply a matching array against a packet and     */
8760 /* return an indication of whether or not the packet successfully matches   */
8761 /* all of the commands in it.                                               */
8762 /* ------------------------------------------------------------------------ */
8763 static int
8764 ipf_fr_matcharray(fin, array)
8765         fr_info_t *fin;
8766         int *array;
8767 {
8768         int i, n, *x, rv, p;
8769         ipfexp_t *e;
8770
8771         rv = 0;
8772         n = array[0];
8773         x = array + 1;
8774
8775         for (; n > 0; x += 3 + x[3], rv = 0) {
8776                 e = (ipfexp_t *)x;
8777                 if (e->ipfe_cmd == IPF_EXP_END)
8778                         break;
8779                 n -= e->ipfe_size;
8780
8781                 /*
8782                  * The upper 16 bits currently store the protocol value.
8783                  * This is currently used with TCP and UDP port compares and
8784                  * allows "tcp.port = 80" without requiring an explicit
8785                  " "ip.pr = tcp" first.
8786                  */
8787                 p = e->ipfe_cmd >> 16;
8788                 if ((p != 0) && (p != fin->fin_p))
8789                         break;
8790
8791                 switch (e->ipfe_cmd)
8792                 {
8793                 case IPF_EXP_IP_PR :
8794                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8795                                 rv |= (fin->fin_p == e->ipfe_arg0[i]);
8796                         }
8797                         break;
8798
8799                 case IPF_EXP_IP_SRCADDR :
8800                         if (fin->fin_v != 4)
8801                                 break;
8802                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8803                                 rv |= ((fin->fin_saddr &
8804                                         e->ipfe_arg0[i * 2 + 1]) ==
8805                                        e->ipfe_arg0[i * 2]);
8806                         }
8807                         break;
8808
8809                 case IPF_EXP_IP_DSTADDR :
8810                         if (fin->fin_v != 4)
8811                                 break;
8812                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8813                                 rv |= ((fin->fin_daddr &
8814                                         e->ipfe_arg0[i * 2 + 1]) ==
8815                                        e->ipfe_arg0[i * 2]);
8816                         }
8817                         break;
8818
8819                 case IPF_EXP_IP_ADDR :
8820                         if (fin->fin_v != 4)
8821                                 break;
8822                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8823                                 rv |= ((fin->fin_saddr &
8824                                         e->ipfe_arg0[i * 2 + 1]) ==
8825                                        e->ipfe_arg0[i * 2]) ||
8826                                       ((fin->fin_daddr &
8827                                         e->ipfe_arg0[i * 2 + 1]) ==
8828                                        e->ipfe_arg0[i * 2]);
8829                         }
8830                         break;
8831
8832 #ifdef USE_INET6
8833                 case IPF_EXP_IP6_SRCADDR :
8834                         if (fin->fin_v != 6)
8835                                 break;
8836                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8837                                 rv |= IP6_MASKEQ(&fin->fin_src6,
8838                                                  &e->ipfe_arg0[i * 8 + 4],
8839                                                  &e->ipfe_arg0[i * 8]);
8840                         }
8841                         break;
8842
8843                 case IPF_EXP_IP6_DSTADDR :
8844                         if (fin->fin_v != 6)
8845                                 break;
8846                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8847                                 rv |= IP6_MASKEQ(&fin->fin_dst6,
8848                                                  &e->ipfe_arg0[i * 8 + 4],
8849                                                  &e->ipfe_arg0[i * 8]);
8850                         }
8851                         break;
8852
8853                 case IPF_EXP_IP6_ADDR :
8854                         if (fin->fin_v != 6)
8855                                 break;
8856                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8857                                 rv |= IP6_MASKEQ(&fin->fin_src6,
8858                                                  &e->ipfe_arg0[i * 8 + 4],
8859                                                  &e->ipfe_arg0[i * 8]) ||
8860                                       IP6_MASKEQ(&fin->fin_dst6,
8861                                                  &e->ipfe_arg0[i * 8 + 4],
8862                                                  &e->ipfe_arg0[i * 8]);
8863                         }
8864                         break;
8865 #endif
8866
8867                 case IPF_EXP_UDP_PORT :
8868                 case IPF_EXP_TCP_PORT :
8869                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8870                                 rv |= (fin->fin_sport == e->ipfe_arg0[i]) ||
8871                                       (fin->fin_dport == e->ipfe_arg0[i]);
8872                         }
8873                         break;
8874
8875                 case IPF_EXP_UDP_SPORT :
8876                 case IPF_EXP_TCP_SPORT :
8877                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8878                                 rv |= (fin->fin_sport == e->ipfe_arg0[i]);
8879                         }
8880                         break;
8881
8882                 case IPF_EXP_UDP_DPORT :
8883                 case IPF_EXP_TCP_DPORT :
8884                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8885                                 rv |= (fin->fin_dport == e->ipfe_arg0[i]);
8886                         }
8887                         break;
8888
8889                 case IPF_EXP_TCP_FLAGS :
8890                         for (i = 0; !rv && i < e->ipfe_narg; i++) {
8891                                 rv |= ((fin->fin_tcpf &
8892                                         e->ipfe_arg0[i * 2 + 1]) ==
8893                                        e->ipfe_arg0[i * 2]);
8894                         }
8895                         break;
8896                 }
8897                 rv ^= e->ipfe_not;
8898
8899                 if (rv == 0)
8900                         break;
8901         }
8902
8903         return rv;
8904 }
8905
8906
8907 /* ------------------------------------------------------------------------ */
8908 /* Function:    ipf_queueflush                                              */
8909 /* Returns:     int - number of entries flushed (0 = none)                  */
8910 /* Parameters:  softc(I)    - pointer to soft context main structure        */
8911 /*              deletefn(I) - function to call to delete entry              */
8912 /*              ipfqs(I)    - top of the list of ipf internal queues        */
8913 /*              userqs(I)   - top of the list of user defined timeouts      */
8914 /*                                                                          */
8915 /* This fucntion gets called when the state/NAT hash tables fill up and we  */
8916 /* need to try a bit harder to free up some space.  The algorithm used here */
8917 /* split into two parts but both halves have the same goal: to reduce the   */
8918 /* number of connections considered to be "active" to the low watermark.    */
8919 /* There are two steps in doing this:                                       */
8920 /* 1) Remove any TCP connections that are already considered to be "closed" */
8921 /*    but have not yet been removed from the state table.  The two states   */
8922 /*    TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect       */
8923 /*    candidates for this style of removal.  If freeing up entries in       */
8924 /*    CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark,   */
8925 /*    we do not go on to step 2.                                            */
8926 /*                                                                          */
8927 /* 2) Look for the oldest entries on each timeout queue and free them if    */
8928 /*    they are within the given window we are considering.  Where the       */
8929 /*    window starts and the steps taken to increase its size depend upon    */
8930 /*    how long ipf has been running (ipf_ticks.)  Anything modified in the  */
8931 /*    last 30 seconds is not touched.                                       */
8932 /*                                              touched                     */
8933 /*         die     ipf_ticks  30*1.5    1800*1.5   |  43200*1.5             */
8934 /*           |          |        |           |     |     |                  */
8935 /* future <--+----------+--------+-----------+-----+-----+-----------> past */
8936 /*                     now        \_int=30s_/ \_int=1hr_/ \_int=12hr        */
8937 /*                                                                          */
8938 /* Points to note:                                                          */
8939 /* - tqe_die is the time, in the future, when entries die.                  */
8940 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */
8941 /*   ticks.                                                                 */
8942 /* - tqe_touched is when the entry was last used by NAT/state               */
8943 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be    */
8944 /*   ipf_ticks any given timeout queue and vice versa.                      */
8945 /* - both tqe_die and tqe_touched increase over time                        */
8946 /* - timeout queues are sorted with the highest value of tqe_die at the     */
8947 /*   bottom and therefore the smallest values of each are at the top        */
8948 /* - the pointer passed in as ipfqs should point to an array of timeout     */
8949 /*   queues representing each of the TCP states                             */
8950 /*                                                                          */
8951 /* We start by setting up a maximum range to scan for things to move of     */
8952 /* iend (newest) to istart (oldest) in chunks of "interval".  If nothing is */
8953 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */
8954 /* we start again with a new value for "iend" and "istart".  This is        */
8955 /* continued until we either finish the scan of 30 second intervals or the  */
8956 /* low water mark is reached.                                               */
8957 /* ------------------------------------------------------------------------ */
8958 int
8959 ipf_queueflush(softc, deletefn, ipfqs, userqs, activep, size, low)
8960         ipf_main_softc_t *softc;
8961         ipftq_delete_fn_t deletefn;
8962         ipftq_t *ipfqs, *userqs;
8963         u_int *activep;
8964         int size, low;
8965 {
8966         u_long interval, istart, iend;
8967         ipftq_t *ifq, *ifqnext;
8968         ipftqent_t *tqe, *tqn;
8969         int removed = 0;
8970
8971         for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) {
8972                 tqn = tqe->tqe_next;
8973                 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8974                         removed++;
8975         }
8976         if ((*activep * 100 / size) > low) {
8977                 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head;
8978                      ((tqe = tqn) != NULL); ) {
8979                         tqn = tqe->tqe_next;
8980                         if ((*deletefn)(softc, tqe->tqe_parent) == 0)
8981                                 removed++;
8982                 }
8983         }
8984
8985         if ((*activep * 100 / size) <= low) {
8986                 return removed;
8987         }
8988
8989         /*
8990          * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
8991          *       used then the operations are upgraded to floating point
8992          *       and kernels don't like floating point...
8993          */
8994         if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
8995                 istart = IPF_TTLVAL(86400 * 4);
8996                 interval = IPF_TTLVAL(43200);
8997         } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
8998                 istart = IPF_TTLVAL(43200);
8999                 interval = IPF_TTLVAL(1800);
9000         } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) {
9001                 istart = IPF_TTLVAL(1800);
9002                 interval = IPF_TTLVAL(30);
9003         } else {
9004                 return 0;
9005         }
9006         if (istart > softc->ipf_ticks) {
9007                 if (softc->ipf_ticks - interval < interval)
9008                         istart = interval;
9009                 else
9010                         istart = (softc->ipf_ticks / interval) * interval;
9011         }
9012
9013         iend = softc->ipf_ticks - interval;
9014
9015         while ((*activep * 100 / size) > low) {
9016                 u_long try;
9017
9018                 try = softc->ipf_ticks - istart;
9019
9020                 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
9021                         for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
9022                                 if (try < tqe->tqe_touched)
9023                                         break;
9024                                 tqn = tqe->tqe_next;
9025                                 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
9026                                         removed++;
9027                         }
9028                 }
9029
9030                 for (ifq = userqs; ifq != NULL; ifq = ifqnext) {
9031                         ifqnext = ifq->ifq_next;
9032
9033                         for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
9034                                 if (try < tqe->tqe_touched)
9035                                         break;
9036                                 tqn = tqe->tqe_next;
9037                                 if ((*deletefn)(softc, tqe->tqe_parent) == 0)
9038                                         removed++;
9039                         }
9040                 }
9041
9042                 if (try >= iend) {
9043                         if (interval == IPF_TTLVAL(43200)) {
9044                                 interval = IPF_TTLVAL(1800);
9045                         } else if (interval == IPF_TTLVAL(1800)) {
9046                                 interval = IPF_TTLVAL(30);
9047                         } else {
9048                                 break;
9049                         }
9050                         if (interval >= softc->ipf_ticks)
9051                                 break;
9052
9053                         iend = softc->ipf_ticks - interval;
9054                 }
9055                 istart -= interval;
9056         }
9057
9058         return removed;
9059 }
9060
9061
9062 /* ------------------------------------------------------------------------ */
9063 /* Function:    ipf_deliverlocal                                            */
9064 /* Returns:     int - 1 = local address, 0 = non-local address              */
9065 /* Parameters:  softc(I)     - pointer to soft context main structure       */
9066 /*              ipversion(I) - IP protocol version (4 or 6)                 */
9067 /*              ifp(I)       - network interface pointer                    */
9068 /*              ipaddr(I)    - IPv4/6 destination address                   */
9069 /*                                                                          */
9070 /* This fucntion is used to determine in the address "ipaddr" belongs to    */
9071 /* the network interface represented by ifp.                                */
9072 /* ------------------------------------------------------------------------ */
9073 int
9074 ipf_deliverlocal(softc, ipversion, ifp, ipaddr)
9075         ipf_main_softc_t *softc;
9076         int ipversion;
9077         void *ifp;
9078         i6addr_t *ipaddr;
9079 {
9080         i6addr_t addr;
9081         int islocal = 0;
9082
9083         if (ipversion == 4) {
9084                 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) {
9085                         if (addr.in4.s_addr == ipaddr->in4.s_addr)
9086                                 islocal = 1;
9087                 }
9088
9089 #ifdef USE_INET6
9090         } else if (ipversion == 6) {
9091                 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) {
9092                         if (IP6_EQ(&addr, ipaddr))
9093                                 islocal = 1;
9094                 }
9095 #endif
9096         }
9097
9098         return islocal;
9099 }
9100
9101
9102 /* ------------------------------------------------------------------------ */
9103 /* Function:    ipf_settimeout                                              */
9104 /* Returns:     int - 0 = success, -1 = failure                             */
9105 /* Parameters:  softc(I) - pointer to soft context main structure           */
9106 /*              t(I)     - pointer to tuneable array entry                  */
9107 /*              p(I)     - pointer to values passed in to apply             */
9108 /*                                                                          */
9109 /* This function is called to set the timeout values for each distinct      */
9110 /* queue timeout that is available.  When called, it calls into both the    */
9111 /* state and NAT code, telling them to update their timeout queues.         */
9112 /* ------------------------------------------------------------------------ */
9113 static int
9114 ipf_settimeout(softc, t, p)
9115         struct ipf_main_softc_s *softc;
9116         ipftuneable_t *t;
9117         ipftuneval_t *p;
9118 {
9119
9120         /*
9121          * ipf_interror should be set by the functions called here, not
9122          * by this function - it's just a middle man.
9123          */
9124         if (ipf_state_settimeout(softc, t, p) == -1)
9125                 return -1;
9126         if (ipf_nat_settimeout(softc, t, p) == -1)
9127                 return -1;
9128         return 0;
9129 }
9130
9131
9132 /* ------------------------------------------------------------------------ */
9133 /* Function:    ipf_apply_timeout                                           */
9134 /* Returns:     int - 0 = success, -1 = failure                             */
9135 /* Parameters:  head(I)    - pointer to tuneable array entry                */
9136 /*              seconds(I) - pointer to values passed in to apply           */
9137 /*                                                                          */
9138 /* This function applies a timeout of "seconds" to the timeout queue that   */
9139 /* is pointed to by "head".  All entries on this list have an expiration    */
9140 /* set to be the current tick value of ipf plus the ttl.  Given that this   */
9141 /* function should only be called when the delta is non-zero, the task is   */
9142 /* to walk the entire list and apply the change.  The sort order will not   */
9143 /* change.  The only catch is that this is O(n) across the list, so if the  */
9144 /* queue has lots of entries (10s of thousands or 100s of thousands), it    */
9145 /* could take a relatively long time to work through them all.              */
9146 /* ------------------------------------------------------------------------ */
9147 void
9148 ipf_apply_timeout(head, seconds)
9149         ipftq_t *head;
9150         u_int seconds;
9151 {
9152         u_int oldtimeout, newtimeout;
9153         ipftqent_t *tqe;
9154         int delta;
9155
9156         MUTEX_ENTER(&head->ifq_lock);
9157         oldtimeout = head->ifq_ttl;
9158         newtimeout = IPF_TTLVAL(seconds);
9159         delta = oldtimeout - newtimeout;
9160
9161         head->ifq_ttl = newtimeout;
9162
9163         for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) {
9164                 tqe->tqe_die += delta;
9165         }
9166         MUTEX_EXIT(&head->ifq_lock);
9167 }
9168
9169
9170 /* ------------------------------------------------------------------------ */
9171 /* Function:   ipf_settimeout_tcp                                           */
9172 /* Returns:    int - 0 = successfully applied, -1 = failed                  */
9173 /* Parameters: t(I)   - pointer to tuneable to change                       */
9174 /*             p(I)   - pointer to new timeout information                  */
9175 /*             tab(I) - pointer to table of TCP queues                      */
9176 /*                                                                          */
9177 /* This function applies the new timeout (p) to the TCP tunable (t) and     */
9178 /* updates all of the entries on the relevant timeout queue by calling      */
9179 /* ipf_apply_timeout().                                                     */
9180 /* ------------------------------------------------------------------------ */
9181 int
9182 ipf_settimeout_tcp(t, p, tab)
9183         ipftuneable_t *t;
9184         ipftuneval_t *p;
9185         ipftq_t *tab;
9186 {
9187         if (!strcmp(t->ipft_name, "tcp_idle_timeout") ||
9188             !strcmp(t->ipft_name, "tcp_established")) {
9189                 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int);
9190         } else if (!strcmp(t->ipft_name, "tcp_close_wait")) {
9191                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int);
9192         } else if (!strcmp(t->ipft_name, "tcp_last_ack")) {
9193                 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int);
9194         } else if (!strcmp(t->ipft_name, "tcp_timeout")) {
9195                 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
9196                 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
9197                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
9198         } else if (!strcmp(t->ipft_name, "tcp_listen")) {
9199                 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
9200         } else if (!strcmp(t->ipft_name, "tcp_half_established")) {
9201                 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
9202         } else if (!strcmp(t->ipft_name, "tcp_closing")) {
9203                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
9204         } else if (!strcmp(t->ipft_name, "tcp_syn_received")) {
9205                 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int);
9206         } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) {
9207                 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int);
9208         } else if (!strcmp(t->ipft_name, "tcp_closed")) {
9209                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
9210         } else if (!strcmp(t->ipft_name, "tcp_half_closed")) {
9211                 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
9212         } else if (!strcmp(t->ipft_name, "tcp_time_wait")) {
9213                 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int);
9214         } else {
9215                 /*
9216                  * ipf_interror isn't set here because it should be set
9217                  * by whatever called this function.
9218                  */
9219                 return -1;
9220         }
9221         return 0;
9222 }
9223
9224
9225 /* ------------------------------------------------------------------------ */
9226 /* Function:   ipf_main_soft_create                                         */
9227 /* Returns:    NULL = failure, else success                                 */
9228 /* Parameters: arg(I) - pointer to soft context structure if already allocd */
9229 /*                                                                          */
9230 /* Create the foundation soft context structure. In circumstances where it  */
9231 /* is not required to dynamically allocate the context, a pointer can be    */
9232 /* passed in (rather than NULL) to a structure to be initialised.           */
9233 /* The main thing of interest is that a number of locks are initialised     */
9234 /* here instead of in the where might be expected - in the relevant create  */
9235 /* function elsewhere.  This is done because the current locking design has */
9236 /* some areas where these locks are used outside of their module.           */
9237 /* Possibly the most important exercise that is done here is setting of all */
9238 /* the timeout values, allowing them to be changed before init().           */
9239 /* ------------------------------------------------------------------------ */
9240 void *
9241 ipf_main_soft_create(arg)
9242         void *arg;
9243 {
9244         ipf_main_softc_t *softc;
9245
9246         if (arg == NULL) {
9247                 KMALLOC(softc, ipf_main_softc_t *);
9248                 if (softc == NULL)
9249                         return NULL;
9250         } else {
9251                 softc = arg;
9252         }
9253
9254         bzero((char *)softc, sizeof(*softc));
9255
9256         /*
9257          * This serves as a flag as to whether or not the softc should be
9258          * free'd when _destroy is called.
9259          */
9260         softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0;
9261
9262         softc->ipf_tuners = ipf_tune_array_copy(softc,
9263                                                 sizeof(ipf_main_tuneables),
9264                                                 ipf_main_tuneables);
9265         if (softc->ipf_tuners == NULL) {
9266                 ipf_main_soft_destroy(softc);
9267                 return NULL;
9268         }
9269
9270         MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex");
9271         MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock");
9272         RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex");
9273         RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock");
9274         RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock");
9275         RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock");
9276         RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock");
9277         RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock");
9278         RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock");
9279
9280         softc->ipf_token_head = NULL;
9281         softc->ipf_token_tail = &softc->ipf_token_head;
9282
9283         softc->ipf_tcpidletimeout = FIVE_DAYS;
9284         softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL);
9285         softc->ipf_tcplastack = IPF_TTLVAL(30);
9286         softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL);
9287         softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL);
9288         softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL);
9289         softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL);
9290         softc->ipf_tcpclosed = IPF_TTLVAL(30);
9291         softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600);
9292         softc->ipf_udptimeout = IPF_TTLVAL(120);
9293         softc->ipf_udpacktimeout = IPF_TTLVAL(12);
9294         softc->ipf_icmptimeout = IPF_TTLVAL(60);
9295         softc->ipf_icmpacktimeout = IPF_TTLVAL(6);
9296         softc->ipf_iptimeout = IPF_TTLVAL(60);
9297
9298 #if defined(IPFILTER_DEFAULT_BLOCK)
9299         softc->ipf_pass = FR_BLOCK|FR_NOMATCH;
9300 #else
9301         softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
9302 #endif
9303         softc->ipf_minttl = 4;
9304         softc->ipf_icmpminfragmtu = 68;
9305         softc->ipf_flags = IPF_LOGGING;
9306
9307         return softc;
9308 }
9309
9310 /* ------------------------------------------------------------------------ */
9311 /* Function:   ipf_main_soft_init                                           */
9312 /* Returns:    0 = success, -1 = failure                                    */
9313 /* Parameters: softc(I) - pointer to soft context main structure            */
9314 /*                                                                          */
9315 /* A null-op function that exists as a placeholder so that the flow in      */
9316 /* other functions is obvious.                                              */
9317 /* ------------------------------------------------------------------------ */
9318 /*ARGSUSED*/
9319 int
9320 ipf_main_soft_init(softc)
9321         ipf_main_softc_t *softc;
9322 {
9323         return 0;
9324 }
9325
9326
9327 /* ------------------------------------------------------------------------ */
9328 /* Function:   ipf_main_soft_destroy                                        */
9329 /* Returns:    void                                                         */
9330 /* Parameters: softc(I) - pointer to soft context main structure            */
9331 /*                                                                          */
9332 /* Undo everything that we did in ipf_main_soft_create.                     */
9333 /*                                                                          */
9334 /* The most important check that needs to be made here is whether or not    */
9335 /* the structure was allocated by ipf_main_soft_create() by checking what   */
9336 /* value is stored in ipf_dynamic_main.                                     */
9337 /* ------------------------------------------------------------------------ */
9338 /*ARGSUSED*/
9339 void
9340 ipf_main_soft_destroy(softc)
9341         ipf_main_softc_t *softc;
9342 {
9343
9344         RW_DESTROY(&softc->ipf_frag);
9345         RW_DESTROY(&softc->ipf_poolrw);
9346         RW_DESTROY(&softc->ipf_nat);
9347         RW_DESTROY(&softc->ipf_state);
9348         RW_DESTROY(&softc->ipf_tokens);
9349         RW_DESTROY(&softc->ipf_mutex);
9350         RW_DESTROY(&softc->ipf_global);
9351         MUTEX_DESTROY(&softc->ipf_timeoutlock);
9352         MUTEX_DESTROY(&softc->ipf_rw);
9353
9354         if (softc->ipf_tuners != NULL) {
9355                 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables));
9356         }
9357         if (softc->ipf_dynamic_softc == 1) {
9358                 KFREE(softc);
9359         }
9360 }
9361
9362
9363 /* ------------------------------------------------------------------------ */
9364 /* Function:   ipf_main_soft_fini                                           */
9365 /* Returns:    0 = success, -1 = failure                                    */
9366 /* Parameters: softc(I) - pointer to soft context main structure            */
9367 /*                                                                          */
9368 /* Clean out the rules which have been added since _init was last called,   */
9369 /* the only dynamic part of the mainline.                                   */
9370 /* ------------------------------------------------------------------------ */
9371 int
9372 ipf_main_soft_fini(softc)
9373         ipf_main_softc_t *softc;
9374 {
9375         (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
9376         (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
9377         (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
9378         (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE);
9379
9380         return 0;
9381 }
9382
9383
9384 /* ------------------------------------------------------------------------ */
9385 /* Function:   ipf_main_load                                                */
9386 /* Returns:    0 = success, -1 = failure                                    */
9387 /* Parameters: none                                                         */
9388 /*                                                                          */
9389 /* Handle global initialisation that needs to be done for the base part of  */
9390 /* IPFilter. At present this just amounts to initialising some ICMP lookup  */
9391 /* arrays that get used by the state/NAT code.                              */
9392 /* ------------------------------------------------------------------------ */
9393 int
9394 ipf_main_load()
9395 {
9396         int i;
9397
9398         /* fill icmp reply type table */
9399         for (i = 0; i <= ICMP_MAXTYPE; i++)
9400                 icmpreplytype4[i] = -1;
9401         icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
9402         icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
9403         icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
9404         icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
9405
9406 #ifdef  USE_INET6
9407         /* fill icmp reply type table */
9408         for (i = 0; i <= ICMP6_MAXTYPE; i++)
9409                 icmpreplytype6[i] = -1;
9410         icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
9411         icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
9412         icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
9413         icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
9414         icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
9415 #endif
9416
9417         return 0;
9418 }
9419
9420
9421 /* ------------------------------------------------------------------------ */
9422 /* Function:   ipf_main_unload                                              */
9423 /* Returns:    0 = success, -1 = failure                                    */
9424 /* Parameters: none                                                         */
9425 /*                                                                          */
9426 /* A null-op function that exists as a placeholder so that the flow in      */
9427 /* other functions is obvious.                                              */
9428 /* ------------------------------------------------------------------------ */
9429 int
9430 ipf_main_unload()
9431 {
9432         return 0;
9433 }
9434
9435
9436 /* ------------------------------------------------------------------------ */
9437 /* Function:   ipf_load_all                                                 */
9438 /* Returns:    0 = success, -1 = failure                                    */
9439 /* Parameters: none                                                         */
9440 /*                                                                          */
9441 /* Work through all of the subsystems inside IPFilter and call the load     */
9442 /* function for each in an order that won't lead to a crash :)              */
9443 /* ------------------------------------------------------------------------ */
9444 int
9445 ipf_load_all()
9446 {
9447         if (ipf_main_load() == -1)
9448                 return -1;
9449
9450         if (ipf_state_main_load() == -1)
9451                 return -1;
9452
9453         if (ipf_nat_main_load() == -1)
9454                 return -1;
9455
9456         if (ipf_frag_main_load() == -1)
9457                 return -1;
9458
9459         if (ipf_auth_main_load() == -1)
9460                 return -1;
9461
9462         if (ipf_proxy_main_load() == -1)
9463                 return -1;
9464
9465         return 0;
9466 }
9467
9468
9469 /* ------------------------------------------------------------------------ */
9470 /* Function:   ipf_unload_all                                               */
9471 /* Returns:    0 = success, -1 = failure                                    */
9472 /* Parameters: none                                                         */
9473 /*                                                                          */
9474 /* Work through all of the subsystems inside IPFilter and call the unload   */
9475 /* function for each in an order that won't lead to a crash :)              */
9476 /* ------------------------------------------------------------------------ */
9477 int
9478 ipf_unload_all()
9479 {
9480         if (ipf_proxy_main_unload() == -1)
9481                 return -1;
9482
9483         if (ipf_auth_main_unload() == -1)
9484                 return -1;
9485
9486         if (ipf_frag_main_unload() == -1)
9487                 return -1;
9488
9489         if (ipf_nat_main_unload() == -1)
9490                 return -1;
9491
9492         if (ipf_state_main_unload() == -1)
9493                 return -1;
9494
9495         if (ipf_main_unload() == -1)
9496                 return -1;
9497
9498         return 0;
9499 }
9500
9501
9502 /* ------------------------------------------------------------------------ */
9503 /* Function:   ipf_create_all                                               */
9504 /* Returns:    NULL = failure, else success                                 */
9505 /* Parameters: arg(I) - pointer to soft context main structure              */
9506 /*                                                                          */
9507 /* Work through all of the subsystems inside IPFilter and call the create   */
9508 /* function for each in an order that won't lead to a crash :)              */
9509 /* ------------------------------------------------------------------------ */
9510 ipf_main_softc_t *
9511 ipf_create_all(arg)
9512         void *arg;
9513 {
9514         ipf_main_softc_t *softc;
9515
9516         softc = ipf_main_soft_create(arg);
9517         if (softc == NULL)
9518                 return NULL;
9519
9520 #ifdef IPFILTER_LOG
9521         softc->ipf_log_soft = ipf_log_soft_create(softc);
9522         if (softc->ipf_log_soft == NULL) {
9523                 ipf_destroy_all(softc);
9524                 return NULL;
9525         }
9526 #endif
9527
9528         softc->ipf_lookup_soft = ipf_lookup_soft_create(softc);
9529         if (softc->ipf_lookup_soft == NULL) {
9530                 ipf_destroy_all(softc);
9531                 return NULL;
9532         }
9533
9534         softc->ipf_sync_soft = ipf_sync_soft_create(softc);
9535         if (softc->ipf_sync_soft == NULL) {
9536                 ipf_destroy_all(softc);
9537                 return NULL;
9538         }
9539
9540         softc->ipf_state_soft = ipf_state_soft_create(softc);
9541         if (softc->ipf_state_soft == NULL) {
9542                 ipf_destroy_all(softc);
9543                 return NULL;
9544         }
9545
9546         softc->ipf_nat_soft = ipf_nat_soft_create(softc);
9547         if (softc->ipf_nat_soft == NULL) {
9548                 ipf_destroy_all(softc);
9549                 return NULL;
9550         }
9551
9552         softc->ipf_frag_soft = ipf_frag_soft_create(softc);
9553         if (softc->ipf_frag_soft == NULL) {
9554                 ipf_destroy_all(softc);
9555                 return NULL;
9556         }
9557
9558         softc->ipf_auth_soft = ipf_auth_soft_create(softc);
9559         if (softc->ipf_auth_soft == NULL) {
9560                 ipf_destroy_all(softc);
9561                 return NULL;
9562         }
9563
9564         softc->ipf_proxy_soft = ipf_proxy_soft_create(softc);
9565         if (softc->ipf_proxy_soft == NULL) {
9566                 ipf_destroy_all(softc);
9567                 return NULL;
9568         }
9569
9570         return softc;
9571 }
9572
9573
9574 /* ------------------------------------------------------------------------ */
9575 /* Function:   ipf_destroy_all                                              */
9576 /* Returns:    void                                                         */
9577 /* Parameters: softc(I) - pointer to soft context main structure            */
9578 /*                                                                          */
9579 /* Work through all of the subsystems inside IPFilter and call the destroy  */
9580 /* function for each in an order that won't lead to a crash :)              */
9581 /*                                                                          */
9582 /* Every one of these functions is expected to succeed, so there is no      */
9583 /* checking of return values.                                               */
9584 /* ------------------------------------------------------------------------ */
9585 void
9586 ipf_destroy_all(softc)
9587         ipf_main_softc_t *softc;
9588 {
9589
9590         if (softc->ipf_state_soft != NULL) {
9591                 ipf_state_soft_destroy(softc, softc->ipf_state_soft);
9592                 softc->ipf_state_soft = NULL;
9593         }
9594
9595         if (softc->ipf_nat_soft != NULL) {
9596                 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft);
9597                 softc->ipf_nat_soft = NULL;
9598         }
9599
9600         if (softc->ipf_frag_soft != NULL) {
9601                 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft);
9602                 softc->ipf_frag_soft = NULL;
9603         }
9604
9605         if (softc->ipf_auth_soft != NULL) {
9606                 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft);
9607                 softc->ipf_auth_soft = NULL;
9608         }
9609
9610         if (softc->ipf_proxy_soft != NULL) {
9611                 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft);
9612                 softc->ipf_proxy_soft = NULL;
9613         }
9614
9615         if (softc->ipf_sync_soft != NULL) {
9616                 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft);
9617                 softc->ipf_sync_soft = NULL;
9618         }
9619
9620         if (softc->ipf_lookup_soft != NULL) {
9621                 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft);
9622                 softc->ipf_lookup_soft = NULL;
9623         }
9624
9625 #ifdef IPFILTER_LOG
9626         if (softc->ipf_log_soft != NULL) {
9627                 ipf_log_soft_destroy(softc, softc->ipf_log_soft);
9628                 softc->ipf_log_soft = NULL;
9629         }
9630 #endif
9631
9632         ipf_main_soft_destroy(softc);
9633 }
9634
9635
9636 /* ------------------------------------------------------------------------ */
9637 /* Function:   ipf_init_all                                                 */
9638 /* Returns:    0 = success, -1 = failure                                    */
9639 /* Parameters: softc(I) - pointer to soft context main structure            */
9640 /*                                                                          */
9641 /* Work through all of the subsystems inside IPFilter and call the init     */
9642 /* function for each in an order that won't lead to a crash :)              */
9643 /* ------------------------------------------------------------------------ */
9644 int
9645 ipf_init_all(softc)
9646         ipf_main_softc_t *softc;
9647 {
9648
9649         if (ipf_main_soft_init(softc) == -1)
9650                 return -1;
9651
9652 #ifdef IPFILTER_LOG
9653         if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1)
9654                 return -1;
9655 #endif
9656
9657         if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1)
9658                 return -1;
9659
9660         if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1)
9661                 return -1;
9662
9663         if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1)
9664                 return -1;
9665
9666         if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1)
9667                 return -1;
9668
9669         if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1)
9670                 return -1;
9671
9672         if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1)
9673                 return -1;
9674
9675         if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1)
9676                 return -1;
9677
9678         return 0;
9679 }
9680
9681
9682 /* ------------------------------------------------------------------------ */
9683 /* Function:   ipf_fini_all                                                 */
9684 /* Returns:    0 = success, -1 = failure                                    */
9685 /* Parameters: softc(I) - pointer to soft context main structure            */
9686 /*                                                                          */
9687 /* Work through all of the subsystems inside IPFilter and call the fini     */
9688 /* function for each in an order that won't lead to a crash :)              */
9689 /* ------------------------------------------------------------------------ */
9690 int
9691 ipf_fini_all(softc)
9692         ipf_main_softc_t *softc;
9693 {
9694
9695         ipf_token_flush(softc);
9696
9697         if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1)
9698                 return -1;
9699
9700         if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1)
9701                 return -1;
9702
9703         if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1)
9704                 return -1;
9705
9706         if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1)
9707                 return -1;
9708
9709         if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1)
9710                 return -1;
9711
9712         if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1)
9713                 return -1;
9714
9715         if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1)
9716                 return -1;
9717
9718 #ifdef IPFILTER_LOG
9719         if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1)
9720                 return -1;
9721 #endif
9722
9723         if (ipf_main_soft_fini(softc) == -1)
9724                 return -1;
9725
9726         return 0;
9727 }
9728
9729
9730 /* ------------------------------------------------------------------------ */
9731 /* Function:    ipf_rule_expire                                             */
9732 /* Returns:     Nil                                                         */
9733 /* Parameters:  softc(I) - pointer to soft context main structure           */
9734 /*                                                                          */
9735 /* At present this function exists just to support temporary addition of    */
9736 /* firewall rules. Both inactive and active lists are scanned for items to  */
9737 /* purge, as by rights, the expiration is computed as soon as the rule is   */
9738 /* loaded in.                                                               */
9739 /* ------------------------------------------------------------------------ */
9740 void
9741 ipf_rule_expire(softc)
9742         ipf_main_softc_t *softc;
9743 {
9744         frentry_t *fr;
9745
9746         if ((softc->ipf_rule_explist[0] == NULL) &&
9747             (softc->ipf_rule_explist[1] == NULL))
9748                 return;
9749
9750         WRITE_ENTER(&softc->ipf_mutex);
9751
9752         while ((fr = softc->ipf_rule_explist[0]) != NULL) {
9753                 /*
9754                  * Because the list is kept sorted on insertion, the fist
9755                  * one that dies in the future means no more work to do.
9756                  */
9757                 if (fr->fr_die > softc->ipf_ticks)
9758                         break;
9759                 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0);
9760         }
9761
9762         while ((fr = softc->ipf_rule_explist[1]) != NULL) {
9763                 /*
9764                  * Because the list is kept sorted on insertion, the fist
9765                  * one that dies in the future means no more work to do.
9766                  */
9767                 if (fr->fr_die > softc->ipf_ticks)
9768                         break;
9769                 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1);
9770         }
9771
9772         RWLOCK_EXIT(&softc->ipf_mutex);
9773 }
9774
9775
9776 static int ipf_ht_node_cmp __P((struct host_node_s *, struct host_node_s *));
9777 static void ipf_ht_node_make_key __P((host_track_t *, host_node_t *, int,
9778                                       i6addr_t *));
9779
9780 host_node_t RBI_ZERO(ipf_rb);
9781 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp)
9782
9783
9784 /* ------------------------------------------------------------------------ */
9785 /* Function:    ipf_ht_node_cmp                                             */
9786 /* Returns:     int   - 0 == nodes are the same, ..                         */
9787 /* Parameters:  k1(I) - pointer to first key to compare                     */
9788 /*              k2(I) - pointer to second key to compare                    */
9789 /*                                                                          */
9790 /* The "key" for the node is a combination of two fields: the address       */
9791 /* family and the address itself.                                           */
9792 /*                                                                          */
9793 /* Because we're not actually interpreting the address data, it isn't       */
9794 /* necessary to convert them to/from network/host byte order. The mask is   */
9795 /* just used to remove bits that aren't significant - it doesn't matter     */
9796 /* where they are, as long as they're always in the same place.             */
9797 /*                                                                          */
9798 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because    */
9799 /* this is where individual ones will differ the most - but not true for    */
9800 /* for /48's, etc.                                                          */
9801 /* ------------------------------------------------------------------------ */
9802 static int
9803 ipf_ht_node_cmp(k1, k2)
9804         struct host_node_s *k1, *k2;
9805 {
9806         int i;
9807
9808         i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family);
9809         if (i != 0)
9810                 return i;
9811
9812         if (k1->hn_addr.adf_family == AF_INET)
9813                 return (k2->hn_addr.adf_addr.in4.s_addr -
9814                         k1->hn_addr.adf_addr.in4.s_addr);
9815
9816         i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3];
9817         if (i != 0)
9818                 return i;
9819         i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2];
9820         if (i != 0)
9821                 return i;
9822         i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1];
9823         if (i != 0)
9824                 return i;
9825         i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0];
9826         return i;
9827 }
9828
9829
9830 /* ------------------------------------------------------------------------ */
9831 /* Function:    ipf_ht_node_make_key                                        */
9832 /* Returns:     Nil                                                         */
9833 /* parameters:  htp(I)    - pointer to address tracking structure           */
9834 /*              key(I)    - where to store masked address for lookup        */
9835 /*              family(I) - protocol family of address                      */
9836 /*              addr(I)   - pointer to network address                      */
9837 /*                                                                          */
9838 /* Using the "netmask" (number of bits) stored parent host tracking struct, */
9839 /* copy the address passed in into the key structure whilst masking out the */
9840 /* bits that we don't want.                                                 */
9841 /*                                                                          */
9842 /* Because the parser will set ht_netmask to 128 if there is no protocol    */
9843 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we  */
9844 /* have to be wary of that and not allow 32-128 to happen.                  */
9845 /* ------------------------------------------------------------------------ */
9846 static void
9847 ipf_ht_node_make_key(htp, key, family, addr)
9848         host_track_t *htp;
9849         host_node_t *key;
9850         int family;
9851         i6addr_t *addr;
9852 {
9853         key->hn_addr.adf_family = family;
9854         if (family == AF_INET) {
9855                 u_32_t mask;
9856                 int bits;
9857
9858                 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4);
9859                 bits = htp->ht_netmask;
9860                 if (bits >= 32) {
9861                         mask = 0xffffffff;
9862                 } else {
9863                         mask = htonl(0xffffffff << (32 - bits));
9864                 }
9865                 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask;
9866 #ifdef USE_INET6
9867         } else {
9868                 int bits = htp->ht_netmask;
9869
9870                 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6);
9871                 if (bits > 96) {
9872                         key->hn_addr.adf_addr.i6[3] = addr->i6[3] &
9873                                              htonl(0xffffffff << (128 - bits));
9874                         key->hn_addr.adf_addr.i6[2] = addr->i6[2];
9875                         key->hn_addr.adf_addr.i6[1] = addr->i6[2];
9876                         key->hn_addr.adf_addr.i6[0] = addr->i6[2];
9877                 } else if (bits > 64) {
9878                         key->hn_addr.adf_addr.i6[3] = 0;
9879                         key->hn_addr.adf_addr.i6[2] = addr->i6[2] &
9880                                              htonl(0xffffffff << (96 - bits));
9881                         key->hn_addr.adf_addr.i6[1] = addr->i6[1];
9882                         key->hn_addr.adf_addr.i6[0] = addr->i6[0];
9883                 } else if (bits > 32) {
9884                         key->hn_addr.adf_addr.i6[3] = 0;
9885                         key->hn_addr.adf_addr.i6[2] = 0;
9886                         key->hn_addr.adf_addr.i6[1] = addr->i6[1] &
9887                                              htonl(0xffffffff << (64 - bits));
9888                         key->hn_addr.adf_addr.i6[0] = addr->i6[0];
9889                 } else {
9890                         key->hn_addr.adf_addr.i6[3] = 0;
9891                         key->hn_addr.adf_addr.i6[2] = 0;
9892                         key->hn_addr.adf_addr.i6[1] = 0;
9893                         key->hn_addr.adf_addr.i6[0] = addr->i6[0] &
9894                                              htonl(0xffffffff << (32 - bits));
9895                 }
9896 #endif
9897         }
9898 }
9899
9900
9901 /* ------------------------------------------------------------------------ */
9902 /* Function:    ipf_ht_node_add                                             */
9903 /* Returns:     int       - 0 == success,  -1 == failure                    */
9904 /* Parameters:  softc(I)  - pointer to soft context main structure          */
9905 /*              htp(I)    - pointer to address tracking structure           */
9906 /*              family(I) - protocol family of address                      */
9907 /*              addr(I)   - pointer to network address                      */
9908 /*                                                                          */
9909 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
9910 /*       ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
9911 /*                                                                          */
9912 /* After preparing the key with the address information to find, look in    */
9913 /* the red-black tree to see if the address is known. A successful call to  */
9914 /* this function can mean one of two things: a new node was added to the    */
9915 /* tree or a matching node exists and we're able to bump up its activity.   */
9916 /* ------------------------------------------------------------------------ */
9917 int
9918 ipf_ht_node_add(softc, htp, family, addr)
9919         ipf_main_softc_t *softc;
9920         host_track_t *htp;
9921         int family;
9922         i6addr_t *addr;
9923 {
9924         host_node_t *h;
9925         host_node_t k;
9926
9927         ipf_ht_node_make_key(htp, &k, family, addr);
9928
9929         h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
9930         if (h == NULL) {
9931                 if (htp->ht_cur_nodes >= htp->ht_max_nodes)
9932                         return -1;
9933                 KMALLOC(h, host_node_t *);
9934                 if (h == NULL) {
9935                         DT(ipf_rb_no_mem);
9936                         LBUMP(ipf_rb_no_mem);
9937                         return -1;
9938                 }
9939
9940                 /*
9941                  * If there was a macro to initialise the RB node then that
9942                  * would get used here, but there isn't...
9943                  */
9944                 bzero((char *)h, sizeof(*h));
9945                 h->hn_addr = k.hn_addr;
9946                 h->hn_addr.adf_family = k.hn_addr.adf_family;
9947                 RBI_INSERT(ipf_rb, &htp->ht_root, h);
9948                 htp->ht_cur_nodes++;
9949         } else {
9950                 if ((htp->ht_max_per_node != 0) &&
9951                     (h->hn_active >= htp->ht_max_per_node)) {
9952                         DT(ipf_rb_node_max);
9953                         LBUMP(ipf_rb_node_max);
9954                         return -1;
9955                 }
9956         }
9957
9958         h->hn_active++;
9959
9960         return 0;
9961 }
9962
9963
9964 /* ------------------------------------------------------------------------ */
9965 /* Function:    ipf_ht_node_del                                             */
9966 /* Returns:     int       - 0 == success,  -1 == failure                    */
9967 /* parameters:  htp(I)    - pointer to address tracking structure           */
9968 /*              family(I) - protocol family of address                      */
9969 /*              addr(I)   - pointer to network address                      */
9970 /*                                                                          */
9971 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS  */
9972 /*       ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp.         */
9973 /*                                                                          */
9974 /* Try and find the address passed in amongst the leavese on this tree to   */
9975 /* be friend. If found then drop the active account for that node drops by  */
9976 /* one. If that count reaches 0, it is time to free it all up.              */
9977 /* ------------------------------------------------------------------------ */
9978 int
9979 ipf_ht_node_del(htp, family, addr)
9980         host_track_t *htp;
9981         int family;
9982         i6addr_t *addr;
9983 {
9984         host_node_t *h;
9985         host_node_t k;
9986
9987         ipf_ht_node_make_key(htp, &k, family, addr);
9988
9989         h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
9990         if (h == NULL) {
9991                 return -1;
9992         } else {
9993                 h->hn_active--;
9994                 if (h->hn_active == 0) {
9995                         (void) RBI_DELETE(ipf_rb, &htp->ht_root, h);
9996                         htp->ht_cur_nodes--;
9997                         KFREE(h);
9998                 }
9999         }
10000
10001         return 0;
10002 }
10003
10004
10005 /* ------------------------------------------------------------------------ */
10006 /* Function:    ipf_rb_ht_init                                              */
10007 /* Returns:     Nil                                                         */
10008 /* Parameters:  head(I) - pointer to host tracking structure                */
10009 /*                                                                          */
10010 /* Initialise the host tracking structure to be ready for use above.        */
10011 /* ------------------------------------------------------------------------ */
10012 void
10013 ipf_rb_ht_init(head)
10014         host_track_t *head;
10015 {
10016         RBI_INIT(ipf_rb, &head->ht_root);
10017 }
10018
10019
10020 /* ------------------------------------------------------------------------ */
10021 /* Function:    ipf_rb_ht_freenode                                          */
10022 /* Returns:     Nil                                                         */
10023 /* Parameters:  head(I) - pointer to host tracking structure                */
10024 /*              arg(I)  - additional argument from walk caller              */
10025 /*                                                                          */
10026 /* Free an actual host_node_t structure.                                    */
10027 /* ------------------------------------------------------------------------ */
10028 void
10029 ipf_rb_ht_freenode(node, arg)
10030         host_node_t *node;
10031         void *arg;
10032 {
10033         KFREE(node);
10034 }
10035
10036
10037 /* ------------------------------------------------------------------------ */
10038 /* Function:    ipf_rb_ht_flush                                             */
10039 /* Returns:     Nil                                                         */
10040 /* Parameters:  head(I) - pointer to host tracking structure                */
10041 /*                                                                          */
10042 /* Remove all of the nodes in the tree tracking hosts by calling a walker   */
10043 /* and free'ing each one.                                                   */
10044 /* ------------------------------------------------------------------------ */
10045 void
10046 ipf_rb_ht_flush(head)
10047         host_track_t *head;
10048 {
10049         RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL);
10050 }
10051
10052
10053 /* ------------------------------------------------------------------------ */
10054 /* Function:    ipf_slowtimer                                               */
10055 /* Returns:     Nil                                                         */
10056 /* Parameters:  ptr(I) - pointer to main ipf soft context structure         */
10057 /*                                                                          */
10058 /* Slowly expire held state for fragments.  Timeouts are set * in           */
10059 /* expectation of this being called twice per second.                       */
10060 /* ------------------------------------------------------------------------ */
10061 void
10062 ipf_slowtimer(softc)
10063         ipf_main_softc_t *softc;
10064 {
10065
10066         ipf_token_expire(softc);
10067         ipf_frag_expire(softc);
10068         ipf_state_expire(softc);
10069         ipf_nat_expire(softc);
10070         ipf_auth_expire(softc);
10071         ipf_lookup_expire(softc);
10072         ipf_rule_expire(softc);
10073         ipf_sync_expire(softc);
10074         softc->ipf_ticks++;
10075 #   if defined(__OpenBSD__)
10076         timeout_add(&ipf_slowtimer_ch, hz/2);
10077 #   endif
10078 }
10079
10080
10081 /* ------------------------------------------------------------------------ */
10082 /* Function:    ipf_inet_mask_add                                           */
10083 /* Returns:     Nil                                                         */
10084 /* Parameters:  bits(I) - pointer to nat context information                */
10085 /*              mtab(I) - pointer to mask hash table structure              */
10086 /*                                                                          */
10087 /* When called, bits represents the mask of a new NAT rule that has just    */
10088 /* been added. This function inserts a bitmask into the array of masks to   */
10089 /* search when searching for a matching NAT rule for a packet.              */
10090 /* Prevention of duplicate masks is achieved by checking the use count for  */
10091 /* a given netmask.                                                         */
10092 /* ------------------------------------------------------------------------ */
10093 void
10094 ipf_inet_mask_add(bits, mtab)
10095         int bits;
10096         ipf_v4_masktab_t *mtab;
10097 {
10098         u_32_t mask;
10099         int i, j;
10100
10101         mtab->imt4_masks[bits]++;
10102         if (mtab->imt4_masks[bits] > 1)
10103                 return;
10104
10105         if (bits == 0)
10106                 mask = 0;
10107         else
10108                 mask = 0xffffffff << (32 - bits);
10109
10110         for (i = 0; i < 33; i++) {
10111                 if (ntohl(mtab->imt4_active[i]) < mask) {
10112                         for (j = 32; j > i; j--)
10113                                 mtab->imt4_active[j] = mtab->imt4_active[j - 1];
10114                         mtab->imt4_active[i] = htonl(mask);
10115                         break;
10116                 }
10117         }
10118         mtab->imt4_max++;
10119 }
10120
10121
10122 /* ------------------------------------------------------------------------ */
10123 /* Function:    ipf_inet_mask_del                                           */
10124 /* Returns:     Nil                                                         */
10125 /* Parameters:  bits(I) - number of bits set in the netmask                 */
10126 /*              mtab(I) - pointer to mask hash table structure              */
10127 /*                                                                          */
10128 /* Remove the 32bit bitmask represented by "bits" from the collection of    */
10129 /* netmasks stored inside of mtab.                                          */
10130 /* ------------------------------------------------------------------------ */
10131 void
10132 ipf_inet_mask_del(bits, mtab)
10133         int bits;
10134         ipf_v4_masktab_t *mtab;
10135 {
10136         u_32_t mask;
10137         int i, j;
10138
10139         mtab->imt4_masks[bits]--;
10140         if (mtab->imt4_masks[bits] > 0)
10141                 return;
10142
10143         mask = htonl(0xffffffff << (32 - bits));
10144         for (i = 0; i < 33; i++) {
10145                 if (mtab->imt4_active[i] == mask) {
10146                         for (j = i + 1; j < 33; j++)
10147                                 mtab->imt4_active[j - 1] = mtab->imt4_active[j];
10148                         break;
10149                 }
10150         }
10151         mtab->imt4_max--;
10152         ASSERT(mtab->imt4_max >= 0);
10153 }
10154
10155
10156 #ifdef USE_INET6
10157 /* ------------------------------------------------------------------------ */
10158 /* Function:    ipf_inet6_mask_add                                          */
10159 /* Returns:     Nil                                                         */
10160 /* Parameters:  bits(I) - number of bits set in mask                        */
10161 /*              mask(I) - pointer to mask to add                            */
10162 /*              mtab(I) - pointer to mask hash table structure              */
10163 /*                                                                          */
10164 /* When called, bitcount represents the mask of a IPv6 NAT map rule that    */
10165 /* has just been added. This function inserts a bitmask into the array of   */
10166 /* masks to search when searching for a matching NAT rule for a packet.     */
10167 /* Prevention of duplicate masks is achieved by checking the use count for  */
10168 /* a given netmask.                                                         */
10169 /* ------------------------------------------------------------------------ */
10170 void
10171 ipf_inet6_mask_add(bits, mask, mtab)
10172         int bits;
10173         i6addr_t *mask;
10174         ipf_v6_masktab_t *mtab;
10175 {
10176         i6addr_t zero;
10177         int i, j;
10178
10179         mtab->imt6_masks[bits]++;
10180         if (mtab->imt6_masks[bits] > 1)
10181                 return;
10182
10183         if (bits == 0) {
10184                 mask = &zero;
10185                 zero.i6[0] = 0;
10186                 zero.i6[1] = 0;
10187                 zero.i6[2] = 0;
10188                 zero.i6[3] = 0;
10189         }
10190
10191         for (i = 0; i < 129; i++) {
10192                 if (IP6_LT(&mtab->imt6_active[i], mask)) {
10193                         for (j = 128; j > i; j--)
10194                                 mtab->imt6_active[j] = mtab->imt6_active[j - 1];
10195                         mtab->imt6_active[i] = *mask;
10196                         break;
10197                 }
10198         }
10199         mtab->imt6_max++;
10200 }
10201
10202
10203 /* ------------------------------------------------------------------------ */
10204 /* Function:    ipf_inet6_mask_del                                          */
10205 /* Returns:     Nil                                                         */
10206 /* Parameters:  bits(I) - number of bits set in mask                        */
10207 /*              mask(I) - pointer to mask to remove                         */
10208 /*              mtab(I) - pointer to mask hash table structure              */
10209 /*                                                                          */
10210 /* Remove the 128bit bitmask represented by "bits" from the collection of   */
10211 /* netmasks stored inside of mtab.                                          */
10212 /* ------------------------------------------------------------------------ */
10213 void
10214 ipf_inet6_mask_del(bits, mask, mtab)
10215         int bits;
10216         i6addr_t *mask;
10217         ipf_v6_masktab_t *mtab;
10218 {
10219         i6addr_t zero;
10220         int i, j;
10221
10222         mtab->imt6_masks[bits]--;
10223         if (mtab->imt6_masks[bits] > 0)
10224                 return;
10225
10226         if (bits == 0)
10227                 mask = &zero;
10228         zero.i6[0] = 0;
10229         zero.i6[1] = 0;
10230         zero.i6[2] = 0;
10231         zero.i6[3] = 0;
10232
10233         for (i = 0; i < 129; i++) {
10234                 if (IP6_EQ(&mtab->imt6_active[i], mask)) {
10235                         for (j = i + 1; j < 129; j++) {
10236                                 mtab->imt6_active[j - 1] = mtab->imt6_active[j];
10237                                 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero))
10238                                         break;
10239                         }
10240                         break;
10241                 }
10242         }
10243         mtab->imt6_max--;
10244         ASSERT(mtab->imt6_max >= 0);
10245 }
10246 #endif