]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ipfilter/netinet/fil.c
This commit was generated by cvs2svn to compensate for changes in r169942,
[FreeBSD/FreeBSD.git] / sys / contrib / ipfilter / netinet / fil.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 1993-2003 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL  1
12 # define        _KERNEL 1
13 #endif
14 #include <sys/errno.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/time.h>
18 #if defined(__NetBSD__)
19 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
20 #  include "opt_ipfilter_log.h"
21 # endif
22 #endif
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(_AIX51)
38 # include <sys/fcntl.h>
39 #endif
40 #if defined(_KERNEL)
41 # include <sys/systm.h>
42 # include <sys/file.h>
43 #else
44 # include <stdio.h>
45 # include <string.h>
46 # include <stdlib.h>
47 # include <stddef.h>
48 # include <sys/file.h>
49 # define _KERNEL
50 # ifdef __OpenBSD__
51 struct file;
52 # endif
53 # include <sys/uio.h>
54 # undef _KERNEL
55 #endif
56 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \
57     !defined(linux)
58 # include <sys/mbuf.h>
59 #else
60 # if !defined(linux)
61 #  include <sys/byteorder.h>
62 # endif
63 # if (SOLARIS2 < 5) && defined(sun)
64 #  include <sys/dditypes.h>
65 # endif
66 #endif
67 #ifdef __hpux
68 # define _NET_ROUTE_INCLUDED
69 #endif
70 #if !defined(linux)
71 # include <sys/protosw.h>
72 #endif
73 #include <sys/socket.h>
74 #include <net/if.h>
75 #ifdef sun
76 # include <net/af.h>
77 #endif
78 #if !defined(_KERNEL) && defined(__FreeBSD__)
79 # if (__FreeBSD_version >= 504000)
80 #  undef _RADIX_H_
81 # endif
82 # include "radix_ipf.h"
83 #endif
84 #include <net/route.h>
85 #include <netinet/in.h>
86 #include <netinet/in_systm.h>
87 #include <netinet/ip.h>
88 #if !defined(linux)
89 # include <netinet/ip_var.h>
90 #endif
91 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
92 # include <sys/hashing.h>
93 # include <netinet/in_var.h>
94 #endif
95 #include <netinet/tcp.h>
96 #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL)
97 # include <netinet/udp.h>
98 # include <netinet/ip_icmp.h>
99 #endif
100 #ifdef __hpux
101 # undef _NET_ROUTE_INCLUDED
102 #endif
103 #include "netinet/ip_compat.h"
104 #ifdef  USE_INET6
105 # include <netinet/icmp6.h>
106 # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux)
107 #  include <netinet6/in6_var.h>
108 # endif
109 #endif
110 #include <netinet/tcpip.h>
111 #include "netinet/ip_fil.h"
112 #include "netinet/ip_nat.h"
113 #include "netinet/ip_frag.h"
114 #include "netinet/ip_state.h"
115 #include "netinet/ip_proxy.h"
116 #include "netinet/ip_auth.h"
117 #ifdef IPFILTER_SCAN
118 # include "netinet/ip_scan.h"
119 #endif
120 #ifdef IPFILTER_SYNC
121 # include "netinet/ip_sync.h"
122 #endif
123 #include "netinet/ip_pool.h"
124 #include "netinet/ip_htable.h"
125 #ifdef IPFILTER_COMPILED
126 # include "netinet/ip_rules.h"
127 #endif
128 #if defined(IPFILTER_BPF) && defined(_KERNEL)
129 # include <net/bpf.h>
130 #endif
131 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
132 # include <sys/malloc.h>
133 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
134 #  include "opt_ipfilter.h"
135 # endif
136 #endif
137 #include "netinet/ipl.h"
138 /* END OF INCLUDES */
139
140 #include <machine/in_cksum.h>
141
142 #if !defined(lint)
143 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
144 static const char rcsid[] = "@(#)$FreeBSD$";
145 /* static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.78 2006/03/29 11:19:54 darrenr Exp $"; */
146 #endif
147
148 #ifndef _KERNEL
149 # include "ipf.h"
150 # include "ipt.h"
151 # include "bpf-ipf.h"
152 extern  int     opts;
153 #endif /* _KERNEL */
154
155
156 fr_info_t       frcache[2][8];
157 struct  filterstats frstats[2] = { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } };
158 struct  frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
159                 *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } },
160                 *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } },
161                 *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } },
162                 *ipnatrules[2][2] = { { NULL, NULL }, { NULL, NULL } };
163 struct  frgroup *ipfgroups[IPL_LOGSIZE][2];
164 char    ipfilter_version[] = IPL_VERSION;
165 int     fr_refcnt = 0;
166 /*
167  * For fr_running:
168  * 0 == loading, 1 = running, -1 = disabled, -2 = unloading
169  */
170 int     fr_running = 0;
171 int     fr_flags = IPF_LOGGING;
172 int     fr_active = 0;
173 int     fr_control_forwarding = 0;
174 int     fr_update_ipid = 0;
175 u_short fr_ip_id = 0;
176 int     fr_chksrc = 0;  /* causes a system crash if enabled */
177 int     fr_minttl = 4;
178 int     fr_icmpminfragmtu = 68;
179 u_long  fr_frouteok[2] = {0, 0};
180 u_long  fr_userifqs = 0;
181 u_long  fr_badcoalesces[2] = {0, 0};
182 u_char  ipf_iss_secret[32];
183 #if defined(IPFILTER_DEFAULT_BLOCK)
184 int     fr_pass = FR_BLOCK|FR_NOMATCH;
185 #else
186 int     fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
187 #endif
188 int     fr_features = 0
189 #ifdef  IPFILTER_LKM
190                 | IPF_FEAT_LKM
191 #endif
192 #ifdef  IPFILTER_LOG
193                 | IPF_FEAT_LOG
194 #endif
195 #ifdef  IPFILTER_LOOKUP
196                 | IPF_FEAT_LOOKUP
197 #endif
198 #ifdef  IPFILTER_BPF
199                 | IPF_FEAT_BPF
200 #endif
201 #ifdef  IPFILTER_COMPILED
202                 | IPF_FEAT_COMPILED
203 #endif
204 #ifdef  IPFILTER_CKSUM
205                 | IPF_FEAT_CKSUM
206 #endif
207 #ifdef  IPFILTER_SYNC
208                 | IPF_FEAT_SYNC
209 #endif
210 #ifdef  IPFILTER_SCAN
211                 | IPF_FEAT_SCAN
212 #endif
213 #ifdef  USE_INET6
214                 | IPF_FEAT_IPV6
215 #endif
216         ;
217
218 static  INLINE int      fr_ipfcheck __P((fr_info_t *, frentry_t *, int));
219 static  int             fr_portcheck __P((frpcmp_t *, u_short *));
220 static  int             frflushlist __P((int, minor_t, int *, frentry_t **));
221 static  ipfunc_t        fr_findfunc __P((ipfunc_t));
222 static  frentry_t       *fr_firewall __P((fr_info_t *, u_32_t *));
223 static  int             fr_funcinit __P((frentry_t *fr));
224 static  INLINE void     frpr_ah __P((fr_info_t *));
225 static  INLINE void     frpr_esp __P((fr_info_t *));
226 static  INLINE void     frpr_gre __P((fr_info_t *));
227 static  INLINE void     frpr_udp __P((fr_info_t *));
228 static  INLINE void     frpr_tcp __P((fr_info_t *));
229 static  INLINE void     frpr_icmp __P((fr_info_t *));
230 static  INLINE void     frpr_ipv4hdr __P((fr_info_t *));
231 static  INLINE int      frpr_pullup __P((fr_info_t *, int));
232 static  INLINE void     frpr_short __P((fr_info_t *, int));
233 static  INLINE int      frpr_tcpcommon __P((fr_info_t *));
234 static  INLINE int      frpr_udpcommon __P((fr_info_t *));
235 static  int             fr_updateipid __P((fr_info_t *));
236 #ifdef  IPFILTER_LOOKUP
237 static  int             fr_grpmapinit __P((frentry_t *fr));
238 static  INLINE void     *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *));
239 #endif
240 static  void            frsynclist __P((frentry_t *, void *));
241 static  ipftuneable_t   *fr_findtunebyname __P((const char *));
242 static  ipftuneable_t   *fr_findtunebycookie __P((void *, void **));
243
244
245 /*
246  * bit values for identifying presence of individual IP options
247  * All of these tables should be ordered by increasing key value on the left
248  * hand side to allow for binary searching of the array and include a trailer
249  * with a 0 for the bitmask for linear searches to easily find the end with.
250  */
251 const   struct  optlist ipopts[20] = {
252         { IPOPT_NOP,    0x000001 },
253         { IPOPT_RR,     0x000002 },
254         { IPOPT_ZSU,    0x000004 },
255         { IPOPT_MTUP,   0x000008 },
256         { IPOPT_MTUR,   0x000010 },
257         { IPOPT_ENCODE, 0x000020 },
258         { IPOPT_TS,     0x000040 },
259         { IPOPT_TR,     0x000080 },
260         { IPOPT_SECURITY, 0x000100 },
261         { IPOPT_LSRR,   0x000200 },
262         { IPOPT_E_SEC,  0x000400 },
263         { IPOPT_CIPSO,  0x000800 },
264         { IPOPT_SATID,  0x001000 },
265         { IPOPT_SSRR,   0x002000 },
266         { IPOPT_ADDEXT, 0x004000 },
267         { IPOPT_VISA,   0x008000 },
268         { IPOPT_IMITD,  0x010000 },
269         { IPOPT_EIP,    0x020000 },
270         { IPOPT_FINN,   0x040000 },
271         { 0,            0x000000 }
272 };
273
274 #ifdef USE_INET6
275 struct optlist ip6exthdr[] = {
276         { IPPROTO_HOPOPTS,              0x000001 },
277         { IPPROTO_IPV6,                 0x000002 },
278         { IPPROTO_ROUTING,              0x000004 },
279         { IPPROTO_FRAGMENT,             0x000008 },
280         { IPPROTO_ESP,                  0x000010 },
281         { IPPROTO_AH,                   0x000020 },
282         { IPPROTO_NONE,                 0x000040 },
283         { IPPROTO_DSTOPTS,              0x000080 },
284         { IPPROTO_MOBILITY,             0x000100 },
285         { 0,                            0 }
286 };
287 #endif
288
289 struct optlist tcpopts[] = {
290         { TCPOPT_NOP,                   0x000001 },
291         { TCPOPT_MAXSEG,                0x000002 },
292         { TCPOPT_WINDOW,                0x000004 },
293         { TCPOPT_SACK_PERMITTED,        0x000008 },
294         { TCPOPT_SACK,                  0x000010 },
295         { TCPOPT_TIMESTAMP,             0x000020 },
296         { 0,                            0x000000 }
297 };
298
299 /*
300  * bit values for identifying presence of individual IP security options
301  */
302 const   struct  optlist secopt[8] = {
303         { IPSO_CLASS_RES4,      0x01 },
304         { IPSO_CLASS_TOPS,      0x02 },
305         { IPSO_CLASS_SECR,      0x04 },
306         { IPSO_CLASS_RES3,      0x08 },
307         { IPSO_CLASS_CONF,      0x10 },
308         { IPSO_CLASS_UNCL,      0x20 },
309         { IPSO_CLASS_RES2,      0x40 },
310         { IPSO_CLASS_RES1,      0x80 }
311 };
312
313
314 /*
315  * Table of functions available for use with call rules.
316  */
317 static ipfunc_resolve_t fr_availfuncs[] = {
318 #ifdef  IPFILTER_LOOKUP
319         { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit },
320         { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit },
321 #endif
322         { "", NULL }
323 };
324
325
326 /*
327  * The next section of code is a a collection of small routines that set
328  * fields in the fr_info_t structure passed based on properties of the
329  * current packet.  There are different routines for the same protocol
330  * for each of IPv4 and IPv6.  Adding a new protocol, for which there
331  * will "special" inspection for setup, is now more easily done by adding
332  * a new routine and expanding the frpr_ipinit*() function rather than by
333  * adding more code to a growing switch statement.
334  */
335 #ifdef USE_INET6
336 static  INLINE int      frpr_ah6 __P((fr_info_t *));
337 static  INLINE void     frpr_esp6 __P((fr_info_t *));
338 static  INLINE void     frpr_gre6 __P((fr_info_t *));
339 static  INLINE void     frpr_udp6 __P((fr_info_t *));
340 static  INLINE void     frpr_tcp6 __P((fr_info_t *));
341 static  INLINE void     frpr_icmp6 __P((fr_info_t *));
342 static  INLINE int      frpr_ipv6hdr __P((fr_info_t *));
343 static  INLINE void     frpr_short6 __P((fr_info_t *, int));
344 static  INLINE int      frpr_hopopts6 __P((fr_info_t *));
345 static  INLINE int      frpr_mobility6 __P((fr_info_t *));
346 static  INLINE int      frpr_routing6 __P((fr_info_t *));
347 static  INLINE int      frpr_dstopts6 __P((fr_info_t *));
348 static  INLINE void     frpr_fragment6 __P((fr_info_t *));
349 static  INLINE int      frpr_ipv6exthdr __P((fr_info_t *, int, int));
350
351
352 /* ------------------------------------------------------------------------ */
353 /* Function:    frpr_short6                                                 */
354 /* Returns:     void                                                        */
355 /* Parameters:  fin(I) - pointer to packet information                      */
356 /*                                                                          */
357 /* IPv6 Only                                                                */
358 /* This is function enforces the 'is a packet too short to be legit' rule   */
359 /* for IPv6 and marks the packet with FI_SHORT if so.  See function comment */
360 /* for frpr_short() for more details.                                       */
361 /* ------------------------------------------------------------------------ */
362 static INLINE void frpr_short6(fin, xmin)
363 fr_info_t *fin;
364 int xmin;
365 {
366
367         if (fin->fin_dlen < xmin)
368                 fin->fin_flx |= FI_SHORT;
369 }
370
371
372 /* ------------------------------------------------------------------------ */
373 /* Function:    frpr_ipv6hdr                                                */
374 /* Returns:     int    - 0 = IPv6 packet intact, -1 = packet lost           */
375 /* Parameters:  fin(I) - pointer to packet information                      */
376 /*                                                                          */
377 /* IPv6 Only                                                                */
378 /* Copy values from the IPv6 header into the fr_info_t struct and call the  */
379 /* per-protocol analyzer if it exists.  In validating the packet, a protocol*/
380 /* analyzer may pullup or free the packet itself so we need to be vigiliant */
381 /* of that possibility arising.                                             */
382 /* ------------------------------------------------------------------------ */
383 static INLINE int frpr_ipv6hdr(fin)
384 fr_info_t *fin;
385 {
386         ip6_t *ip6 = (ip6_t *)fin->fin_ip;
387         int p, go = 1, i, hdrcount;
388         fr_ip_t *fi = &fin->fin_fi;
389
390         fin->fin_off = 0;
391
392         fi->fi_tos = 0;
393         fi->fi_optmsk = 0;
394         fi->fi_secmsk = 0;
395         fi->fi_auth = 0;
396
397         p = ip6->ip6_nxt;
398         fi->fi_ttl = ip6->ip6_hlim;
399         fi->fi_src.in6 = ip6->ip6_src;
400         fi->fi_dst.in6 = ip6->ip6_dst;
401         fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff);
402
403         hdrcount = 0;
404         while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) {
405                 switch (p)
406                 {
407                 case IPPROTO_UDP :
408                         frpr_udp6(fin);
409                         go = 0;
410                         break;
411
412                 case IPPROTO_TCP :
413                         frpr_tcp6(fin);
414                         go = 0;
415                         break;
416
417                 case IPPROTO_ICMPV6 :
418                         frpr_icmp6(fin);
419                         go = 0;
420                         break;
421
422                 case IPPROTO_GRE :
423                         frpr_gre6(fin);
424                         go = 0;
425                         break;
426
427                 case IPPROTO_HOPOPTS :
428                         p = frpr_hopopts6(fin);
429                         break;
430
431                 case IPPROTO_MOBILITY :
432                         p = frpr_mobility6(fin);
433                         break;
434
435                 case IPPROTO_DSTOPTS :
436                         p = frpr_dstopts6(fin);
437                         break;
438
439                 case IPPROTO_ROUTING :
440                         p = frpr_routing6(fin);
441                         break;
442
443                 case IPPROTO_AH :
444                         p = frpr_ah6(fin);
445                         break;
446
447                 case IPPROTO_ESP :
448                         frpr_esp6(fin);
449                         go = 0;
450                         break;
451
452                 case IPPROTO_IPV6 :
453                         for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
454                                 if (ip6exthdr[i].ol_val == p) {
455                                         fin->fin_flx |= ip6exthdr[i].ol_bit;
456                                         break;
457                                 }
458                         go = 0;
459                         break;
460
461                 case IPPROTO_NONE :
462                         go = 0;
463                         break;
464
465                 case IPPROTO_FRAGMENT :
466                         frpr_fragment6(fin);
467                         go = 0;
468                         break;
469
470                 default :
471                         go = 0;
472                         break;
473                 }
474                 hdrcount++;
475
476                 /*
477                  * It is important to note that at this point, for the
478                  * extension headers (go != 0), the entire header may not have
479                  * been pulled up when the code gets to this point.  This is
480                  * only done for "go != 0" because the other header handlers
481                  * will all pullup their complete header.  The other indicator
482                  * of an incomplete packet is that this was just an extension
483                  * header.
484                  */
485                 if ((go != 0) && (p != IPPROTO_NONE) &&
486                     (frpr_pullup(fin, 0) == -1)) {
487                         p = IPPROTO_NONE;
488                         go = 0;
489                 }
490         }
491         fi->fi_p = p;
492
493         /*
494          * Some of the above functions, like frpr_esp6(), can call fr_pullup
495          * and destroy whatever packet was here.  The caller of this function
496          * expects us to return -1 if there is a problem with fr_pullup.
497          */
498         if (fin->fin_m == NULL)
499                 return -1;
500
501         return 0;
502 }
503
504
505 /* ------------------------------------------------------------------------ */
506 /* Function:    frpr_ipv6exthdr                                             */
507 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
508 /* Parameters:  fin(I)      - pointer to packet information                 */
509 /*              multiple(I) - flag indicating yes/no if multiple occurances */
510 /*                            of this extension header are allowed.         */
511 /*              proto(I)    - protocol number for this extension header     */
512 /*                                                                          */
513 /* IPv6 Only                                                                */
514 /* ------------------------------------------------------------------------ */
515 static INLINE int frpr_ipv6exthdr(fin, multiple, proto)
516 fr_info_t *fin;
517 int multiple, proto;
518 {
519         struct ip6_ext *hdr;
520         u_short shift;
521         int i;
522
523         fin->fin_flx |= FI_V6EXTHDR;
524
525                                 /* 8 is default length of extension hdr */
526         if ((fin->fin_dlen - 8) < 0) {
527                 fin->fin_flx |= FI_SHORT;
528                 return IPPROTO_NONE;
529         }
530
531         if (frpr_pullup(fin, 8) == -1)
532                 return IPPROTO_NONE;
533
534         hdr = fin->fin_dp;
535         shift = 8 + (hdr->ip6e_len << 3);
536         if (shift > fin->fin_dlen) {    /* Nasty extension header length? */
537                 fin->fin_flx |= FI_BAD;
538                 return IPPROTO_NONE;
539         }
540
541         for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
542                 if (ip6exthdr[i].ol_val == proto) {
543                         /*
544                          * Most IPv6 extension headers are only allowed once.
545                          */
546                         if ((multiple == 0) &&
547                             ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0))
548                                 fin->fin_flx |= FI_BAD;
549                         else
550                                 fin->fin_optmsk |= ip6exthdr[i].ol_bit;
551                         break;
552                 }
553
554         fin->fin_dp = (char *)fin->fin_dp + shift;
555         fin->fin_dlen -= shift;
556
557         return hdr->ip6e_nxt;
558 }
559
560
561 /* ------------------------------------------------------------------------ */
562 /* Function:    frpr_hopopts6                                               */
563 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
564 /* Parameters:  fin(I) - pointer to packet information                      */
565 /*                                                                          */
566 /* IPv6 Only                                                                */
567 /* This is function checks pending hop by hop options extension header      */
568 /* ------------------------------------------------------------------------ */
569 static INLINE int frpr_hopopts6(fin)
570 fr_info_t *fin;
571 {
572         return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
573 }
574
575
576 /* ------------------------------------------------------------------------ */
577 /* Function:    frpr_mobility6                                              */
578 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
579 /* Parameters:  fin(I) - pointer to packet information                      */
580 /*                                                                          */
581 /* IPv6 Only                                                                */
582 /* This is function checks the IPv6 mobility extension header               */
583 /* ------------------------------------------------------------------------ */
584 static INLINE int frpr_mobility6(fin)
585 fr_info_t *fin;
586 {
587         return frpr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
588 }
589
590
591 /* ------------------------------------------------------------------------ */
592 /* Function:    frpr_routing6                                               */
593 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
594 /* Parameters:  fin(I) - pointer to packet information                      */
595 /*                                                                          */
596 /* IPv6 Only                                                                */
597 /* This is function checks pending routing extension header                 */
598 /* ------------------------------------------------------------------------ */
599 static INLINE int frpr_routing6(fin)
600 fr_info_t *fin;
601 {
602         struct ip6_ext *hdr;
603         int shift;
604
605         if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE)
606                 return IPPROTO_NONE;
607
608         hdr = fin->fin_dp;
609         shift = 8 + (hdr->ip6e_len << 3);
610         /*
611          * Nasty extension header length?
612          */
613         if ((shift < sizeof(struct ip6_hdr)) ||
614             ((shift - sizeof(struct ip6_hdr)) & 15)) {
615                 fin->fin_flx |= FI_BAD;
616                 /*
617                  * Compensate for the changes made in frpr_ipv6exthdr()
618                  */
619                 fin->fin_dlen += shift;
620                 fin->fin_dp = (char *)fin->fin_dp - shift;
621                 return IPPROTO_NONE;
622         }
623
624         return hdr->ip6e_nxt;
625 }
626
627
628 /* ------------------------------------------------------------------------ */
629 /* Function:    frpr_fragment6                                              */
630 /* Returns:     void                                                        */
631 /* Parameters:  fin(I) - pointer to packet information                      */
632 /*                                                                          */
633 /* IPv6 Only                                                                */
634 /* Examine the IPv6 fragment header and extract fragment offset information.*/
635 /*                                                                          */
636 /* We don't know where the transport layer header (or whatever is next is), */
637 /* as it could be behind destination options (amongst others).  Because     */
638 /* there is no fragment cache, there is no knowledge about whether or not an*/
639 /* upper layer header has been seen (or where it ends) and thus we are not  */
640 /* able to continue processing beyond this header with any confidence.      */
641 /* ------------------------------------------------------------------------ */
642 static INLINE void frpr_fragment6(fin)
643 fr_info_t *fin;
644 {
645         struct ip6_frag *frag;
646
647         fin->fin_flx |= FI_FRAG;
648
649         if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE)
650                 return;
651
652         if (frpr_pullup(fin, sizeof(*frag)) == -1)
653                 return;
654
655         frag = fin->fin_dp;
656         /*
657          * Fragment but no fragmentation info set?  Bad packet...
658          */
659         if (frag->ip6f_offlg == 0) {
660                 fin->fin_flx |= FI_BAD;
661                 return;
662         }
663
664         fin->fin_off = frag->ip6f_offlg & IP6F_OFF_MASK;
665         fin->fin_off <<= 3;
666         if (fin->fin_off != 0)
667                 fin->fin_flx |= FI_FRAGBODY;
668
669         fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag);
670         fin->fin_dlen -= sizeof(*frag);
671 }
672
673
674 /* ------------------------------------------------------------------------ */
675 /* Function:    frpr_dstopts6                                               */
676 /* Returns:     int    - value of the next header or IPPROTO_NONE if error  */
677 /* Parameters:  fin(I) - pointer to packet information                      */
678 /*              nextheader(I) - stores next header value                    */
679 /*                                                                          */
680 /* IPv6 Only                                                                */
681 /* This is function checks pending destination options extension header     */
682 /* ------------------------------------------------------------------------ */
683 static INLINE int frpr_dstopts6(fin)
684 fr_info_t *fin;
685 {
686         return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS);
687 }
688
689
690 /* ------------------------------------------------------------------------ */
691 /* Function:    frpr_icmp6                                                  */
692 /* Returns:     void                                                        */
693 /* Parameters:  fin(I) - pointer to packet information                      */
694 /*                                                                          */
695 /* IPv6 Only                                                                */
696 /* This routine is mainly concerned with determining the minimum valid size */
697 /* for an ICMPv6 packet.                                                    */
698 /* ------------------------------------------------------------------------ */
699 static INLINE void frpr_icmp6(fin)
700 fr_info_t *fin;
701 {
702         int minicmpsz = sizeof(struct icmp6_hdr);
703         struct icmp6_hdr *icmp6;
704
705         if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t)) == -1)
706                 return;
707
708         if (fin->fin_dlen > 1) {
709                 icmp6 = fin->fin_dp;
710
711                 fin->fin_data[0] = *(u_short *)icmp6;
712
713                 switch (icmp6->icmp6_type)
714                 {
715                 case ICMP6_ECHO_REPLY :
716                 case ICMP6_ECHO_REQUEST :
717                         minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
718                         break;
719                 case ICMP6_DST_UNREACH :
720                 case ICMP6_PACKET_TOO_BIG :
721                 case ICMP6_TIME_EXCEEDED :
722                 case ICMP6_PARAM_PROB :
723                         if ((fin->fin_m != NULL) &&
724                             (M_LEN(fin->fin_m) < fin->fin_plen)) {
725                                 if (fr_coalesce(fin) != 1)
726                                         return;
727                         }
728                         fin->fin_flx |= FI_ICMPERR;
729                         minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
730                         break;
731                 default :
732                         break;
733                 }
734         }
735
736         frpr_short6(fin, minicmpsz);
737 }
738
739
740 /* ------------------------------------------------------------------------ */
741 /* Function:    frpr_udp6                                                   */
742 /* Returns:     void                                                        */
743 /* Parameters:  fin(I) - pointer to packet information                      */
744 /*                                                                          */
745 /* IPv6 Only                                                                */
746 /* Analyse the packet for IPv6/UDP properties.                              */
747 /* Is not expected to be called for fragmented packets.                     */
748 /* ------------------------------------------------------------------------ */
749 static INLINE void frpr_udp6(fin)
750 fr_info_t *fin;
751 {
752
753         frpr_short6(fin, sizeof(struct udphdr));
754
755         if (frpr_udpcommon(fin) == 0)
756                 fr_checkv6sum(fin);
757 }
758
759
760 /* ------------------------------------------------------------------------ */
761 /* Function:    frpr_tcp6                                                   */
762 /* Returns:     void                                                        */
763 /* Parameters:  fin(I) - pointer to packet information                      */
764 /*                                                                          */
765 /* IPv6 Only                                                                */
766 /* Analyse the packet for IPv6/TCP properties.                              */
767 /* Is not expected to be called for fragmented packets.                     */
768 /* ------------------------------------------------------------------------ */
769 static INLINE void frpr_tcp6(fin)
770 fr_info_t *fin;
771 {
772
773         frpr_short6(fin, sizeof(struct tcphdr));
774
775         if (frpr_tcpcommon(fin) == 0)
776                 fr_checkv6sum(fin);
777 }
778
779
780 /* ------------------------------------------------------------------------ */
781 /* Function:    frpr_esp6                                                   */
782 /* Returns:     void                                                        */
783 /* Parameters:  fin(I) - pointer to packet information                      */
784 /*                                                                          */
785 /* IPv6 Only                                                                */
786 /* Analyse the packet for ESP properties.                                   */
787 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
788 /* even though the newer ESP packets must also have a sequence number that  */
789 /* is 32bits as well, it is not possible(?) to determine the version from a */
790 /* simple packet header.                                                    */
791 /* ------------------------------------------------------------------------ */
792 static INLINE void frpr_esp6(fin)
793 fr_info_t *fin;
794 {
795
796         frpr_short6(fin, sizeof(grehdr_t));
797
798         (void) frpr_pullup(fin, 8);
799 }
800
801
802 /* ------------------------------------------------------------------------ */
803 /* Function:    frpr_ah6                                                    */
804 /* Returns:     void                                                        */
805 /* Parameters:  fin(I) - pointer to packet information                      */
806 /*                                                                          */
807 /* IPv6 Only                                                                */
808 /* Analyse the packet for AH properties.                                    */
809 /* The minimum length is taken to be the combination of all fields in the   */
810 /* header being present and no authentication data (null algorithm used.)   */
811 /* ------------------------------------------------------------------------ */
812 static INLINE int frpr_ah6(fin)
813 fr_info_t *fin;
814 {
815         authhdr_t *ah;
816
817         frpr_short6(fin, 12);
818
819         if (frpr_pullup(fin, sizeof(*ah)) == -1)
820                 return IPPROTO_NONE;
821
822         ah = (authhdr_t *)fin->fin_dp;
823         return ah->ah_next;
824 }
825
826
827 /* ------------------------------------------------------------------------ */
828 /* Function:    frpr_gre6                                                   */
829 /* Returns:     void                                                        */
830 /* Parameters:  fin(I) - pointer to packet information                      */
831 /*                                                                          */
832 /* Analyse the packet for GRE properties.                                   */
833 /* ------------------------------------------------------------------------ */
834 static INLINE void frpr_gre6(fin)
835 fr_info_t *fin;
836 {
837         grehdr_t *gre;
838
839         frpr_short6(fin, sizeof(grehdr_t));
840
841         if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
842                 return;
843
844         gre = fin->fin_dp;
845         if (GRE_REV(gre->gr_flags) == 1)
846                 fin->fin_data[0] = gre->gr_call;
847 }
848 #endif  /* USE_INET6 */
849
850
851 /* ------------------------------------------------------------------------ */
852 /* Function:    frpr_pullup                                                 */
853 /* Returns:     int     - 0 == pullup succeeded, -1 == failure              */
854 /* Parameters:  fin(I)  - pointer to packet information                     */
855 /*              plen(I) - length (excluding L3 header) to pullup            */
856 /*                                                                          */
857 /* Short inline function to cut down on code duplication to perform a call  */
858 /* to fr_pullup to ensure there is the required amount of data,             */
859 /* consecutively in the packet buffer.                                      */
860 /* ------------------------------------------------------------------------ */
861 static INLINE int frpr_pullup(fin, plen)
862 fr_info_t *fin;
863 int plen;
864 {
865 #if defined(_KERNEL)
866         if (fin->fin_m != NULL) {
867                 if (fin->fin_dp != NULL)
868                         plen += (char *)fin->fin_dp -
869                                 ((char *)fin->fin_ip + fin->fin_hlen);
870                 plen += fin->fin_hlen;
871                 if (M_LEN(fin->fin_m) < plen) {
872                         if (fr_pullup(fin->fin_m, fin, plen) == NULL)
873                                 return -1;
874                 }
875         }
876 #endif
877         return 0;
878 }
879
880
881 /* ------------------------------------------------------------------------ */
882 /* Function:    frpr_short                                                  */
883 /* Returns:     void                                                        */
884 /* Parameters:  fin(I)  - pointer to packet information                     */
885 /*              xmin(I) - minimum header size                               */
886 /*                                                                          */
887 /* Check if a packet is "short" as defined by xmin.  The rule we are        */
888 /* applying here is that the packet must not be fragmented within the layer */
889 /* 4 header.  That is, it must not be a fragment that has its offset set to */
890 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the    */
891 /* entire layer 4 header must be present (min).                             */
892 /* ------------------------------------------------------------------------ */
893 static INLINE void frpr_short(fin, xmin)
894 fr_info_t *fin;
895 int xmin;
896 {
897
898         if (fin->fin_off == 0) {
899                 if (fin->fin_dlen < xmin)
900                         fin->fin_flx |= FI_SHORT;
901         } else if (fin->fin_off < xmin) {
902                 fin->fin_flx |= FI_SHORT;
903         }
904 }
905
906
907 /* ------------------------------------------------------------------------ */
908 /* Function:    frpr_icmp                                                   */
909 /* Returns:     void                                                        */
910 /* Parameters:  fin(I) - pointer to packet information                      */
911 /*                                                                          */
912 /* IPv4 Only                                                                */
913 /* Do a sanity check on the packet for ICMP (v4).  In nearly all cases,     */
914 /* except extrememly bad packets, both type and code will be present.       */
915 /* The expected minimum size of an ICMP packet is very much dependent on    */
916 /* the type of it.                                                          */
917 /*                                                                          */
918 /* XXX - other ICMP sanity checks?                                          */
919 /* ------------------------------------------------------------------------ */
920 static INLINE void frpr_icmp(fin)
921 fr_info_t *fin;
922 {
923         int minicmpsz = sizeof(struct icmp);
924         icmphdr_t *icmp;
925         ip_t *oip;
926
927         if (fin->fin_off != 0) {
928                 frpr_short(fin, ICMPERR_ICMPHLEN);
929                 return;
930         }
931
932         if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
933                 return;
934
935         if (fin->fin_dlen > 1) {
936                 icmp = fin->fin_dp;
937
938                 fin->fin_data[0] = *(u_short *)icmp;
939
940                 switch (icmp->icmp_type)
941                 {
942                 case ICMP_ECHOREPLY :
943                 case ICMP_ECHO :
944                 /* Router discovery messaes - RFC 1256 */
945                 case ICMP_ROUTERADVERT :
946                 case ICMP_ROUTERSOLICIT :
947                         minicmpsz = ICMP_MINLEN;
948                         break;
949                 /*
950                  * type(1) + code(1) + cksum(2) + id(2) seq(2) +
951                  * 3 * timestamp(3 * 4)
952                  */
953                 case ICMP_TSTAMP :
954                 case ICMP_TSTAMPREPLY :
955                         minicmpsz = 20;
956                         break;
957                 /*
958                  * type(1) + code(1) + cksum(2) + id(2) seq(2) +
959                  * mask(4)
960                  */
961                 case ICMP_MASKREQ :
962                 case ICMP_MASKREPLY :
963                         minicmpsz = 12;
964                         break;
965                 /*
966                  * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
967                  */
968                 case ICMP_UNREACH :
969 #ifdef icmp_nextmtu
970                         if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
971                                 if (icmp->icmp_nextmtu < fr_icmpminfragmtu)
972                                         fin->fin_flx |= FI_BAD;
973                         }
974 #endif
975                 case ICMP_SOURCEQUENCH :
976                 case ICMP_REDIRECT :
977                 case ICMP_TIMXCEED :
978                 case ICMP_PARAMPROB :
979                         fin->fin_flx |= FI_ICMPERR;
980                         if (fr_coalesce(fin) != 1)
981                                 return;
982                         /*
983                          * ICMP error packets should not be generated for IP
984                          * packets that are a fragment that isn't the first
985                          * fragment.
986                          */
987                         oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
988                         if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
989                                 fin->fin_flx |= FI_BAD;
990                         break;
991                 default :
992                         break;
993                 }
994
995                 if (fin->fin_dlen >= 6)                         /* ID field */
996                         fin->fin_data[1] = icmp->icmp_id;
997         }
998
999         frpr_short(fin, minicmpsz);
1000
1001         fr_checkv4sum(fin);
1002 }
1003
1004
1005 /* ------------------------------------------------------------------------ */
1006 /* Function:    frpr_tcpcommon                                              */
1007 /* Returns:     int    - 0 = header ok, 1 = bad packet, -1 = buffer error   */
1008 /* Parameters:  fin(I) - pointer to packet information                      */
1009 /*                                                                          */
1010 /* TCP header sanity checking.  Look for bad combinations of TCP flags,     */
1011 /* and make some checks with how they interact with other fields.           */
1012 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is     */
1013 /* valid and mark the packet as bad if not.                                 */
1014 /* ------------------------------------------------------------------------ */
1015 static INLINE int frpr_tcpcommon(fin)
1016 fr_info_t *fin;
1017 {
1018         int flags, tlen;
1019         tcphdr_t *tcp;
1020
1021         fin->fin_flx |= FI_TCPUDP;
1022         if (fin->fin_off != 0)
1023                 return 0;
1024
1025         if (frpr_pullup(fin, sizeof(*tcp)) == -1)
1026                 return -1;
1027         tcp = fin->fin_dp;
1028
1029         if (fin->fin_dlen > 3) {
1030                 fin->fin_sport = ntohs(tcp->th_sport);
1031                 fin->fin_dport = ntohs(tcp->th_dport);
1032         }
1033
1034         if ((fin->fin_flx & FI_SHORT) != 0)
1035                 return 1;
1036
1037         /*
1038          * Use of the TCP data offset *must* result in a value that is at
1039          * least the same size as the TCP header.
1040          */
1041         tlen = TCP_OFF(tcp) << 2;
1042         if (tlen < sizeof(tcphdr_t)) {
1043                 fin->fin_flx |= FI_BAD;
1044                 return 1;
1045         }
1046
1047         flags = tcp->th_flags;
1048         fin->fin_tcpf = tcp->th_flags;
1049
1050         /*
1051          * If the urgent flag is set, then the urgent pointer must
1052          * also be set and vice versa.  Good TCP packets do not have
1053          * just one of these set.
1054          */
1055         if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) {
1056                 fin->fin_flx |= FI_BAD;
1057         } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) {
1058                 /* Ignore this case, it shows up in "real" traffic with */
1059                 /* bogus values in the urgent pointer field. */
1060                 ;
1061         } else if (((flags & (TH_SYN|TH_FIN)) != 0) &&
1062                    ((flags & (TH_RST|TH_ACK)) == TH_RST)) {
1063                 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */
1064                 fin->fin_flx |= FI_BAD;
1065         } else if (!(flags & TH_ACK)) {
1066                 /*
1067                  * If the ack bit isn't set, then either the SYN or
1068                  * RST bit must be set.  If the SYN bit is set, then
1069                  * we expect the ACK field to be 0.  If the ACK is
1070                  * not set and if URG, PSH or FIN are set, consdier
1071                  * that to indicate a bad TCP packet.
1072                  */
1073                 if ((flags == TH_SYN) && (tcp->th_ack != 0)) {
1074                         /*
1075                          * Cisco PIX sets the ACK field to a random value.
1076                          * In light of this, do not set FI_BAD until a patch
1077                          * is available from Cisco to ensure that
1078                          * interoperability between existing systems is
1079                          * achieved.
1080                          */
1081                         /*fin->fin_flx |= FI_BAD*/;
1082                 } else if (!(flags & (TH_RST|TH_SYN))) {
1083                         fin->fin_flx |= FI_BAD;
1084                 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) {
1085                         fin->fin_flx |= FI_BAD;
1086                 }
1087         }
1088
1089         /*
1090          * At this point, it's not exactly clear what is to be gained by
1091          * marking up which TCP options are and are not present.  The one we
1092          * are most interested in is the TCP window scale.  This is only in
1093          * a SYN packet [RFC1323] so we don't need this here...?
1094          * Now if we were to analyse the header for passive fingerprinting,
1095          * then that might add some weight to adding this...
1096          */
1097         if (tlen == sizeof(tcphdr_t))
1098                 return 0;
1099
1100         if (frpr_pullup(fin, tlen) == -1)
1101                 return -1;
1102
1103 #if 0
1104         ip = fin->fin_ip;
1105         s = (u_char *)(tcp + 1);
1106         off = IP_HL(ip) << 2;
1107 # ifdef _KERNEL
1108         if (fin->fin_mp != NULL) {
1109                 mb_t *m = *fin->fin_mp;
1110
1111                 if (off + tlen > M_LEN(m))
1112                         return;
1113         }
1114 # endif
1115         for (tlen -= (int)sizeof(*tcp); tlen > 0; ) {
1116                 opt = *s;
1117                 if (opt == '\0')
1118                         break;
1119                 else if (opt == TCPOPT_NOP)
1120                         ol = 1;
1121                 else {
1122                         if (tlen < 2)
1123                                 break;
1124                         ol = (int)*(s + 1);
1125                         if (ol < 2 || ol > tlen)
1126                                 break;
1127                 }
1128
1129                 for (i = 9, mv = 4; mv >= 0; ) {
1130                         op = ipopts + i;
1131                         if (opt == (u_char)op->ol_val) {
1132                                 optmsk |= op->ol_bit;
1133                                 break;
1134                         }
1135                 }
1136                 tlen -= ol;
1137                 s += ol;
1138         }
1139 #endif /* 0 */
1140
1141         return 0;
1142 }
1143
1144
1145
1146 /* ------------------------------------------------------------------------ */
1147 /* Function:    frpr_udpcommon                                              */
1148 /* Returns:     int    - 0 = header ok, 1 = bad packet                      */
1149 /* Parameters:  fin(I) - pointer to packet information                      */
1150 /*                                                                          */
1151 /* Extract the UDP source and destination ports, if present.  If compiled   */
1152 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid.          */
1153 /* ------------------------------------------------------------------------ */
1154 static INLINE int frpr_udpcommon(fin)
1155 fr_info_t *fin;
1156 {
1157         udphdr_t *udp;
1158
1159         fin->fin_flx |= FI_TCPUDP;
1160
1161         if (!fin->fin_off && (fin->fin_dlen > 3)) {
1162                 if (frpr_pullup(fin, sizeof(*udp)) == -1) {
1163                         fin->fin_flx |= FI_SHORT;
1164                         return 1;
1165                 }
1166
1167                 udp = fin->fin_dp;
1168
1169                 fin->fin_sport = ntohs(udp->uh_sport);
1170                 fin->fin_dport = ntohs(udp->uh_dport);
1171         }
1172
1173         return 0;
1174 }
1175
1176
1177 /* ------------------------------------------------------------------------ */
1178 /* Function:    frpr_tcp                                                    */
1179 /* Returns:     void                                                        */
1180 /* Parameters:  fin(I) - pointer to packet information                      */
1181 /*                                                                          */
1182 /* IPv4 Only                                                                */
1183 /* Analyse the packet for IPv4/TCP properties.                              */
1184 /* ------------------------------------------------------------------------ */
1185 static INLINE void frpr_tcp(fin)
1186 fr_info_t *fin;
1187 {
1188
1189         frpr_short(fin, sizeof(tcphdr_t));
1190
1191         if (frpr_tcpcommon(fin) == 0)
1192                 fr_checkv4sum(fin);
1193 }
1194
1195
1196 /* ------------------------------------------------------------------------ */
1197 /* Function:    frpr_udp                                                    */
1198 /* Returns:     void                                                        */
1199 /* Parameters:  fin(I) - pointer to packet information                      */
1200 /*                                                                          */
1201 /* IPv4 Only                                                                */
1202 /* Analyse the packet for IPv4/UDP properties.                              */
1203 /* ------------------------------------------------------------------------ */
1204 static INLINE void frpr_udp(fin)
1205 fr_info_t *fin;
1206 {
1207
1208         frpr_short(fin, sizeof(udphdr_t));
1209
1210         if (frpr_udpcommon(fin) == 0)
1211                 fr_checkv4sum(fin);
1212 }
1213
1214
1215 /* ------------------------------------------------------------------------ */
1216 /* Function:    frpr_esp                                                    */
1217 /* Returns:     void                                                        */
1218 /* Parameters:  fin(I) - pointer to packet information                      */
1219 /*                                                                          */
1220 /* Analyse the packet for ESP properties.                                   */
1221 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits)  */
1222 /* even though the newer ESP packets must also have a sequence number that  */
1223 /* is 32bits as well, it is not possible(?) to determine the version from a */
1224 /* simple packet header.                                                    */
1225 /* ------------------------------------------------------------------------ */
1226 static INLINE void frpr_esp(fin)
1227 fr_info_t *fin;
1228 {
1229
1230         if (fin->fin_off == 0) {
1231                 frpr_short(fin, 8);
1232                 (void) frpr_pullup(fin, 8);
1233         }
1234
1235 }
1236
1237
1238 /* ------------------------------------------------------------------------ */
1239 /* Function:    frpr_ah                                                     */
1240 /* Returns:     void                                                        */
1241 /* Parameters:  fin(I) - pointer to packet information                      */
1242 /*                                                                          */
1243 /* Analyse the packet for AH properties.                                    */
1244 /* The minimum length is taken to be the combination of all fields in the   */
1245 /* header being present and no authentication data (null algorithm used.)   */
1246 /* ------------------------------------------------------------------------ */
1247 static INLINE void frpr_ah(fin)
1248 fr_info_t *fin;
1249 {
1250         authhdr_t *ah;
1251         int len;
1252
1253         frpr_short(fin, sizeof(*ah));
1254
1255         if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0))
1256                 return;
1257
1258         if (frpr_pullup(fin, sizeof(*ah)) == -1)
1259                 return;
1260
1261         ah = (authhdr_t *)fin->fin_dp;
1262
1263         len = (ah->ah_plen + 2) << 2;
1264         frpr_short(fin, len);
1265 }
1266
1267
1268 /* ------------------------------------------------------------------------ */
1269 /* Function:    frpr_gre                                                    */
1270 /* Returns:     void                                                        */
1271 /* Parameters:  fin(I) - pointer to packet information                      */
1272 /*                                                                          */
1273 /* Analyse the packet for GRE properties.                                   */
1274 /* ------------------------------------------------------------------------ */
1275 static INLINE void frpr_gre(fin)
1276 fr_info_t *fin;
1277 {
1278         grehdr_t *gre;
1279
1280         frpr_short(fin, sizeof(*gre));
1281
1282         if (fin->fin_off != 0)
1283                 return;
1284
1285         if (frpr_pullup(fin, sizeof(*gre)) == -1)
1286                 return;
1287
1288         if (fin->fin_off == 0) {
1289                 gre = fin->fin_dp;
1290                 if (GRE_REV(gre->gr_flags) == 1)
1291                         fin->fin_data[0] = gre->gr_call;
1292         }
1293 }
1294
1295
1296 /* ------------------------------------------------------------------------ */
1297 /* Function:    frpr_ipv4hdr                                                */
1298 /* Returns:     void                                                        */
1299 /* Parameters:  fin(I) - pointer to packet information                      */
1300 /*                                                                          */
1301 /* IPv4 Only                                                                */
1302 /* Analyze the IPv4 header and set fields in the fr_info_t structure.       */
1303 /* Check all options present and flag their presence if any exist.          */
1304 /* ------------------------------------------------------------------------ */
1305 static INLINE void frpr_ipv4hdr(fin)
1306 fr_info_t *fin;
1307 {
1308         u_short optmsk = 0, secmsk = 0, auth = 0;
1309         int hlen, ol, mv, p, i;
1310         const struct optlist *op;
1311         u_char *s, opt;
1312         u_short off;
1313         fr_ip_t *fi;
1314         ip_t *ip;
1315
1316         fi = &fin->fin_fi;
1317         hlen = fin->fin_hlen;
1318
1319         ip = fin->fin_ip;
1320         p = ip->ip_p;
1321         fi->fi_p = p;
1322         fi->fi_tos = ip->ip_tos;
1323         fin->fin_id = ip->ip_id;
1324         off = ip->ip_off;
1325
1326         /* Get both TTL and protocol */
1327         fi->fi_p = ip->ip_p;
1328         fi->fi_ttl = ip->ip_ttl;
1329 #if 0
1330         (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
1331 #endif
1332
1333         /* Zero out bits not used in IPv6 address */
1334         fi->fi_src.i6[1] = 0;
1335         fi->fi_src.i6[2] = 0;
1336         fi->fi_src.i6[3] = 0;
1337         fi->fi_dst.i6[1] = 0;
1338         fi->fi_dst.i6[2] = 0;
1339         fi->fi_dst.i6[3] = 0;
1340
1341         fi->fi_saddr = ip->ip_src.s_addr;
1342         fi->fi_daddr = ip->ip_dst.s_addr;
1343
1344         /*
1345          * set packet attribute flags based on the offset and
1346          * calculate the byte offset that it represents.
1347          */
1348         off &= IP_MF|IP_OFFMASK;
1349         if (off != 0) {
1350                 fi->fi_flx |= FI_FRAG;
1351                 off &= IP_OFFMASK;
1352                 if (off != 0) {
1353                         fin->fin_flx |= FI_FRAGBODY;
1354                         off <<= 3;
1355                         if ((off + fin->fin_dlen > 65535) || 
1356                             (fin->fin_dlen == 0) || (fin->fin_dlen & 7)) {
1357                                 /* 
1358                                  * The length of the packet, starting at its
1359                                  * offset cannot exceed 65535 (0xffff) as the 
1360                                  * length of an IP packet is only 16 bits.
1361                                  *
1362                                  * Any fragment that isn't the last fragment
1363                                  * must have a length greater than 0 and it
1364                                  * must be an even multiple of 8.
1365                                  */
1366                                 fi->fi_flx |= FI_BAD;
1367                         }
1368                 }
1369         }
1370         fin->fin_off = off;
1371
1372         /*
1373          * Call per-protocol setup and checking
1374          */
1375         switch (p)
1376         {
1377         case IPPROTO_UDP :
1378                 frpr_udp(fin);
1379                 break;
1380         case IPPROTO_TCP :
1381                 frpr_tcp(fin);
1382                 break;
1383         case IPPROTO_ICMP :
1384                 frpr_icmp(fin);
1385                 break;
1386         case IPPROTO_AH :
1387                 frpr_ah(fin);
1388                 break;
1389         case IPPROTO_ESP :
1390                 frpr_esp(fin);
1391                 break;
1392         case IPPROTO_GRE :
1393                 frpr_gre(fin);
1394                 break;
1395         }
1396
1397         ip = fin->fin_ip;
1398         if (ip == NULL)
1399                 return;
1400
1401         /*
1402          * If it is a standard IP header (no options), set the flag fields
1403          * which relate to options to 0.
1404          */
1405         if (hlen == sizeof(*ip)) {
1406                 fi->fi_optmsk = 0;
1407                 fi->fi_secmsk = 0;
1408                 fi->fi_auth = 0;
1409                 return;
1410         }
1411
1412         /*
1413          * So the IP header has some IP options attached.  Walk the entire
1414          * list of options present with this packet and set flags to indicate
1415          * which ones are here and which ones are not.  For the somewhat out
1416          * of date and obscure security classification options, set a flag to
1417          * represent which classification is present.
1418          */
1419         fi->fi_flx |= FI_OPTIONS;
1420
1421         for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
1422                 opt = *s;
1423                 if (opt == '\0')
1424                         break;
1425                 else if (opt == IPOPT_NOP)
1426                         ol = 1;
1427                 else {
1428                         if (hlen < 2)
1429                                 break;
1430                         ol = (int)*(s + 1);
1431                         if (ol < 2 || ol > hlen)
1432                                 break;
1433                 }
1434                 for (i = 9, mv = 4; mv >= 0; ) {
1435                         op = ipopts + i;
1436                         if ((opt == (u_char)op->ol_val) && (ol > 4)) {
1437                                 optmsk |= op->ol_bit;
1438                                 if (opt == IPOPT_SECURITY) {
1439                                         const struct optlist *sp;
1440                                         u_char  sec;
1441                                         int j, m;
1442
1443                                         sec = *(s + 2); /* classification */
1444                                         for (j = 3, m = 2; m >= 0; ) {
1445                                                 sp = secopt + j;
1446                                                 if (sec == sp->ol_val) {
1447                                                         secmsk |= sp->ol_bit;
1448                                                         auth = *(s + 3);
1449                                                         auth *= 256;
1450                                                         auth += *(s + 4);
1451                                                         break;
1452                                                 }
1453                                                 if (sec < sp->ol_val)
1454                                                         j -= m;
1455                                                 else
1456                                                         j += m;
1457                                                 m--;
1458                                         }
1459                                 }
1460                                 break;
1461                         }
1462                         if (opt < op->ol_val)
1463                                 i -= mv;
1464                         else
1465                                 i += mv;
1466                         mv--;
1467                 }
1468                 hlen -= ol;
1469                 s += ol;
1470         }
1471
1472         /*
1473          *
1474          */
1475         if (auth && !(auth & 0x0100))
1476                 auth &= 0xff00;
1477         fi->fi_optmsk = optmsk;
1478         fi->fi_secmsk = secmsk;
1479         fi->fi_auth = auth;
1480 }
1481
1482
1483 /* ------------------------------------------------------------------------ */
1484 /* Function:    fr_makefrip                                                 */
1485 /* Returns:     void                                                        */
1486 /* Parameters:  hlen(I) - length of IP packet header                        */
1487 /*              ip(I)   - pointer to the IP header                          */
1488 /*              fin(IO) - pointer to packet information                     */
1489 /*                                                                          */
1490 /* Compact the IP header into a structure which contains just the info.     */
1491 /* which is useful for comparing IP headers with and store this information */
1492 /* in the fr_info_t structure pointer to by fin.  At present, it is assumed */
1493 /* this function will be called with either an IPv4 or IPv6 packet.         */
1494 /* ------------------------------------------------------------------------ */
1495 int     fr_makefrip(hlen, ip, fin)
1496 int hlen;
1497 ip_t *ip;
1498 fr_info_t *fin;
1499 {
1500         int v;
1501
1502         fin->fin_nat = NULL;
1503         fin->fin_state = NULL;
1504         fin->fin_depth = 0;
1505         fin->fin_hlen = (u_short)hlen;
1506         fin->fin_ip = ip;
1507         fin->fin_rule = 0xffffffff;
1508         fin->fin_group[0] = -1;
1509         fin->fin_group[1] = '\0';
1510         fin->fin_dlen = fin->fin_plen - hlen;
1511         fin->fin_dp = (char *)ip + hlen;
1512
1513         v = fin->fin_v;
1514         if (v == 4)
1515                 frpr_ipv4hdr(fin);
1516 #ifdef  USE_INET6
1517         else if (v == 6) {
1518                 if (frpr_ipv6hdr(fin) == -1)
1519                         return -1;
1520         }
1521 #endif
1522         if (fin->fin_ip == NULL)
1523                 return -1;
1524         return 0;
1525 }
1526
1527
1528 /* ------------------------------------------------------------------------ */
1529 /* Function:    fr_portcheck                                                */
1530 /* Returns:     int - 1 == port matched, 0 == port match failed             */
1531 /* Parameters:  frp(I) - pointer to port check `expression'                 */
1532 /*              pop(I) - pointer to port number to evaluate                 */
1533 /*                                                                          */
1534 /* Perform a comparison of a port number against some other(s), using a     */
1535 /* structure with compare information stored in it.                         */
1536 /* ------------------------------------------------------------------------ */
1537 static INLINE int fr_portcheck(frp, pop)
1538 frpcmp_t *frp;
1539 u_short *pop;
1540 {
1541         u_short tup, po;
1542         int err = 1;
1543
1544         tup = *pop;
1545         po = frp->frp_port;
1546
1547         /*
1548          * Do opposite test to that required and continue if that succeeds.
1549          */
1550         switch (frp->frp_cmp)
1551         {
1552         case FR_EQUAL :
1553                 if (tup != po) /* EQUAL */
1554                         err = 0;
1555                 break;
1556         case FR_NEQUAL :
1557                 if (tup == po) /* NOTEQUAL */
1558                         err = 0;
1559                 break;
1560         case FR_LESST :
1561                 if (tup >= po) /* LESSTHAN */
1562                         err = 0;
1563                 break;
1564         case FR_GREATERT :
1565                 if (tup <= po) /* GREATERTHAN */
1566                         err = 0;
1567                 break;
1568         case FR_LESSTE :
1569                 if (tup > po) /* LT or EQ */
1570                         err = 0;
1571                 break;
1572         case FR_GREATERTE :
1573                 if (tup < po) /* GT or EQ */
1574                         err = 0;
1575                 break;
1576         case FR_OUTRANGE :
1577                 if (tup >= po && tup <= frp->frp_top) /* Out of range */
1578                         err = 0;
1579                 break;
1580         case FR_INRANGE :
1581                 if (tup <= po || tup >= frp->frp_top) /* In range */
1582                         err = 0;
1583                 break;
1584         case FR_INCRANGE :
1585                 if (tup < po || tup > frp->frp_top) /* Inclusive range */
1586                         err = 0;
1587                 break;
1588         default :
1589                 break;
1590         }
1591         return err;
1592 }
1593
1594
1595 /* ------------------------------------------------------------------------ */
1596 /* Function:    fr_tcpudpchk                                                */
1597 /* Returns:     int - 1 == protocol matched, 0 == check failed              */
1598 /* Parameters:  fin(I) - pointer to packet information                      */
1599 /*              ft(I)  - pointer to structure with comparison data          */
1600 /*                                                                          */
1601 /* Compares the current pcket (assuming it is TCP/UDP) information with a   */
1602 /* structure containing information that we want to match against.          */
1603 /* ------------------------------------------------------------------------ */
1604 int fr_tcpudpchk(fin, ft)
1605 fr_info_t *fin;
1606 frtuc_t *ft;
1607 {
1608         int err = 1;
1609
1610         /*
1611          * Both ports should *always* be in the first fragment.
1612          * So far, I cannot find any cases where they can not be.
1613          *
1614          * compare destination ports
1615          */
1616         if (ft->ftu_dcmp)
1617                 err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport);
1618
1619         /*
1620          * compare source ports
1621          */
1622         if (err && ft->ftu_scmp)
1623                 err = fr_portcheck(&ft->ftu_src, &fin->fin_sport);
1624
1625         /*
1626          * If we don't have all the TCP/UDP header, then how can we
1627          * expect to do any sort of match on it ?  If we were looking for
1628          * TCP flags, then NO match.  If not, then match (which should
1629          * satisfy the "short" class too).
1630          */
1631         if (err && (fin->fin_p == IPPROTO_TCP)) {
1632                 if (fin->fin_flx & FI_SHORT)
1633                         return !(ft->ftu_tcpf | ft->ftu_tcpfm);
1634                 /*
1635                  * Match the flags ?  If not, abort this match.
1636                  */
1637                 if (ft->ftu_tcpfm &&
1638                     ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) {
1639                         FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
1640                                  ft->ftu_tcpfm, ft->ftu_tcpf));
1641                         err = 0;
1642                 }
1643         }
1644         return err;
1645 }
1646
1647
1648
1649 /* ------------------------------------------------------------------------ */
1650 /* Function:    fr_ipfcheck                                                 */
1651 /* Returns:     int - 0 == match, 1 == no match                             */
1652 /* Parameters:  fin(I)     - pointer to packet information                  */
1653 /*              fr(I)      - pointer to filter rule                         */
1654 /*              portcmp(I) - flag indicating whether to attempt matching on */
1655 /*                           TCP/UDP port data.                             */
1656 /*                                                                          */
1657 /* Check to see if a packet matches an IPFilter rule.  Checks of addresses, */
1658 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
1659 /* this function.                                                           */
1660 /* ------------------------------------------------------------------------ */
1661 static INLINE int fr_ipfcheck(fin, fr, portcmp)
1662 fr_info_t *fin;
1663 frentry_t *fr;
1664 int portcmp;
1665 {
1666         u_32_t  *ld, *lm, *lip;
1667         fripf_t *fri;
1668         fr_ip_t *fi;
1669         int i;
1670
1671         fi = &fin->fin_fi;
1672         fri = fr->fr_ipf;
1673         lip = (u_32_t *)fi;
1674         lm = (u_32_t *)&fri->fri_mip;
1675         ld = (u_32_t *)&fri->fri_ip;
1676
1677         /*
1678          * first 32 bits to check coversion:
1679          * IP version, TOS, TTL, protocol
1680          */
1681         i = ((*lip & *lm) != *ld);
1682         FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
1683                    *lip, *lm, *ld));
1684         if (i)
1685                 return 1;
1686
1687         /*
1688          * Next 32 bits is a constructed bitmask indicating which IP options
1689          * are present (if any) in this packet.
1690          */
1691         lip++, lm++, ld++;
1692         i |= ((*lip & *lm) != *ld);
1693         FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
1694                    *lip, *lm, *ld));
1695         if (i)
1696                 return 1;
1697
1698         lip++, lm++, ld++;
1699         /*
1700          * Unrolled loops (4 each, for 32 bits) for address checks.
1701          */
1702         /*
1703          * Check the source address.
1704          */
1705 #ifdef  IPFILTER_LOOKUP
1706         if (fr->fr_satype == FRI_LOOKUP) {
1707                 i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip);
1708                 if (i == -1)
1709                         return 1;
1710                 lip += 3;
1711                 lm += 3;
1712                 ld += 3;
1713         } else {
1714 #endif
1715                 i = ((*lip & *lm) != *ld);
1716                 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
1717                            *lip, *lm, *ld));
1718                 if (fi->fi_v == 6) {
1719                         lip++, lm++, ld++;
1720                         i |= ((*lip & *lm) != *ld);
1721                         FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
1722                                    *lip, *lm, *ld));
1723                         lip++, lm++, ld++;
1724                         i |= ((*lip & *lm) != *ld);
1725                         FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
1726                                    *lip, *lm, *ld));
1727                         lip++, lm++, ld++;
1728                         i |= ((*lip & *lm) != *ld);
1729                         FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
1730                                    *lip, *lm, *ld));
1731                 } else {
1732                         lip += 3;
1733                         lm += 3;
1734                         ld += 3;
1735                 }
1736 #ifdef  IPFILTER_LOOKUP
1737         }
1738 #endif
1739         i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
1740         if (i)
1741                 return 1;
1742
1743         /*
1744          * Check the destination address.
1745          */
1746         lip++, lm++, ld++;
1747 #ifdef  IPFILTER_LOOKUP
1748         if (fr->fr_datype == FRI_LOOKUP) {
1749                 i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip);
1750                 if (i == -1)
1751                         return 1;
1752                 lip += 3;
1753                 lm += 3;
1754                 ld += 3;
1755         } else {
1756 #endif
1757                 i = ((*lip & *lm) != *ld);
1758                 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
1759                            *lip, *lm, *ld));
1760                 if (fi->fi_v == 6) {
1761                         lip++, lm++, ld++;
1762                         i |= ((*lip & *lm) != *ld);
1763                         FR_DEBUG(("3b. %#08x & %#08x != %#08x\n",
1764                                    *lip, *lm, *ld));
1765                         lip++, lm++, ld++;
1766                         i |= ((*lip & *lm) != *ld);
1767                         FR_DEBUG(("3c. %#08x & %#08x != %#08x\n",
1768                                    *lip, *lm, *ld));
1769                         lip++, lm++, ld++;
1770                         i |= ((*lip & *lm) != *ld);
1771                         FR_DEBUG(("3d. %#08x & %#08x != %#08x\n",
1772                                    *lip, *lm, *ld));
1773                 } else {
1774                         lip += 3;
1775                         lm += 3;
1776                         ld += 3;
1777                 }
1778 #ifdef  IPFILTER_LOOKUP
1779         }
1780 #endif
1781         i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
1782         if (i)
1783                 return 1;
1784         /*
1785          * IP addresses matched.  The next 32bits contains:
1786          * mast of old IP header security & authentication bits.
1787          */
1788         lip++, lm++, ld++;
1789         i |= ((*lip & *lm) != *ld);
1790         FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
1791                    *lip, *lm, *ld));
1792
1793         /*
1794          * Next we have 32 bits of packet flags.
1795          */
1796         lip++, lm++, ld++;
1797         i |= ((*lip & *lm) != *ld);
1798         FR_DEBUG(("5. %#08x & %#08x != %#08x\n",
1799                    *lip, *lm, *ld));
1800
1801         if (i == 0) {
1802                 /*
1803                  * If a fragment, then only the first has what we're
1804                  * looking for here...
1805                  */
1806                 if (portcmp) {
1807                         if (!fr_tcpudpchk(fin, &fr->fr_tuc))
1808                                 i = 1;
1809                 } else {
1810                         if (fr->fr_dcmp || fr->fr_scmp ||
1811                             fr->fr_tcpf || fr->fr_tcpfm)
1812                                 i = 1;
1813                         if (fr->fr_icmpm || fr->fr_icmp) {
1814                                 if (((fi->fi_p != IPPROTO_ICMP) &&
1815                                      (fi->fi_p != IPPROTO_ICMPV6)) ||
1816                                     fin->fin_off || (fin->fin_dlen < 2))
1817                                         i = 1;
1818                                 else if ((fin->fin_data[0] & fr->fr_icmpm) !=
1819                                          fr->fr_icmp) {
1820                                         FR_DEBUG(("i. %#x & %#x != %#x\n",
1821                                                  fin->fin_data[0],
1822                                                  fr->fr_icmpm, fr->fr_icmp));
1823                                         i = 1;
1824                                 }
1825                         }
1826                 }
1827         }
1828         return i;
1829 }
1830
1831
1832 /* ------------------------------------------------------------------------ */
1833 /* Function:    fr_scanlist                                                 */
1834 /* Returns:     int - result flags of scanning filter list                  */
1835 /* Parameters:  fin(I) - pointer to packet information                      */
1836 /*              pass(I) - default result to return for filtering            */
1837 /*                                                                          */
1838 /* Check the input/output list of rules for a match to the current packet.  */
1839 /* If a match is found, the value of fr_flags from the rule becomes the     */
1840 /* return value and fin->fin_fr points to the matched rule.                 */
1841 /*                                                                          */
1842 /* This function may be called recusively upto 16 times (limit inbuilt.)    */
1843 /* When unwinding, it should finish up with fin_depth as 0.                 */
1844 /*                                                                          */
1845 /* Could be per interface, but this gets real nasty when you don't have,    */
1846 /* or can't easily change, the kernel source code to .                      */
1847 /* ------------------------------------------------------------------------ */
1848 int fr_scanlist(fin, pass)
1849 fr_info_t *fin;
1850 u_32_t pass;
1851 {
1852         int rulen, portcmp, off, logged, skip;
1853         struct frentry *fr, *fnext;
1854         u_32_t passt, passo;
1855
1856         /*
1857          * Do not allow nesting deeper than 16 levels.
1858          */
1859         if (fin->fin_depth >= 16)
1860                 return pass;
1861
1862         fr = fin->fin_fr;
1863
1864         /*
1865          * If there are no rules in this list, return now.
1866          */
1867         if (fr == NULL)
1868                 return pass;
1869
1870         skip = 0;
1871         logged = 0;
1872         portcmp = 0;
1873         fin->fin_depth++;
1874         fin->fin_fr = NULL;
1875         off = fin->fin_off;
1876
1877         if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
1878                 portcmp = 1;
1879
1880         for (rulen = 0; fr; fr = fnext, rulen++) {
1881                 fnext = fr->fr_next;
1882                 if (skip != 0) {
1883                         FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags));
1884                         skip--;
1885                         continue;
1886                 }
1887
1888                 /*
1889                  * In all checks below, a null (zero) value in the
1890                  * filter struture is taken to mean a wildcard.
1891                  *
1892                  * check that we are working for the right interface
1893                  */
1894 #ifdef  _KERNEL
1895                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
1896                         continue;
1897 #else
1898                 if (opts & (OPT_VERBOSE|OPT_DEBUG))
1899                         printf("\n");
1900                 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' :
1901                                   FR_ISPASS(pass) ? 'p' :
1902                                   FR_ISACCOUNT(pass) ? 'A' :
1903                                   FR_ISAUTH(pass) ? 'a' :
1904                                   (pass & FR_NOMATCH) ? 'n' :'b'));
1905                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
1906                         continue;
1907                 FR_VERBOSE((":i"));
1908 #endif
1909
1910                 switch (fr->fr_type)
1911                 {
1912                 case FR_T_IPF :
1913                 case FR_T_IPF|FR_T_BUILTIN :
1914                         if (fr_ipfcheck(fin, fr, portcmp))
1915                                 continue;
1916                         break;
1917 #if defined(IPFILTER_BPF)
1918                 case FR_T_BPFOPC :
1919                 case FR_T_BPFOPC|FR_T_BUILTIN :
1920                     {
1921                         u_char *mc;
1922
1923                         if (*fin->fin_mp == NULL)
1924                                 continue;
1925                         if (fin->fin_v != fr->fr_v)
1926                                 continue;
1927                         mc = (u_char *)fin->fin_m;
1928                         if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0))
1929                                 continue;
1930                         break;
1931                     }
1932 #endif
1933                 case FR_T_CALLFUNC|FR_T_BUILTIN :
1934                     {
1935                         frentry_t *f;
1936
1937                         f = (*fr->fr_func)(fin, &pass);
1938                         if (f != NULL)
1939                                 fr = f;
1940                         else
1941                                 continue;
1942                         break;
1943                     }
1944                 default :
1945                         break;
1946                 }
1947
1948                 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
1949                         if (fin->fin_nattag == NULL)
1950                                 continue;
1951                         if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
1952                                 continue;
1953                 }
1954                 FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen));
1955
1956                 passt = fr->fr_flags;
1957
1958                 /*
1959                  * Allowing a rule with the "keep state" flag set to match
1960                  * packets that have been tagged "out of window" by the TCP
1961                  * state tracking is foolish as the attempt to add a new
1962                  * state entry to the table will fail.
1963                  */
1964                 if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW))
1965                         continue;
1966
1967                 /*
1968                  * If the rule is a "call now" rule, then call the function
1969                  * in the rule, if it exists and use the results from that.
1970                  * If the function pointer is bad, just make like we ignore
1971                  * it, except for increasing the hit counter.
1972                  */
1973                 if ((passt & FR_CALLNOW) != 0) {
1974                         frentry_t *frs;
1975
1976                         ATOMIC_INC64(fr->fr_hits);
1977                         if ((fr->fr_func != NULL) &&
1978                             (fr->fr_func == (ipfunc_t)-1))
1979                                 continue;
1980
1981                         frs = fin->fin_fr;
1982                         fin->fin_fr = fr;
1983                         fr = (*fr->fr_func)(fin, &passt);
1984                         if (fr == NULL) {
1985                                 fin->fin_fr = frs;
1986                                 continue;
1987                         }
1988                         passt = fr->fr_flags;
1989                 }
1990                 fin->fin_fr = fr;
1991
1992 #ifdef  IPFILTER_LOG
1993                 /*
1994                  * Just log this packet...
1995                  */
1996                 if ((passt & FR_LOGMASK) == FR_LOG) {
1997                         if (ipflog(fin, passt) == -1) {
1998                                 if (passt & FR_LOGORBLOCK) {
1999                                         passt &= ~FR_CMDMASK;
2000                                         passt |= FR_BLOCK|FR_QUICK;
2001                                 }
2002                                 ATOMIC_INCL(frstats[fin->fin_out].fr_skip);
2003                         }
2004                         ATOMIC_INCL(frstats[fin->fin_out].fr_pkl);
2005                         logged = 1;
2006                 }
2007 #endif /* IPFILTER_LOG */
2008                 fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
2009                 passo = pass;
2010                 if (FR_ISSKIP(passt))
2011                         skip = fr->fr_arg;
2012                 else if ((passt & FR_LOGMASK) != FR_LOG)
2013                         pass = passt;
2014                 if (passt & (FR_RETICMP|FR_FAKEICMP))
2015                         fin->fin_icode = fr->fr_icode;
2016                 FR_DEBUG(("pass %#x\n", pass));
2017                 ATOMIC_INC64(fr->fr_hits);
2018                 fin->fin_rule = rulen;
2019                 (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
2020                 if (fr->fr_grp != NULL) {
2021                         fin->fin_fr = *fr->fr_grp;
2022                         passt = fr_scanlist(fin, pass);
2023                         if (fin->fin_fr == NULL) {
2024                                 fin->fin_rule = rulen;
2025                                 (void) strncpy(fin->fin_group, fr->fr_group,
2026                                                FR_GROUPLEN);
2027                                 fin->fin_fr = fr;
2028                                 passt = pass;
2029                         }
2030                         if (fin->fin_flx & FI_DONTCACHE)
2031                                 logged = 1;
2032                         pass = passt;
2033                 }
2034
2035                 if (passt & FR_QUICK) {
2036                         /*
2037                          * Finally, if we've asked to track state for this
2038                          * packet, set it up.  Add state for "quick" rules
2039                          * here so that if the action fails we can consider
2040                          * the rule to "not match" and keep on processing
2041                          * filter rules.
2042                          */
2043                         if ((pass & FR_KEEPSTATE) &&
2044                             !(fin->fin_flx & FI_STATE)) {
2045                                 int out = fin->fin_out;
2046
2047                                 fin->fin_fr = fr;
2048                                 if (fr_addstate(fin, NULL, 0) != NULL) {
2049                                         ATOMIC_INCL(frstats[out].fr_ads);
2050                                 } else {
2051                                         ATOMIC_INCL(frstats[out].fr_bads);
2052                                         pass = passo;
2053                                         continue;
2054                                 }
2055                         }
2056                         break;
2057                 }
2058         }
2059         if (logged)
2060                 fin->fin_flx |= FI_DONTCACHE;
2061         fin->fin_depth--;
2062         return pass;
2063 }
2064
2065
2066 /* ------------------------------------------------------------------------ */
2067 /* Function:    fr_acctpkt                                                  */
2068 /* Returns:     frentry_t* - always returns NULL                            */
2069 /* Parameters:  fin(I) - pointer to packet information                      */
2070 /*              passp(IO) - pointer to current/new filter decision (unused) */
2071 /*                                                                          */
2072 /* Checks a packet against accounting rules, if there are any for the given */
2073 /* IP protocol version.                                                     */
2074 /*                                                                          */
2075 /* N.B.: this function returns NULL to match the prototype used by other    */
2076 /* functions called from the IPFilter "mainline" in fr_check().             */
2077 /* ------------------------------------------------------------------------ */
2078 frentry_t *fr_acctpkt(fin, passp)
2079 fr_info_t *fin;
2080 u_32_t *passp;
2081 {
2082         char group[FR_GROUPLEN];
2083         frentry_t *fr, *frsave;
2084         u_32_t pass, rulen;
2085
2086         passp = passp;
2087 #ifdef  USE_INET6
2088         if (fin->fin_v == 6)
2089                 fr = ipacct6[fin->fin_out][fr_active];
2090         else
2091 #endif
2092                 fr = ipacct[fin->fin_out][fr_active];
2093
2094         if (fr != NULL) {
2095                 frsave = fin->fin_fr;
2096                 bcopy(fin->fin_group, group, FR_GROUPLEN);
2097                 rulen = fin->fin_rule;
2098                 fin->fin_fr = fr;
2099                 pass = fr_scanlist(fin, FR_NOMATCH);
2100                 if (FR_ISACCOUNT(pass)) {
2101                         ATOMIC_INCL(frstats[0].fr_acct);
2102                 }
2103                 fin->fin_fr = frsave;
2104                 bcopy(group, fin->fin_group, FR_GROUPLEN);
2105                 fin->fin_rule = rulen;
2106         }
2107         return NULL;
2108 }
2109
2110
2111 /* ------------------------------------------------------------------------ */
2112 /* Function:    fr_firewall                                                 */
2113 /* Returns:     frentry_t* - returns pointer to matched rule, if no matches */
2114 /*                           were found, returns NULL.                      */
2115 /* Parameters:  fin(I) - pointer to packet information                      */
2116 /*              passp(IO) - pointer to current/new filter decision (unused) */
2117 /*                                                                          */
2118 /* Applies an appropriate set of firewall rules to the packet, to see if    */
2119 /* there are any matches.  The first check is to see if a match can be seen */
2120 /* in the cache.  If not, then search an appropriate list of rules.  Once a */
2121 /* matching rule is found, take any appropriate actions as defined by the   */
2122 /* rule - except logging.                                                   */
2123 /* ------------------------------------------------------------------------ */
2124 static frentry_t *fr_firewall(fin, passp)
2125 fr_info_t *fin;
2126 u_32_t *passp;
2127 {
2128         frentry_t *fr;
2129         fr_info_t *fc;
2130         u_32_t pass;
2131         int out;
2132
2133         out = fin->fin_out;
2134         pass = *passp;
2135
2136         /*
2137          * If a packet is found in the auth table, then skip checking
2138          * the access lists for permission but we do need to consider
2139          * the result as if it were from the ACL's.
2140          */
2141         fc = &frcache[out][CACHE_HASH(fin)];
2142         READ_ENTER(&ipf_frcache);
2143         if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
2144                 /*
2145                  * copy cached data so we can unlock the mutexes earlier.
2146                  */
2147                 bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
2148                 RWLOCK_EXIT(&ipf_frcache);
2149                 ATOMIC_INCL(frstats[out].fr_chit);
2150
2151                 if ((fr = fin->fin_fr) != NULL) {
2152                         ATOMIC_INC64(fr->fr_hits);
2153                         pass = fr->fr_flags;
2154                 }
2155         } else {
2156                 RWLOCK_EXIT(&ipf_frcache);
2157
2158 #ifdef  USE_INET6
2159                 if (fin->fin_v == 6)
2160                         fin->fin_fr = ipfilter6[out][fr_active];
2161                 else
2162 #endif
2163                         fin->fin_fr = ipfilter[out][fr_active];
2164                 if (fin->fin_fr != NULL)
2165                         pass = fr_scanlist(fin, fr_pass);
2166
2167                 if (((pass & FR_KEEPSTATE) == 0) &&
2168                     ((fin->fin_flx & FI_DONTCACHE) == 0)) {
2169                         WRITE_ENTER(&ipf_frcache);
2170                         bcopy((char *)fin, (char *)fc, FI_COPYSIZE);
2171                         RWLOCK_EXIT(&ipf_frcache);
2172                 }
2173                 if ((pass & FR_NOMATCH)) {
2174                         ATOMIC_INCL(frstats[out].fr_nom);
2175                 }
2176                 fr = fin->fin_fr;
2177         }
2178
2179         /*
2180          * Apply packets per second rate-limiting to a rule as required.
2181          */
2182         if ((fr != NULL) && (fr->fr_pps != 0) &&
2183             !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
2184                 pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST);
2185                 pass |= FR_BLOCK;
2186                 ATOMIC_INCL(frstats[out].fr_ppshit);
2187         }
2188
2189         /*
2190          * If we fail to add a packet to the authorization queue, then we
2191          * drop the packet later.  However, if it was added then pretend
2192          * we've dropped it already.
2193          */
2194         if (FR_ISAUTH(pass)) {
2195                 if (fr_newauth(fin->fin_m, fin) != 0) {
2196 #ifdef  _KERNEL
2197                         if ((pass & FR_RETMASK) == 0)
2198                                 fin->fin_m = *fin->fin_mp = NULL;
2199 #else
2200                         ;
2201 #endif
2202                         fin->fin_error = 0;
2203                 } else
2204                         fin->fin_error = ENOSPC;
2205         }
2206
2207         if ((fr != NULL) && (fr->fr_func != NULL) &&
2208             (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW))
2209                 (void) (*fr->fr_func)(fin, &pass);
2210
2211         /*
2212          * If a rule is a pre-auth rule, check again in the list of rules
2213          * loaded for authenticated use.  It does not particulary matter
2214          * if this search fails because a "preauth" result, from a rule,
2215          * is treated as "not a pass", hence the packet is blocked.
2216          */
2217         if (FR_ISPREAUTH(pass)) {
2218                 if ((fin->fin_fr = ipauth) != NULL)
2219                         pass = fr_scanlist(fin, fr_pass);
2220         }
2221
2222         /*
2223          * If the rule has "keep frag" and the packet is actually a fragment,
2224          * then create a fragment state entry.
2225          */
2226         if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
2227                 if (fin->fin_flx & FI_FRAG) {
2228                         if (fr_newfrag(fin, pass) == -1) {
2229                                 ATOMIC_INCL(frstats[out].fr_bnfr);
2230                         } else {
2231                                 ATOMIC_INCL(frstats[out].fr_nfr);
2232                         }
2233                 } else {
2234                         ATOMIC_INCL(frstats[out].fr_cfr);
2235                 }
2236         }
2237
2238         fr = fin->fin_fr;
2239
2240         if (passp != NULL)
2241                 *passp = pass;
2242
2243         return fr;
2244 }
2245
2246
2247 /* ------------------------------------------------------------------------ */
2248 /* Function:    fr_check                                                    */
2249 /* Returns:     int -  0 == packet allowed through,                         */
2250 /*              User space:                                                 */
2251 /*                    -1 == packet blocked                                  */
2252 /*                     1 == packet not matched                              */
2253 /*                    -2 == requires authentication                         */
2254 /*              Kernel:                                                     */
2255 /*                   > 0 == filter error # for packet                       */
2256 /* Parameters: ip(I)   - pointer to start of IPv4/6 packet                  */
2257 /*             hlen(I) - length of header                                   */
2258 /*             ifp(I)  - pointer to interface this packet is on             */
2259 /*             out(I)  - 0 == packet going in, 1 == packet going out        */
2260 /*             mp(IO)  - pointer to caller's buffer pointer that holds this */
2261 /*                       IP packet.                                         */
2262 /* Solaris & HP-UX ONLY :                                                   */
2263 /*             qpi(I)  - pointer to STREAMS queue information for this      */
2264 /*                       interface & direction.                             */
2265 /*                                                                          */
2266 /* fr_check() is the master function for all IPFilter packet processing.    */
2267 /* It orchestrates: Network Address Translation (NAT), checking for packet  */
2268 /* authorisation (or pre-authorisation), presence of related state info.,   */
2269 /* generating log entries, IP packet accounting, routing of packets as      */
2270 /* directed by firewall rules and of course whether or not to allow the     */
2271 /* packet to be further processed by the kernel.                            */
2272 /*                                                                          */
2273 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer  */
2274 /* freed.  Packets passed may be returned with the pointer pointed to by    */
2275 /* by "mp" changed to a new buffer.                                         */
2276 /* ------------------------------------------------------------------------ */
2277 int fr_check(ip, hlen, ifp, out
2278 #if defined(_KERNEL) && defined(MENTAT)
2279 , qif, mp)
2280 void *qif;
2281 #else
2282 , mp)
2283 #endif
2284 mb_t **mp;
2285 ip_t *ip;
2286 int hlen;
2287 void *ifp;
2288 int out;
2289 {
2290         /*
2291          * The above really sucks, but short of writing a diff
2292          */
2293         fr_info_t frinfo;
2294         fr_info_t *fin = &frinfo;
2295         u_32_t pass = fr_pass;
2296         frentry_t *fr = NULL;
2297         int v = IP_V(ip);
2298         mb_t *mc = NULL;
2299         mb_t *m;
2300 #ifdef USE_INET6
2301         ip6_t *ip6;
2302 #endif
2303         /*
2304          * The first part of fr_check() deals with making sure that what goes
2305          * into the filtering engine makes some sense.  Information about the
2306          * the packet is distilled, collected into a fr_info_t structure and
2307          * the an attempt to ensure the buffer the packet is in is big enough
2308          * to hold all the required packet headers.
2309          */
2310 #ifdef  _KERNEL
2311 # ifdef MENTAT
2312         qpktinfo_t *qpi = qif;
2313
2314         if ((u_int)ip & 0x3)
2315                 return 2;
2316 # else
2317         SPL_INT(s);
2318 # endif
2319
2320         READ_ENTER(&ipf_global);
2321
2322         if (fr_running <= 0) {
2323                 RWLOCK_EXIT(&ipf_global);
2324                 return 0;
2325         }
2326
2327         bzero((char *)fin, sizeof(*fin));
2328
2329 # ifdef MENTAT
2330         if (qpi->qpi_flags & QF_GROUP)
2331                 fin->fin_flx |= FI_MBCAST;
2332         m = qpi->qpi_m;
2333         fin->fin_qfm = m;
2334         fin->fin_qpi = qpi;
2335 # else /* MENTAT */
2336
2337         m = *mp;
2338
2339 #  if defined(M_MCAST)
2340         if ((m->m_flags & M_MCAST) != 0)
2341                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2342 #  endif
2343 #  if defined(M_MLOOP)
2344         if ((m->m_flags & M_MLOOP) != 0)
2345                 fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
2346 #  endif
2347 #  if defined(M_BCAST)
2348         if ((m->m_flags & M_BCAST) != 0)
2349                 fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
2350 #  endif
2351 #  ifdef M_CANFASTFWD
2352         /*
2353          * XXX For now, IP Filter and fast-forwarding of cached flows
2354          * XXX are mutually exclusive.  Eventually, IP Filter should
2355          * XXX get a "can-fast-forward" filter rule.
2356          */
2357         m->m_flags &= ~M_CANFASTFWD;
2358 #  endif /* M_CANFASTFWD */
2359 #  ifdef CSUM_DELAY_DATA
2360         /*
2361          * disable delayed checksums.
2362          */
2363         if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
2364                 in_delayed_cksum(m);
2365                 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
2366         }
2367 #  endif /* CSUM_DELAY_DATA */
2368 # endif /* MENTAT */
2369 #else
2370         READ_ENTER(&ipf_global);
2371
2372         bzero((char *)fin, sizeof(*fin));
2373         m = *mp;
2374 #endif /* _KERNEL */
2375
2376         fin->fin_v = v;
2377         fin->fin_m = m;
2378         fin->fin_ip = ip;
2379         fin->fin_mp = mp;
2380         fin->fin_out = out;
2381         fin->fin_ifp = ifp;
2382         fin->fin_error = ENETUNREACH;
2383         fin->fin_hlen = (u_short)hlen;
2384         fin->fin_dp = (char *)ip + hlen;
2385
2386         fin->fin_ipoff = (char *)ip - MTOD(m, char *);
2387
2388         SPL_NET(s);
2389
2390 #ifdef  USE_INET6
2391         if (v == 6) {
2392                 ATOMIC_INCL(frstats[out].fr_ipv6);
2393                 /*
2394                  * Jumbo grams are quite likely too big for internal buffer
2395                  * structures to handle comfortably, for now, so just drop
2396                  * them.
2397                  */
2398                 ip6 = (ip6_t *)ip;
2399                 fin->fin_plen = ntohs(ip6->ip6_plen);
2400                 if (fin->fin_plen == 0) {
2401                         pass = FR_BLOCK|FR_NOMATCH;
2402                         goto finished;
2403                 }
2404                 fin->fin_plen += sizeof(ip6_t);
2405         } else
2406 #endif
2407         {
2408 #if (defined(OpenBSD) && OpenBSD >= 200311) && defined(_KERNEL)
2409                 ip->ip_len = ntohs(ip->ip_len);
2410                 ip->ip_off = ntohs(ip->ip_off);
2411 #endif
2412                 fin->fin_plen = ip->ip_len;
2413         }
2414
2415         if (fr_makefrip(hlen, ip, fin) == -1) {
2416                 pass = FR_BLOCK|FR_NOMATCH;
2417                 goto finished;
2418         }
2419
2420         /*
2421          * For at least IPv6 packets, if a m_pullup() fails then this pointer
2422          * becomes NULL and so we have no packet to free.
2423          */
2424         if (*fin->fin_mp == NULL)
2425                 goto finished;
2426
2427         if (!out) {
2428                 if (v == 4) {
2429 #ifdef _KERNEL
2430                         if (fr_chksrc && !fr_verifysrc(fin)) {
2431                                 ATOMIC_INCL(frstats[0].fr_badsrc);
2432                                 fin->fin_flx |= FI_BADSRC;
2433                         }
2434 #endif
2435                         if (fin->fin_ip->ip_ttl < fr_minttl) {
2436                                 ATOMIC_INCL(frstats[0].fr_badttl);
2437                                 fin->fin_flx |= FI_LOWTTL;
2438                         }
2439                 }
2440 #ifdef USE_INET6
2441                 else  if (v == 6) {
2442                         ip6 = (ip6_t *)ip;
2443                         if (ip6->ip6_hlim < fr_minttl) {
2444                                 ATOMIC_INCL(frstats[0].fr_badttl);
2445                                 fin->fin_flx |= FI_LOWTTL;
2446                         }
2447                 }
2448 #endif
2449         }
2450
2451         if (fin->fin_flx & FI_SHORT) {
2452                 ATOMIC_INCL(frstats[out].fr_short);
2453         }
2454
2455         READ_ENTER(&ipf_mutex);
2456
2457         /*
2458          * Check auth now.  This, combined with the check below to see if apass
2459          * is 0 is to ensure that we don't count the packet twice, which can
2460          * otherwise occur when we reprocess it.  As it is, we only count it
2461          * after it has no auth. table matchup.  This also stops NAT from
2462          * occuring until after the packet has been auth'd.
2463          */
2464         fr = fr_checkauth(fin, &pass);
2465         if (!out) {
2466                 if (fr_checknatin(fin, &pass) == -1) {
2467                         RWLOCK_EXIT(&ipf_mutex);
2468                         goto finished;
2469                 }
2470         }
2471         if (!out)
2472                 (void) fr_acctpkt(fin, NULL);
2473
2474         if (fr == NULL)
2475                 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG)
2476                         fr = fr_knownfrag(fin, &pass);
2477         if (fr == NULL)
2478                 fr = fr_checkstate(fin, &pass);
2479
2480         if ((pass & FR_NOMATCH) || (fr == NULL))
2481                 fr = fr_firewall(fin, &pass);
2482
2483         /*
2484          * If we've asked to track state for this packet, set it up.
2485          * Here rather than fr_firewall because fr_checkauth may decide
2486          * to return a packet for "keep state"
2487          */
2488         if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) {
2489                 if (fr_addstate(fin, NULL, 0) != NULL) {
2490                         ATOMIC_INCL(frstats[out].fr_ads);
2491                 } else {
2492                         ATOMIC_INCL(frstats[out].fr_bads);
2493                         if (FR_ISPASS(pass)) {
2494                                 pass &= ~FR_CMDMASK;
2495                                 pass |= FR_BLOCK;
2496                         }
2497                 }
2498         }
2499
2500         fin->fin_fr = fr;
2501
2502         /*
2503          * Only count/translate packets which will be passed on, out the
2504          * interface.
2505          */
2506         if (out && FR_ISPASS(pass)) {
2507                 (void) fr_acctpkt(fin, NULL);
2508
2509                 if (fr_checknatout(fin, &pass) == -1) {
2510                         RWLOCK_EXIT(&ipf_mutex);
2511                         goto finished;
2512                 } else if ((fr_update_ipid != 0) && (v == 4)) {
2513                         if (fr_updateipid(fin) == -1) {
2514                                 ATOMIC_INCL(frstats[1].fr_ipud);
2515                                 pass &= ~FR_CMDMASK;
2516                                 pass |= FR_BLOCK;
2517                         } else {
2518                                 ATOMIC_INCL(frstats[0].fr_ipud);
2519                         }
2520                 }
2521         }
2522
2523 #ifdef  IPFILTER_LOG
2524         if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
2525                 (void) fr_dolog(fin, &pass);
2526         }
2527 #endif
2528
2529         if (fin->fin_state != NULL) {
2530                 fr_statederef(fin, (ipstate_t **)&fin->fin_state);
2531                 fin->fin_state = NULL;
2532         }
2533
2534         if (fin->fin_nat != NULL) {
2535                 fr_natderef((nat_t **)&fin->fin_nat);
2536                 fin->fin_nat = NULL;
2537         }
2538
2539         /*
2540          * Up the reference on fr_lock and exit ipf_mutex.  fr_fastroute
2541          * only frees up the lock on ipf_global and the generation of a
2542          * packet below could cause a recursive call into IPFilter.
2543          * Hang onto the filter rule just in case someone decides to remove
2544          * or flush it in the meantime.
2545          */
2546         if (fr != NULL) {
2547                 MUTEX_ENTER(&fr->fr_lock);
2548                 fr->fr_ref++;
2549                 MUTEX_EXIT(&fr->fr_lock);
2550         }
2551
2552         RWLOCK_EXIT(&ipf_mutex);
2553
2554         if ((pass & FR_RETMASK) != 0) {
2555                 /*
2556                  * Should we return an ICMP packet to indicate error
2557                  * status passing through the packet filter ?
2558                  * WARNING: ICMP error packets AND TCP RST packets should
2559                  * ONLY be sent in repsonse to incoming packets.  Sending them
2560                  * in response to outbound packets can result in a panic on
2561                  * some operating systems.
2562                  */
2563                 if (!out) {
2564                         if (pass & FR_RETICMP) {
2565                                 int dst;
2566
2567                                 if ((pass & FR_RETMASK) == FR_FAKEICMP)
2568                                         dst = 1;
2569                                 else
2570                                         dst = 0;
2571                                 (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst);
2572                                 ATOMIC_INCL(frstats[0].fr_ret);
2573                         } else if (((pass & FR_RETMASK) == FR_RETRST) &&
2574                                    !(fin->fin_flx & FI_SHORT)) {
2575                                 if (((fin->fin_flx & FI_OOW) != 0) ||
2576                                     (fr_send_reset(fin) == 0)) {
2577                                         ATOMIC_INCL(frstats[1].fr_ret);
2578                                 }
2579                         }
2580
2581                         /*
2582                          * When using return-* with auth rules, the auth code
2583                          * takes over disposing of this packet.
2584                          */
2585                         if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
2586                                 fin->fin_m = *fin->fin_mp = NULL;
2587                         }
2588                 } else {
2589                         if (pass & FR_RETRST)
2590                                 fin->fin_error = ECONNRESET;
2591                 }
2592         }
2593
2594         /*
2595          * If we didn't drop off the bottom of the list of rules (and thus
2596          * the 'current' rule fr is not NULL), then we may have some extra
2597          * instructions about what to do with a packet.
2598          * Once we're finished return to our caller, freeing the packet if
2599          * we are dropping it (* BSD ONLY *).
2600          */
2601         if (fr != NULL) {
2602                 frdest_t *fdp;
2603
2604                 fdp = &fr->fr_tifs[fin->fin_rev];
2605
2606                 if (!out && (pass & FR_FASTROUTE)) {
2607                         /*
2608                          * For fastroute rule, no destioation interface defined
2609                          * so pass NULL as the frdest_t parameter
2610                          */
2611                         (void) fr_fastroute(fin->fin_m, mp, fin, NULL);
2612                         m = *mp = NULL;
2613                 } else if ((fdp->fd_ifp != NULL) &&
2614                            (fdp->fd_ifp != (struct ifnet *)-1)) {
2615                         /* this is for to rules: */
2616                         (void) fr_fastroute(fin->fin_m, mp, fin, fdp);
2617                         m = *mp = NULL;
2618                 }
2619
2620                 /*
2621                  * Generate a duplicated packet.
2622                  */
2623                 if ((pass & FR_DUP) != 0) {
2624                         mc = M_DUPLICATE(fin->fin_m);
2625                         if (mc != NULL)
2626                                 (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif);
2627                 }
2628
2629                 (void) fr_derefrule(&fr);
2630         }
2631
2632 finished:
2633         if (!FR_ISPASS(pass)) {
2634                 ATOMIC_INCL(frstats[out].fr_block);
2635                 if (*mp != NULL) {
2636                         FREE_MB_T(*mp);
2637                         m = *mp = NULL;
2638                 }
2639         } else {
2640                 ATOMIC_INCL(frstats[out].fr_pass);
2641 #if defined(_KERNEL) && defined(__sgi)
2642                 if ((fin->fin_hbuf != NULL) &&
2643                     (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) {
2644                         COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf);
2645                 }
2646 #endif
2647         }
2648
2649         SPL_X(s);
2650         RWLOCK_EXIT(&ipf_global);
2651
2652 #ifdef _KERNEL
2653 # if defined(OpenBSD) && OpenBSD >= 200311    
2654         if (FR_ISPASS(pass) && (v == 4)) {
2655                 ip = fin->fin_ip;
2656                 ip->ip_len = ntohs(ip->ip_len);
2657                 ip->ip_off = ntohs(ip->ip_off);
2658         }
2659 # endif
2660         return (FR_ISPASS(pass)) ? 0 : fin->fin_error;
2661 #else /* _KERNEL */
2662         FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
2663         if ((pass & FR_NOMATCH) != 0)
2664                 return 1;
2665
2666         if ((pass & FR_RETMASK) != 0)
2667                 switch (pass & FR_RETMASK)
2668                 {
2669                 case FR_RETRST :
2670                         return 3;
2671                 case FR_RETICMP :
2672                         return 4;
2673                 case FR_FAKEICMP :
2674                         return 5;
2675                 }
2676
2677         switch (pass & FR_CMDMASK)
2678         {
2679         case FR_PASS :
2680                 return 0;
2681         case FR_BLOCK :
2682                 return -1;
2683         case FR_AUTH :
2684                 return -2;
2685         case FR_ACCOUNT :
2686                 return -3;
2687         case FR_PREAUTH :
2688                 return -4;
2689         }
2690         return 2;
2691 #endif /* _KERNEL */
2692 }
2693
2694
2695 #ifdef  IPFILTER_LOG
2696 /* ------------------------------------------------------------------------ */
2697 /* Function:    fr_dolog                                                    */
2698 /* Returns:     frentry_t* - returns contents of fin_fr (no change made)    */
2699 /* Parameters:  fin(I) - pointer to packet information                      */
2700 /*              passp(IO) - pointer to current/new filter decision (unused) */
2701 /*                                                                          */
2702 /* Checks flags set to see how a packet should be logged, if it is to be    */
2703 /* logged.  Adjust statistics based on its success or not.                  */
2704 /* ------------------------------------------------------------------------ */
2705 frentry_t *fr_dolog(fin, passp)
2706 fr_info_t *fin;
2707 u_32_t *passp;
2708 {
2709         u_32_t pass;
2710         int out;
2711
2712         out = fin->fin_out;
2713         pass = *passp;
2714
2715         if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
2716                 pass |= FF_LOGNOMATCH;
2717                 ATOMIC_INCL(frstats[out].fr_npkl);
2718                 goto logit;
2719         } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
2720             (FR_ISPASS(pass) && (fr_flags & FF_LOGPASS))) {
2721                 if ((pass & FR_LOGMASK) != FR_LOGP)
2722                         pass |= FF_LOGPASS;
2723                 ATOMIC_INCL(frstats[out].fr_ppkl);
2724                 goto logit;
2725         } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
2726                    (FR_ISBLOCK(pass) && (fr_flags & FF_LOGBLOCK))) {
2727                 if ((pass & FR_LOGMASK) != FR_LOGB)
2728                         pass |= FF_LOGBLOCK;
2729                 ATOMIC_INCL(frstats[out].fr_bpkl);
2730 logit:
2731                 if (ipflog(fin, pass) == -1) {
2732                         ATOMIC_INCL(frstats[out].fr_skip);
2733
2734                         /*
2735                          * If the "or-block" option has been used then
2736                          * block the packet if we failed to log it.
2737                          */
2738                         if ((pass & FR_LOGORBLOCK) &&
2739                             FR_ISPASS(pass)) {
2740                                 pass &= ~FR_CMDMASK;
2741                                 pass |= FR_BLOCK;
2742                         }
2743                 }
2744                 *passp = pass;
2745         }
2746
2747         return fin->fin_fr;
2748 }
2749 #endif /* IPFILTER_LOG */
2750
2751
2752 /* ------------------------------------------------------------------------ */
2753 /* Function:    ipf_cksum                                                   */
2754 /* Returns:     u_short - IP header checksum                                */
2755 /* Parameters:  addr(I) - pointer to start of buffer to checksum            */
2756 /*              len(I)  - length of buffer in bytes                         */
2757 /*                                                                          */
2758 /* Calculate the two's complement 16 bit checksum of the buffer passed.     */
2759 /*                                                                          */
2760 /* N.B.: addr should be 16bit aligned.                                      */
2761 /* ------------------------------------------------------------------------ */
2762 u_short ipf_cksum(addr, len)
2763 u_short *addr;
2764 int len;
2765 {
2766         u_32_t sum = 0;
2767
2768         for (sum = 0; len > 1; len -= 2)
2769                 sum += *addr++;
2770
2771         /* mop up an odd byte, if necessary */
2772         if (len == 1)
2773                 sum += *(u_char *)addr;
2774
2775         /*
2776          * add back carry outs from top 16 bits to low 16 bits
2777          */
2778         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
2779         sum += (sum >> 16);                     /* add carry */
2780         return (u_short)(~sum);
2781 }
2782
2783
2784 /* ------------------------------------------------------------------------ */
2785 /* Function:    fr_cksum                                                    */
2786 /* Returns:     u_short - layer 4 checksum                                  */
2787 /* Parameters:  m(I  )     - pointer to buffer holding packet               */
2788 /*              ip(I)      - pointer to IP header                           */
2789 /*              l4proto(I) - protocol to caclulate checksum for             */
2790 /*              l4hdr(I)   - pointer to layer 4 header                      */
2791 /*                                                                          */
2792 /* Calculates the TCP checksum for the packet held in "m", using the data   */
2793 /* in the IP header "ip" to seed it.                                        */
2794 /*                                                                          */
2795 /* NB: This function assumes we've pullup'd enough for all of the IP header */
2796 /* and the TCP header.  We also assume that data blocks aren't allocated in */
2797 /* odd sizes.                                                               */
2798 /*                                                                          */
2799 /* Expects ip_len to be in host byte order when called.                     */
2800 /* ------------------------------------------------------------------------ */
2801 u_short fr_cksum(m, ip, l4proto, l4hdr, l3len)
2802 mb_t *m;
2803 ip_t *ip;
2804 int l4proto, l3len;
2805 void *l4hdr;
2806 {
2807         u_short *sp, slen, sumsave, l4hlen, *csump;
2808         u_int sum, sum2;
2809         int hlen;
2810 #ifdef  USE_INET6
2811         ip6_t *ip6;
2812 #endif
2813
2814         csump = NULL;
2815         sumsave = 0;
2816         l4hlen = 0;
2817         sp = NULL;
2818         slen = 0;
2819         hlen = 0;
2820         sum = 0;
2821
2822         /*
2823          * Add up IP Header portion
2824          */
2825 #ifdef  USE_INET6
2826         if (IP_V(ip) == 4) {
2827 #endif
2828                 hlen = IP_HL(ip) << 2;
2829                 slen = l3len - hlen;
2830                 sum = htons((u_short)l4proto);
2831                 sum += htons(slen);
2832                 sp = (u_short *)&ip->ip_src;
2833                 sum += *sp++;   /* ip_src */
2834                 sum += *sp++;
2835                 sum += *sp++;   /* ip_dst */
2836                 sum += *sp++;
2837 #ifdef  USE_INET6
2838         } else if (IP_V(ip) == 6) {
2839                 ip6 = (ip6_t *)ip;
2840                 hlen = sizeof(*ip6);
2841                 slen = ntohs(l3len);
2842                 sum = htons((u_short)l4proto);
2843                 sum += slen;
2844                 sp = (u_short *)&ip6->ip6_src;
2845                 sum += *sp++;   /* ip6_src */
2846                 sum += *sp++;
2847                 sum += *sp++;
2848                 sum += *sp++;
2849                 sum += *sp++;
2850                 sum += *sp++;
2851                 sum += *sp++;
2852                 sum += *sp++;
2853                 sum += *sp++;   /* ip6_dst */
2854                 sum += *sp++;
2855                 sum += *sp++;
2856                 sum += *sp++;
2857                 sum += *sp++;
2858                 sum += *sp++;
2859                 sum += *sp++;
2860                 sum += *sp++;
2861         }
2862 #endif
2863
2864         switch (l4proto)
2865         {
2866         case IPPROTO_UDP :
2867                 csump = &((udphdr_t *)l4hdr)->uh_sum;
2868                 l4hlen = sizeof(udphdr_t);
2869                 break;
2870
2871         case IPPROTO_TCP :
2872                 csump = &((tcphdr_t *)l4hdr)->th_sum;
2873                 l4hlen = sizeof(tcphdr_t);
2874                 break;
2875         case IPPROTO_ICMP :
2876                 csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
2877                 l4hlen = 4;
2878                 sum = 0;
2879                 break;
2880         default :
2881                 break;
2882         }
2883
2884         if (csump != NULL) {
2885                 sumsave = *csump;
2886                 *csump = 0;
2887         }
2888
2889         l4hlen = l4hlen;        /* LINT */
2890
2891 #ifdef  _KERNEL
2892 # ifdef MENTAT
2893         {
2894         void *rp = m->b_rptr;
2895
2896         if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr)
2897                 m->b_rptr = (u_char *)ip;
2898         sum2 = ip_cksum(m, hlen, sum);  /* hlen == offset */
2899         m->b_rptr = rp;
2900         sum2 = (u_short)(~sum2 & 0xffff);
2901         }
2902 # else /* MENTAT */
2903 #  if defined(BSD) || defined(sun)
2904 #   if BSD >= 199103
2905         m->m_data += hlen;
2906 #   else
2907         m->m_off += hlen;
2908 #   endif
2909         m->m_len -= hlen;
2910         sum2 = in_cksum(m, slen);
2911         m->m_len += hlen;
2912 #   if BSD >= 199103
2913         m->m_data -= hlen;
2914 #   else
2915         m->m_off -= hlen;
2916 #   endif
2917         /*
2918          * Both sum and sum2 are partial sums, so combine them together.
2919          */
2920         sum += ~sum2 & 0xffff;
2921         while (sum > 0xffff)
2922                 sum = (sum & 0xffff) + (sum >> 16);
2923         sum2 = ~sum & 0xffff;
2924 #  else /* defined(BSD) || defined(sun) */
2925 {
2926         union {
2927                 u_char  c[2];
2928                 u_short s;
2929         } bytes;
2930         u_short len = ip->ip_len;
2931 #   if defined(__sgi)
2932         int add;
2933 #   endif
2934
2935         /*
2936          * Add up IP Header portion
2937          */
2938         if (sp != (u_short *)l4hdr)
2939                 sp = (u_short *)l4hdr;
2940
2941         switch (l4proto)
2942         {
2943         case IPPROTO_UDP :
2944                 sum += *sp++;   /* sport */
2945                 sum += *sp++;   /* dport */
2946                 sum += *sp++;   /* udp length */
2947                 sum += *sp++;   /* checksum */
2948                 break;
2949
2950         case IPPROTO_TCP :
2951                 sum += *sp++;   /* sport */
2952                 sum += *sp++;   /* dport */
2953                 sum += *sp++;   /* seq */
2954                 sum += *sp++;
2955                 sum += *sp++;   /* ack */
2956                 sum += *sp++;
2957                 sum += *sp++;   /* off */
2958                 sum += *sp++;   /* win */
2959                 sum += *sp++;   /* checksum */
2960                 sum += *sp++;   /* urp */
2961                 break;
2962         case IPPROTO_ICMP :
2963                 sum = *sp++;    /* type/code */
2964                 sum += *sp++;   /* checksum */
2965                 break;
2966         }
2967
2968 #   ifdef       __sgi
2969         /*
2970          * In case we had to copy the IP & TCP header out of mbufs,
2971          * skip over the mbuf bits which are the header
2972          */
2973         if ((caddr_t)ip != mtod(m, caddr_t)) {
2974                 hlen = (caddr_t)sp - (caddr_t)ip;
2975                 while (hlen) {
2976                         add = MIN(hlen, m->m_len);
2977                         sp = (u_short *)(mtod(m, caddr_t) + add);
2978                         hlen -= add;
2979                         if (add == m->m_len) {
2980                                 m = m->m_next;
2981                                 if (!hlen) {
2982                                         if (!m)
2983                                                 break;
2984                                         sp = mtod(m, u_short *);
2985                                 }
2986                                 PANIC((!m),("fr_cksum(1): not enough data"));
2987                         }
2988                 }
2989         }
2990 #   endif
2991
2992         len -= (l4hlen + hlen);
2993         if (len <= 0)
2994                 goto nodata;
2995
2996         while (len > 1) {
2997                 if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) {
2998                         m = m->m_next;
2999                         PANIC((!m),("fr_cksum(2): not enough data"));
3000                         sp = mtod(m, u_short *);
3001                 }
3002                 if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) {
3003                         bytes.c[0] = *(u_char *)sp;
3004                         m = m->m_next;
3005                         PANIC((!m),("fr_cksum(3): not enough data"));
3006                         sp = mtod(m, u_short *);
3007                         bytes.c[1] = *(u_char *)sp;
3008                         sum += bytes.s;
3009                         sp = (u_short *)((u_char *)sp + 1);
3010                 }
3011                 if ((u_long)sp & 1) {
3012                         bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
3013                         sum += bytes.s;
3014                 } else
3015                         sum += *sp++;
3016                 len -= 2;
3017         }
3018
3019         if (len != 0)
3020                 sum += ntohs(*(u_char *)sp << 8);
3021 nodata:
3022         while (sum > 0xffff)
3023                 sum = (sum & 0xffff) + (sum >> 16);
3024         sum2 = (u_short)(~sum & 0xffff);
3025 }
3026 #  endif /*  defined(BSD) || defined(sun) */
3027 # endif /* MENTAT */
3028 #else /* _KERNEL */
3029         for (; slen > 1; slen -= 2)
3030                 sum += *sp++;
3031         if (slen)
3032                 sum += ntohs(*(u_char *)sp << 8);
3033         while (sum > 0xffff)
3034                 sum = (sum & 0xffff) + (sum >> 16);
3035         sum2 = (u_short)(~sum & 0xffff);
3036 #endif /* _KERNEL */
3037         if (csump != NULL)
3038                 *csump = sumsave;
3039         return sum2;
3040 }
3041
3042
3043 #if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \
3044     defined(__sgi) ) && !defined(linux) && !defined(_AIX51)
3045 /*
3046  * Copyright (c) 1982, 1986, 1988, 1991, 1993
3047  *      The Regents of the University of California.  All rights reserved.
3048  *
3049  * Redistribution and use in source and binary forms, with or without
3050  * modification, are permitted provided that the following conditions
3051  * are met:
3052  * 1. Redistributions of source code must retain the above copyright
3053  *    notice, this list of conditions and the following disclaimer.
3054  * 2. Redistributions in binary form must reproduce the above copyright
3055  *    notice, this list of conditions and the following disclaimer in the
3056  *    documentation and/or other materials provided with the distribution.
3057  * 3. Neither the name of the University nor the names of its contributors
3058  *    may be used to endorse or promote products derived from this software
3059  *    without specific prior written permission.
3060  *
3061  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3062  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3063  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3064  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3065  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3066  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3067  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3068  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3069  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3070  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3071  * SUCH DAMAGE.
3072  *
3073  *      @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
3074  * $Id: fil.c,v 2.243.2.78 2006/03/29 11:19:54 darrenr Exp $
3075  */
3076 /*
3077  * Copy data from an mbuf chain starting "off" bytes from the beginning,
3078  * continuing for "len" bytes, into the indicated buffer.
3079  */
3080 void
3081 m_copydata(m, off, len, cp)
3082         mb_t *m;
3083         int off;
3084         int len;
3085         caddr_t cp;
3086 {
3087         unsigned count;
3088
3089         if (off < 0 || len < 0)
3090                 panic("m_copydata");
3091         while (off > 0) {
3092                 if (m == 0)
3093                         panic("m_copydata");
3094                 if (off < m->m_len)
3095                         break;
3096                 off -= m->m_len;
3097                 m = m->m_next;
3098         }
3099         while (len > 0) {
3100                 if (m == 0)
3101                         panic("m_copydata");
3102                 count = MIN(m->m_len - off, len);
3103                 bcopy(mtod(m, caddr_t) + off, cp, count);
3104                 len -= count;
3105                 cp += count;
3106                 off = 0;
3107                 m = m->m_next;
3108         }
3109 }
3110
3111
3112 /*
3113  * Copy data from a buffer back into the indicated mbuf chain,
3114  * starting "off" bytes from the beginning, extending the mbuf
3115  * chain if necessary.
3116  */
3117 void
3118 m_copyback(m0, off, len, cp)
3119         struct  mbuf *m0;
3120         int off;
3121         int len;
3122         caddr_t cp;
3123 {
3124         int mlen;
3125         struct mbuf *m = m0, *n;
3126         int totlen = 0;
3127
3128         if (m0 == 0)
3129                 return;
3130         while (off > (mlen = m->m_len)) {
3131                 off -= mlen;
3132                 totlen += mlen;
3133                 if (m->m_next == 0) {
3134                         n = m_getclr(M_DONTWAIT, m->m_type);
3135                         if (n == 0)
3136                                 goto out;
3137                         n->m_len = min(MLEN, len + off);
3138                         m->m_next = n;
3139                 }
3140                 m = m->m_next;
3141         }
3142         while (len > 0) {
3143                 mlen = min(m->m_len - off, len);
3144                 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
3145                 cp += mlen;
3146                 len -= mlen;
3147                 mlen += off;
3148                 off = 0;
3149                 totlen += mlen;
3150                 if (len == 0)
3151                         break;
3152                 if (m->m_next == 0) {
3153                         n = m_get(M_DONTWAIT, m->m_type);
3154                         if (n == 0)
3155                                 break;
3156                         n->m_len = min(MLEN, len);
3157                         m->m_next = n;
3158                 }
3159                 m = m->m_next;
3160         }
3161 out:
3162 #if 0
3163         if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
3164                 m->m_pkthdr.len = totlen;
3165 #endif
3166         return;
3167 }
3168 #endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */
3169
3170
3171 /* ------------------------------------------------------------------------ */
3172 /* Function:    fr_findgroup                                                */
3173 /* Returns:     frgroup_t * - NULL = group not found, else pointer to group */
3174 /* Parameters:  group(I) - group name to search for                         */
3175 /*              unit(I)  - device to which this group belongs               */
3176 /*              set(I)   - which set of rules (inactive/inactive) this is   */
3177 /*              fgpp(O)  - pointer to place to store pointer to the pointer */
3178 /*                         to where to add the next (last) group or where   */
3179 /*                         to delete group from.                            */
3180 /*                                                                          */
3181 /* Search amongst the defined groups for a particular group number.         */
3182 /* ------------------------------------------------------------------------ */
3183 frgroup_t *fr_findgroup(group, unit, set, fgpp)
3184 char *group;
3185 minor_t unit;
3186 int set;
3187 frgroup_t ***fgpp;
3188 {
3189         frgroup_t *fg, **fgp;
3190
3191         /*
3192          * Which list of groups to search in is dependent on which list of
3193          * rules are being operated on.
3194          */
3195         fgp = &ipfgroups[unit][set];
3196
3197         while ((fg = *fgp) != NULL) {
3198                 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
3199                         break;
3200                 else
3201                         fgp = &fg->fg_next;
3202         }
3203         if (fgpp != NULL)
3204                 *fgpp = fgp;
3205         return fg;
3206 }
3207
3208
3209 /* ------------------------------------------------------------------------ */
3210 /* Function:    fr_addgroup                                                 */
3211 /* Returns:     frgroup_t * - NULL == did not create group,                 */
3212 /*                            != NULL == pointer to the group               */
3213 /* Parameters:  num(I)   - group number to add                              */
3214 /*              head(I)  - rule pointer that is using this as the head      */
3215 /*              flags(I) - rule flags which describe the type of rule it is */
3216 /*              unit(I)  - device to which this group will belong to        */
3217 /*              set(I)   - which set of rules (inactive/inactive) this is   */
3218 /* Write Locks: ipf_mutex                                                   */
3219 /*                                                                          */
3220 /* Add a new group head, or if it already exists, increase the reference    */
3221 /* count to it.                                                             */
3222 /* ------------------------------------------------------------------------ */
3223 frgroup_t *fr_addgroup(group, head, flags, unit, set)
3224 char *group;
3225 void *head;
3226 u_32_t flags;
3227 minor_t unit;
3228 int set;
3229 {
3230         frgroup_t *fg, **fgp;
3231         u_32_t gflags;
3232
3233         if (group == NULL)
3234                 return NULL;
3235
3236         if (unit == IPL_LOGIPF && *group == '\0')
3237                 return NULL;
3238
3239         fgp = NULL;
3240         gflags = flags & FR_INOUT;
3241
3242         fg = fr_findgroup(group, unit, set, &fgp);
3243         if (fg != NULL) {
3244                 if (fg->fg_flags == 0)
3245                         fg->fg_flags = gflags;
3246                 else if (gflags != fg->fg_flags)
3247                         return NULL;
3248                 fg->fg_ref++;
3249                 return fg;
3250         }
3251         KMALLOC(fg, frgroup_t *);
3252         if (fg != NULL) {
3253                 fg->fg_head = head;
3254                 fg->fg_start = NULL;
3255                 fg->fg_next = *fgp;
3256                 bcopy(group, fg->fg_name, FR_GROUPLEN);
3257                 fg->fg_flags = gflags;
3258                 fg->fg_ref = 1;
3259                 *fgp = fg;
3260         }
3261         return fg;
3262 }
3263
3264
3265 /* ------------------------------------------------------------------------ */
3266 /* Function:    fr_delgroup                                                 */
3267 /* Returns:     Nil                                                         */
3268 /* Parameters:  group(I) - group name to delete                             */
3269 /*              unit(I)  - device to which this group belongs               */
3270 /*              set(I)   - which set of rules (inactive/inactive) this is   */
3271 /* Write Locks: ipf_mutex                                                   */
3272 /*                                                                          */
3273 /* Attempt to delete a group head.                                          */
3274 /* Only do this when its reference count reaches 0.                         */
3275 /* ------------------------------------------------------------------------ */
3276 void fr_delgroup(group, unit, set)
3277 char *group;
3278 minor_t unit;
3279 int set;
3280 {
3281         frgroup_t *fg, **fgp;
3282
3283         fg = fr_findgroup(group, unit, set, &fgp);
3284         if (fg == NULL)
3285                 return;
3286
3287         fg->fg_ref--;
3288         if (fg->fg_ref == 0) {
3289                 *fgp = fg->fg_next;
3290                 KFREE(fg);
3291         }
3292 }
3293
3294
3295 /* ------------------------------------------------------------------------ */
3296 /* Function:    fr_getrulen                                                 */
3297 /* Returns:     frentry_t * - NULL == not found, else pointer to rule n     */
3298 /* Parameters:  unit(I)  - device for which to count the rule's number      */
3299 /*              flags(I) - which set of rules to find the rule in           */
3300 /*              group(I) - group name                                       */
3301 /*              n(I)     - rule number to find                              */
3302 /*                                                                          */
3303 /* Find rule # n in group # g and return a pointer to it.  Return NULl if   */
3304 /* group # g doesn't exist or there are less than n rules in the group.     */
3305 /* ------------------------------------------------------------------------ */
3306 frentry_t *fr_getrulen(unit, group, n)
3307 int unit;
3308 char *group;
3309 u_32_t n;
3310 {
3311         frentry_t *fr;
3312         frgroup_t *fg;
3313
3314         fg = fr_findgroup(group, unit, fr_active, NULL);
3315         if (fg == NULL)
3316                 return NULL;
3317         for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--)
3318                 ;
3319         if (n != 0)
3320                 return NULL;
3321         return fr;
3322 }
3323
3324
3325 /* ------------------------------------------------------------------------ */
3326 /* Function:    fr_rulen                                                    */
3327 /* Returns:     int - >= 0 - rule number, -1 == search failed               */
3328 /* Parameters:  unit(I) - device for which to count the rule's number       */
3329 /*              fr(I)   - pointer to rule to match                          */
3330 /*                                                                          */
3331 /* Return the number for a rule on a specific filtering device.             */
3332 /* ------------------------------------------------------------------------ */
3333 int fr_rulen(unit, fr)
3334 int unit;
3335 frentry_t *fr;
3336 {
3337         frentry_t *fh;
3338         frgroup_t *fg;
3339         u_32_t n = 0;
3340
3341         if (fr == NULL)
3342                 return -1;
3343         fg = fr_findgroup(fr->fr_group, unit, fr_active, NULL);
3344         if (fg == NULL)
3345                 return -1;
3346         for (fh = fg->fg_head; fh; n++, fh = fh->fr_next)
3347                 if (fh == fr)
3348                         break;
3349         if (fh == NULL)
3350                 return -1;
3351         return n;
3352 }
3353
3354
3355 /* ------------------------------------------------------------------------ */
3356 /* Function:    frflushlist                                                 */
3357 /* Returns:     int - >= 0 - number of flushed rules                        */
3358 /* Parameters:  set(I)   - which set of rules (inactive/inactive) this is   */
3359 /*              unit(I)  - device for which to flush rules                  */
3360 /*              flags(I) - which set of rules to flush                      */
3361 /*              nfreedp(O) - pointer to int where flush count is stored     */
3362 /*              listp(I)   - pointer to list to flush pointer               */
3363 /* Write Locks: ipf_mutex                                                   */
3364 /*                                                                          */
3365 /* Recursively flush rules from the list, descending groups as they are     */
3366 /* encountered.  if a rule is the head of a group and it has lost all its   */
3367 /* group members, then also delete the group reference.  nfreedp is needed  */
3368 /* to store the accumulating count of rules removed, whereas the returned   */
3369 /* value is just the number removed from the current list.  The latter is   */
3370 /* needed to correctly adjust reference counts on rules that define groups. */
3371 /*                                                                          */
3372 /* NOTE: Rules not loaded from user space cannot be flushed.                */
3373 /* ------------------------------------------------------------------------ */
3374 static int frflushlist(set, unit, nfreedp, listp)
3375 int set;
3376 minor_t unit;
3377 int *nfreedp;
3378 frentry_t **listp;
3379 {
3380         int freed = 0, i;
3381         frentry_t *fp;
3382
3383         while ((fp = *listp) != NULL) {
3384                 if ((fp->fr_type & FR_T_BUILTIN) ||
3385                     !(fp->fr_flags & FR_COPIED)) {
3386                         listp = &fp->fr_next;
3387                         continue;
3388                 }
3389                 *listp = fp->fr_next;
3390                 if (fp->fr_grp != NULL) {
3391                         i = frflushlist(set, unit, nfreedp, fp->fr_grp);
3392                         fp->fr_ref -= i;
3393                 }
3394
3395                 if (fp->fr_grhead != NULL) {
3396                         fr_delgroup(fp->fr_grhead, unit, set);
3397                         *fp->fr_grhead = '\0';
3398                 }
3399
3400                 ASSERT(fp->fr_ref > 0);
3401                 fp->fr_next = NULL;
3402                 if (fr_derefrule(&fp) == 0)
3403                         freed++;
3404         }
3405         *nfreedp += freed;
3406         return freed;
3407 }
3408
3409
3410 /* ------------------------------------------------------------------------ */
3411 /* Function:    frflush                                                     */
3412 /* Returns:     int - >= 0 - number of flushed rules                        */
3413 /* Parameters:  unit(I)  - device for which to flush rules                  */
3414 /*              flags(I) - which set of rules to flush                      */
3415 /*                                                                          */
3416 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
3417 /* and IPv6) as defined by the value of flags.                              */
3418 /* ------------------------------------------------------------------------ */
3419 int frflush(unit, proto, flags)
3420 minor_t unit;
3421 int proto, flags;
3422 {
3423         int flushed = 0, set;
3424
3425         WRITE_ENTER(&ipf_mutex);
3426         bzero((char *)frcache, sizeof(frcache));
3427
3428         set = fr_active;
3429         if ((flags & FR_INACTIVE) == FR_INACTIVE)
3430                 set = 1 - set;
3431
3432         if (flags & FR_OUTQUE) {
3433                 if (proto == 0 || proto == 6) {
3434                         (void) frflushlist(set, unit,
3435                             &flushed, &ipfilter6[1][set]);
3436                         (void) frflushlist(set, unit,
3437                             &flushed, &ipacct6[1][set]);
3438                 }
3439                 if (proto == 0 || proto == 4) {
3440                         (void) frflushlist(set, unit,
3441                             &flushed, &ipfilter[1][set]);
3442                         (void) frflushlist(set, unit,
3443                             &flushed, &ipacct[1][set]);
3444                 }
3445         }
3446         if (flags & FR_INQUE) {
3447                 if (proto == 0 || proto == 6) {
3448                         (void) frflushlist(set, unit,
3449                             &flushed, &ipfilter6[0][set]);
3450                         (void) frflushlist(set, unit,
3451                             &flushed, &ipacct6[0][set]);
3452                 }
3453                 if (proto == 0 || proto == 4) {
3454                         (void) frflushlist(set, unit,
3455                             &flushed, &ipfilter[0][set]);
3456                         (void) frflushlist(set, unit,
3457                             &flushed, &ipacct[0][set]);
3458                 }
3459         }
3460         RWLOCK_EXIT(&ipf_mutex);
3461
3462         if (unit == IPL_LOGIPF) {
3463                 int tmp;
3464
3465                 tmp = frflush(IPL_LOGCOUNT, proto, flags);
3466                 if (tmp >= 0)
3467                         flushed += tmp;
3468         }
3469         return flushed;
3470 }
3471
3472
3473 /* ------------------------------------------------------------------------ */
3474 /* Function:    memstr                                                      */
3475 /* Returns:     char *  - NULL if failed, != NULL pointer to matching bytes */
3476 /* Parameters:  src(I)  - pointer to byte sequence to match                 */
3477 /*              dst(I)  - pointer to byte sequence to search                */
3478 /*              slen(I) - match length                                      */
3479 /*              dlen(I) - length available to search in                     */
3480 /*                                                                          */
3481 /* Search dst for a sequence of bytes matching those at src and extend for  */
3482 /* slen bytes.                                                              */
3483 /* ------------------------------------------------------------------------ */
3484 char *memstr(src, dst, slen, dlen)
3485 const char *src;
3486 char *dst;
3487 size_t slen, dlen;
3488 {
3489         char *s = NULL;
3490
3491         while (dlen >= slen) {
3492                 if (bcmp(src, dst, slen) == 0) {
3493                         s = dst;
3494                         break;
3495                 }
3496                 dst++;
3497                 dlen--;
3498         }
3499         return s;
3500 }
3501 /* ------------------------------------------------------------------------ */
3502 /* Function:    fr_fixskip                                                  */
3503 /* Returns:     Nil                                                         */
3504 /* Parameters:  listp(IO)    - pointer to start of list with skip rule      */
3505 /*              rp(I)        - rule added/removed with skip in it.          */
3506 /*              addremove(I) - adjustment (-1/+1) to make to skip count,    */
3507 /*                             depending on whether a rule was just added   */
3508 /*                             or removed.                                  */
3509 /*                                                                          */
3510 /* Adjust all the rules in a list which would have skip'd past the position */
3511 /* where we are inserting to skip to the right place given the change.      */
3512 /* ------------------------------------------------------------------------ */
3513 void fr_fixskip(listp, rp, addremove)
3514 frentry_t **listp, *rp;
3515 int addremove;
3516 {
3517         int rules, rn;
3518         frentry_t *fp;
3519
3520         rules = 0;
3521         for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next)
3522                 rules++;
3523
3524         if (!fp)
3525                 return;
3526
3527         for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
3528                 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules))
3529                         fp->fr_arg += addremove;
3530 }
3531
3532
3533 #ifdef  _KERNEL
3534 /* ------------------------------------------------------------------------ */
3535 /* Function:    count4bits                                                  */
3536 /* Returns:     int - >= 0 - number of consecutive bits in input            */
3537 /* Parameters:  ip(I) - 32bit IP address                                    */
3538 /*                                                                          */
3539 /* IPv4 ONLY                                                                */
3540 /* count consecutive 1's in bit mask.  If the mask generated by counting    */
3541 /* consecutive 1's is different to that passed, return -1, else return #    */
3542 /* of bits.                                                                 */
3543 /* ------------------------------------------------------------------------ */
3544 int     count4bits(ip)
3545 u_32_t  ip;
3546 {
3547         u_32_t  ipn;
3548         int     cnt = 0, i, j;
3549
3550         ip = ipn = ntohl(ip);
3551         for (i = 32; i; i--, ipn *= 2)
3552                 if (ipn & 0x80000000)
3553                         cnt++;
3554                 else
3555                         break;
3556         ipn = 0;
3557         for (i = 32, j = cnt; i; i--, j--) {
3558                 ipn *= 2;
3559                 if (j > 0)
3560                         ipn++;
3561         }
3562         if (ipn == ip)
3563                 return cnt;
3564         return -1;
3565 }
3566
3567
3568 # if 0
3569 /* ------------------------------------------------------------------------ */
3570 /* Function:    count6bits                                                  */
3571 /* Returns:     int - >= 0 - number of consecutive bits in input            */
3572 /* Parameters:  msk(I) - pointer to start of IPv6 bitmask                   */
3573 /*                                                                          */
3574 /* IPv6 ONLY                                                                */
3575 /* count consecutive 1's in bit mask.                                       */
3576 /* ------------------------------------------------------------------------ */
3577 int count6bits(msk)
3578 u_32_t *msk;
3579 {
3580         int i = 0, k;
3581         u_32_t j;
3582
3583         for (k = 3; k >= 0; k--)
3584                 if (msk[k] == 0xffffffff)
3585                         i += 32;
3586                 else {
3587                         for (j = msk[k]; j; j <<= 1)
3588                                 if (j & 0x80000000)
3589                                         i++;
3590                 }
3591         return i;
3592 }
3593 # endif
3594 #endif /* _KERNEL */
3595
3596
3597 /* ------------------------------------------------------------------------ */
3598 /* Function:    frsynclist                                                  */
3599 /* Returns:     void                                                        */
3600 /* Parameters:  fr(I)  - start of filter list to sync interface names for   */
3601 /*              ifp(I) - interface pointer for limiting sync lookups        */
3602 /* Write Locks: ipf_mutex                                                   */
3603 /*                                                                          */
3604 /* Walk through a list of filter rules and resolve any interface names into */
3605 /* pointers.  Where dynamic addresses are used, also update the IP address  */
3606 /* used in the rule.  The interface pointer is used to limit the lookups to */
3607 /* a specific set of matching names if it is non-NULL.                      */
3608 /* ------------------------------------------------------------------------ */
3609 static void frsynclist(fr, ifp)
3610 frentry_t *fr;
3611 void *ifp;
3612 {
3613         frdest_t *fdp;
3614         int v, i;
3615
3616         for (; fr; fr = fr->fr_next) {
3617                 v = fr->fr_v;
3618
3619                 /*
3620                  * Lookup all the interface names that are part of the rule.
3621                  */
3622                 for (i = 0; i < 4; i++) {
3623                         if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
3624                                 continue;
3625                         fr->fr_ifas[i] = fr_resolvenic(fr->fr_ifnames[i], v);
3626                 }
3627
3628                 if (fr->fr_type == FR_T_IPF) {
3629                         if (fr->fr_satype != FRI_NORMAL &&
3630                             fr->fr_satype != FRI_LOOKUP) {
3631                                 (void)fr_ifpaddr(v, fr->fr_satype,
3632                                                  fr->fr_ifas[fr->fr_sifpidx],
3633                                                  &fr->fr_src, &fr->fr_smsk);
3634                         }
3635                         if (fr->fr_datype != FRI_NORMAL &&
3636                             fr->fr_datype != FRI_LOOKUP) {
3637                                 (void)fr_ifpaddr(v, fr->fr_datype,
3638                                                  fr->fr_ifas[fr->fr_difpidx],
3639                                                  &fr->fr_dst, &fr->fr_dmsk);
3640                         }
3641                 }
3642
3643                 fdp = &fr->fr_tifs[0];
3644                 if ((ifp == NULL) || (fdp->fd_ifp == ifp))
3645                         fr_resolvedest(fdp, v);
3646
3647                 fdp = &fr->fr_tifs[1];
3648                 if ((ifp == NULL) || (fdp->fd_ifp == ifp))
3649                         fr_resolvedest(fdp, v);
3650
3651                 fdp = &fr->fr_dif;
3652                 if ((ifp == NULL) || (fdp->fd_ifp == ifp)) {
3653                         fr_resolvedest(fdp, v);
3654
3655                         fr->fr_flags &= ~FR_DUP;
3656                         if ((fdp->fd_ifp != (void *)-1) &&
3657                             (fdp->fd_ifp != NULL))
3658                                 fr->fr_flags |= FR_DUP;
3659                 }
3660
3661 #ifdef  IPFILTER_LOOKUP
3662                 if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP &&
3663                     fr->fr_srcptr == NULL) {
3664                         fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype,
3665                                                          fr->fr_srcnum,
3666                                                          &fr->fr_srcfunc);
3667                 }
3668                 if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP &&
3669                     fr->fr_dstptr == NULL) {
3670                         fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype,
3671                                                          fr->fr_dstnum,
3672                                                          &fr->fr_dstfunc);
3673                 }
3674 #endif
3675         }
3676 }
3677
3678
3679 #ifdef  _KERNEL
3680 /* ------------------------------------------------------------------------ */
3681 /* Function:    frsync                                                      */
3682 /* Returns:     void                                                        */
3683 /* Parameters:  Nil                                                         */
3684 /*                                                                          */
3685 /* frsync() is called when we suspect that the interface list or            */
3686 /* information about interfaces (like IP#) has changed.  Go through all     */
3687 /* filter rules, NAT entries and the state table and check if anything      */
3688 /* needs to be changed/updated.                                             */
3689 /* ------------------------------------------------------------------------ */
3690 void frsync(ifp)
3691 void *ifp;
3692 {
3693         int i;
3694
3695 # if !SOLARIS
3696         fr_natsync(ifp);
3697         fr_statesync(ifp);
3698 # endif
3699
3700         WRITE_ENTER(&ipf_mutex);
3701         frsynclist(ipacct[0][fr_active], ifp);
3702         frsynclist(ipacct[1][fr_active], ifp);
3703         frsynclist(ipfilter[0][fr_active], ifp);
3704         frsynclist(ipfilter[1][fr_active], ifp);
3705         frsynclist(ipacct6[0][fr_active], ifp);
3706         frsynclist(ipacct6[1][fr_active], ifp);
3707         frsynclist(ipfilter6[0][fr_active], ifp);
3708         frsynclist(ipfilter6[1][fr_active], ifp);
3709
3710         for (i = 0; i < IPL_LOGSIZE; i++) {
3711                 frgroup_t *g;
3712
3713                 for (g = ipfgroups[i][0]; g != NULL; g = g->fg_next)
3714                         frsynclist(g->fg_start, ifp);
3715                 for (g = ipfgroups[i][1]; g != NULL; g = g->fg_next)
3716                         frsynclist(g->fg_start, ifp);
3717         }
3718         RWLOCK_EXIT(&ipf_mutex);
3719 }
3720
3721
3722 /*
3723  * In the functions below, bcopy() is called because the pointer being
3724  * copied _from_ in this instance is a pointer to a char buf (which could
3725  * end up being unaligned) and on the kernel's local stack.
3726  */
3727 /* ------------------------------------------------------------------------ */
3728 /* Function:    copyinptr                                                   */
3729 /* Returns:     int - 0 = success, else failure                             */
3730 /* Parameters:  src(I)  - pointer to the source address                     */
3731 /*              dst(I)  - destination address                               */
3732 /*              size(I) - number of bytes to copy                           */
3733 /*                                                                          */
3734 /* Copy a block of data in from user space, given a pointer to the pointer  */
3735 /* to start copying from (src) and a pointer to where to store it (dst).    */
3736 /* NB: src - pointer to user space pointer, dst - kernel space pointer      */
3737 /* ------------------------------------------------------------------------ */
3738 int copyinptr(src, dst, size)
3739 void *src, *dst;
3740 size_t size;
3741 {
3742         caddr_t ca;
3743         int err;
3744
3745 # if SOLARIS
3746         err = COPYIN(src, (caddr_t)&ca, sizeof(ca));
3747         if (err != 0)
3748                 return err;
3749 # else
3750         bcopy(src, (caddr_t)&ca, sizeof(ca));
3751 # endif
3752         err = COPYIN(ca, dst, size);
3753         return err;
3754 }
3755
3756
3757 /* ------------------------------------------------------------------------ */
3758 /* Function:    copyoutptr                                                  */
3759 /* Returns:     int - 0 = success, else failure                             */
3760 /* Parameters:  src(I)  - pointer to the source address                     */
3761 /*              dst(I)  - destination address                               */
3762 /*              size(I) - number of bytes to copy                           */
3763 /*                                                                          */
3764 /* Copy a block of data out to user space, given a pointer to the pointer   */
3765 /* to start copying from (src) and a pointer to where to store it (dst).    */
3766 /* NB: src - kernel space pointer, dst - pointer to user space pointer.     */
3767 /* ------------------------------------------------------------------------ */
3768 int copyoutptr(src, dst, size)
3769 void *src, *dst;
3770 size_t size;
3771 {
3772         caddr_t ca;
3773         int err;
3774
3775         bcopy(dst, (caddr_t)&ca, sizeof(ca));
3776         err = COPYOUT(src, ca, size);
3777         return err;
3778 }
3779 #endif
3780
3781
3782 /* ------------------------------------------------------------------------ */
3783 /* Function:    fr_lock                                                     */
3784 /* Returns:     (void)                                                      */
3785 /* Parameters:  data(I)  - pointer to lock value to set                     */
3786 /*              lockp(O) - pointer to location to store old lock value      */
3787 /*                                                                          */
3788 /* Get the new value for the lock integer, set it and return the old value  */
3789 /* in *lockp.                                                               */
3790 /* ------------------------------------------------------------------------ */
3791 void fr_lock(data, lockp)
3792 caddr_t data;
3793 int *lockp;
3794 {
3795         int arg;
3796
3797         BCOPYIN(data, (caddr_t)&arg, sizeof(arg));
3798         BCOPYOUT((caddr_t)lockp, data, sizeof(*lockp));
3799         *lockp = arg;
3800 }
3801
3802
3803 /* ------------------------------------------------------------------------ */
3804 /* Function:    fr_getstat                                                  */
3805 /* Returns:     Nil                                                         */
3806 /* Parameters:  fiop(I)  - pointer to ipfilter stats structure              */
3807 /*                                                                          */
3808 /* Stores a copy of current pointers, counters, etc, in the friostat        */
3809 /* structure.                                                               */
3810 /* ------------------------------------------------------------------------ */
3811 void fr_getstat(fiop)
3812 friostat_t *fiop;
3813 {
3814         int i, j;
3815
3816         bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2);
3817         fiop->f_locks[IPL_LOGSTATE] = fr_state_lock;
3818         fiop->f_locks[IPL_LOGNAT] = fr_nat_lock;
3819         fiop->f_locks[IPL_LOGIPF] = fr_frag_lock;
3820         fiop->f_locks[IPL_LOGAUTH] = fr_auth_lock;
3821
3822         for (i = 0; i < 2; i++)
3823                 for (j = 0; j < 2; j++) {
3824                         fiop->f_ipf[i][j] = ipfilter[i][j];
3825                         fiop->f_acct[i][j] = ipacct[i][j];
3826                         fiop->f_ipf6[i][j] = ipfilter6[i][j];
3827                         fiop->f_acct6[i][j] = ipacct6[i][j];
3828                 }
3829
3830         fiop->f_ticks = fr_ticks;
3831         fiop->f_active = fr_active;
3832         fiop->f_froute[0] = fr_frouteok[0];
3833         fiop->f_froute[1] = fr_frouteok[1];
3834
3835         fiop->f_running = fr_running;
3836         for (i = 0; i < IPL_LOGSIZE; i++) {
3837                 fiop->f_groups[i][0] = ipfgroups[i][0];
3838                 fiop->f_groups[i][1] = ipfgroups[i][1];
3839         }
3840 #ifdef  IPFILTER_LOG
3841         fiop->f_logging = 1;
3842 #else
3843         fiop->f_logging = 0;
3844 #endif
3845         fiop->f_defpass = fr_pass;
3846         fiop->f_features = fr_features;
3847         (void) strncpy(fiop->f_version, ipfilter_version,
3848                        sizeof(fiop->f_version));
3849 }
3850
3851
3852 #ifdef  USE_INET6
3853 int icmptoicmp6types[ICMP_MAXTYPE+1] = {
3854         ICMP6_ECHO_REPLY,       /* 0: ICMP_ECHOREPLY */
3855         -1,                     /* 1: UNUSED */
3856         -1,                     /* 2: UNUSED */
3857         ICMP6_DST_UNREACH,      /* 3: ICMP_UNREACH */
3858         -1,                     /* 4: ICMP_SOURCEQUENCH */
3859         ND_REDIRECT,            /* 5: ICMP_REDIRECT */
3860         -1,                     /* 6: UNUSED */
3861         -1,                     /* 7: UNUSED */
3862         ICMP6_ECHO_REQUEST,     /* 8: ICMP_ECHO */
3863         -1,                     /* 9: UNUSED */
3864         -1,                     /* 10: UNUSED */
3865         ICMP6_TIME_EXCEEDED,    /* 11: ICMP_TIMXCEED */
3866         ICMP6_PARAM_PROB,       /* 12: ICMP_PARAMPROB */
3867         -1,                     /* 13: ICMP_TSTAMP */
3868         -1,                     /* 14: ICMP_TSTAMPREPLY */
3869         -1,                     /* 15: ICMP_IREQ */
3870         -1,                     /* 16: ICMP_IREQREPLY */
3871         -1,                     /* 17: ICMP_MASKREQ */
3872         -1,                     /* 18: ICMP_MASKREPLY */
3873 };
3874
3875
3876 int     icmptoicmp6unreach[ICMP_MAX_UNREACH] = {
3877         ICMP6_DST_UNREACH_ADDR,         /* 0: ICMP_UNREACH_NET */
3878         ICMP6_DST_UNREACH_ADDR,         /* 1: ICMP_UNREACH_HOST */
3879         -1,                             /* 2: ICMP_UNREACH_PROTOCOL */
3880         ICMP6_DST_UNREACH_NOPORT,       /* 3: ICMP_UNREACH_PORT */
3881         -1,                             /* 4: ICMP_UNREACH_NEEDFRAG */
3882         ICMP6_DST_UNREACH_NOTNEIGHBOR,  /* 5: ICMP_UNREACH_SRCFAIL */
3883         ICMP6_DST_UNREACH_ADDR,         /* 6: ICMP_UNREACH_NET_UNKNOWN */
3884         ICMP6_DST_UNREACH_ADDR,         /* 7: ICMP_UNREACH_HOST_UNKNOWN */
3885         -1,                             /* 8: ICMP_UNREACH_ISOLATED */
3886         ICMP6_DST_UNREACH_ADMIN,        /* 9: ICMP_UNREACH_NET_PROHIB */
3887         ICMP6_DST_UNREACH_ADMIN,        /* 10: ICMP_UNREACH_HOST_PROHIB */
3888         -1,                             /* 11: ICMP_UNREACH_TOSNET */
3889         -1,                             /* 12: ICMP_UNREACH_TOSHOST */
3890         ICMP6_DST_UNREACH_ADMIN,        /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
3891 };
3892 int     icmpreplytype6[ICMP6_MAXTYPE + 1];
3893 #endif
3894
3895 int     icmpreplytype4[ICMP_MAXTYPE + 1];
3896
3897
3898 /* ------------------------------------------------------------------------ */
3899 /* Function:    fr_matchicmpqueryreply                                      */
3900 /* Returns:     int - 1 if "icmp" is a valid reply to "ic" else 0.          */
3901 /* Parameters:  v(I)    - IP protocol version (4 or 6)                      */
3902 /*              ic(I)   - ICMP information                                  */
3903 /*              icmp(I) - ICMP packet header                                */
3904 /*              rev(I)  - direction (0 = forward/1 = reverse) of packet     */
3905 /*                                                                          */
3906 /* Check if the ICMP packet defined by the header pointed to by icmp is a   */
3907 /* reply to one as described by what's in ic.  If it is a match, return 1,  */
3908 /* else return 0 for no match.                                              */
3909 /* ------------------------------------------------------------------------ */
3910 int fr_matchicmpqueryreply(v, ic, icmp, rev)
3911 int v;
3912 icmpinfo_t *ic;
3913 icmphdr_t *icmp;
3914 int rev;
3915 {
3916         int ictype;
3917
3918         ictype = ic->ici_type;
3919
3920         if (v == 4) {
3921                 /*
3922                  * If we matched its type on the way in, then when going out
3923                  * it will still be the same type.
3924                  */
3925                 if ((!rev && (icmp->icmp_type == ictype)) ||
3926                     (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) {
3927                         if (icmp->icmp_type != ICMP_ECHOREPLY)
3928                                 return 1;
3929                         if (icmp->icmp_id == ic->ici_id)
3930                                 return 1;
3931                 }
3932         }
3933 #ifdef  USE_INET6
3934         else if (v == 6) {
3935                 if ((!rev && (icmp->icmp_type == ictype)) ||
3936                     (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) {
3937                         if (icmp->icmp_type != ICMP6_ECHO_REPLY)
3938                                 return 1;
3939                         if (icmp->icmp_id == ic->ici_id)
3940                                 return 1;
3941                 }
3942         }
3943 #endif
3944         return 0;
3945 }
3946
3947
3948 #ifdef  IPFILTER_LOOKUP
3949 /* ------------------------------------------------------------------------ */
3950 /* Function:    fr_resolvelookup                                            */
3951 /* Returns:     void * - NULL = failure, else success.                      */
3952 /* Parameters:  type(I)     - type of lookup these parameters are for.      */
3953 /*              number(I)   - table number to use when searching            */
3954 /*              funcptr(IO) - pointer to pointer for storing IP address     */
3955 /*                           searching function.                            */
3956 /*                                                                          */
3957 /* Search for the "table" number passed in amongst those configured for     */
3958 /* that particular type.  If the type is recognised then the function to    */
3959 /* call to do the IP address search will be change, regardless of whether   */
3960 /* or not the "table" number exists.                                        */
3961 /* ------------------------------------------------------------------------ */
3962 static void *fr_resolvelookup(type, number, funcptr)
3963 u_int type, number;
3964 lookupfunc_t *funcptr;
3965 {
3966         char name[FR_GROUPLEN];
3967         iphtable_t *iph;
3968         ip_pool_t *ipo;
3969         void *ptr;
3970
3971 #if defined(SNPRINTF) && defined(_KERNEL)
3972         SNPRINTF(name, sizeof(name), "%u", number);
3973 #else
3974         (void) sprintf(name, "%u", number);
3975 #endif
3976
3977         READ_ENTER(&ip_poolrw);
3978
3979         switch (type)
3980         {
3981         case IPLT_POOL :
3982 # if (defined(__osf__) && defined(_KERNEL))
3983                 ptr = NULL;
3984                 *funcptr = NULL;
3985 # else
3986                 ipo = ip_pool_find(IPL_LOGIPF, name);
3987                 ptr = ipo;
3988                 if (ipo != NULL) {
3989                         ATOMIC_INC32(ipo->ipo_ref);
3990                 }
3991                 *funcptr = ip_pool_search;
3992 # endif
3993                 break;
3994         case IPLT_HASH :
3995                 iph = fr_findhtable(IPL_LOGIPF, name);
3996                 ptr = iph;
3997                 if (iph != NULL) {
3998                         ATOMIC_INC32(iph->iph_ref);
3999                 }
4000                 *funcptr = fr_iphmfindip;
4001                 break;
4002         default:
4003                 ptr = NULL;
4004                 *funcptr = NULL;
4005                 break;
4006         }
4007         RWLOCK_EXIT(&ip_poolrw);
4008
4009         return ptr;
4010 }
4011 #endif
4012
4013
4014 /* ------------------------------------------------------------------------ */
4015 /* Function:    frrequest                                                   */
4016 /* Returns:     int - 0 == success, > 0 == errno value                      */
4017 /* Parameters:  unit(I)     - device for which this is for                  */
4018 /*              req(I)      - ioctl command (SIOC*)                         */
4019 /*              data(I)     - pointr to ioctl data                          */
4020 /*              set(I)      - 1 or 0 (filter set)                           */
4021 /*              makecopy(I) - flag indicating whether data points to a rule */
4022 /*                            in kernel space & hence doesn't need copying. */
4023 /*                                                                          */
4024 /* This function handles all the requests which operate on the list of      */
4025 /* filter rules.  This includes adding, deleting, insertion.  It is also    */
4026 /* responsible for creating groups when a "head" rule is loaded.  Interface */
4027 /* names are resolved here and other sanity checks are made on the content  */
4028 /* of the rule structure being loaded.  If a rule has user defined timeouts */
4029 /* then make sure they are created and initialised before exiting.          */
4030 /* ------------------------------------------------------------------------ */
4031 int frrequest(unit, req, data, set, makecopy)
4032 int unit;
4033 ioctlcmd_t req;
4034 int set, makecopy;
4035 caddr_t data;
4036 {
4037         frentry_t frd, *fp, *f, **fprev, **ftail;
4038         int error = 0, in, v;
4039         void *ptr, *uptr;
4040         u_int *p, *pp;
4041         frgroup_t *fg;
4042         char *group;
4043
4044         fg = NULL;
4045         fp = &frd;
4046         if (makecopy != 0) {
4047                 error = fr_inobj(data, fp, IPFOBJ_FRENTRY);
4048                 if (error)
4049                         return EFAULT;
4050                 if ((fp->fr_flags & FR_T_BUILTIN) != 0)
4051                         return EINVAL;
4052                 fp->fr_ref = 0;
4053                 fp->fr_flags |= FR_COPIED;
4054         } else {
4055                 fp = (frentry_t *)data;
4056                 if ((fp->fr_type & FR_T_BUILTIN) == 0)
4057                         return EINVAL;
4058                 fp->fr_flags &= ~FR_COPIED;
4059         }
4060
4061         if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
4062             ((fp->fr_dsize != 0) && (fp->fr_data == NULL)))
4063                 return EINVAL;
4064
4065         v = fp->fr_v;
4066         uptr = fp->fr_data;
4067
4068         /*
4069          * Only filter rules for IPv4 or IPv6 are accepted.
4070          */
4071         if (v == 4)
4072                 /*EMPTY*/;
4073 #ifdef  USE_INET6
4074         else if (v == 6)
4075                 /*EMPTY*/;
4076 #endif
4077         else {
4078                 return EINVAL;
4079         }
4080
4081         /*
4082          * If the rule is being loaded from user space, i.e. we had to copy it
4083          * into kernel space, then do not trust the function pointer in the
4084          * rule.
4085          */
4086         if ((makecopy == 1) && (fp->fr_func != NULL)) {
4087                 if (fr_findfunc(fp->fr_func) == NULL)
4088                         return ESRCH;
4089                 error = fr_funcinit(fp);
4090                 if (error != 0)
4091                         return error;
4092         }
4093
4094         ptr = NULL;
4095         /*
4096          * Check that the group number does exist and that its use (in/out)
4097          * matches what the rule is.
4098          */
4099         if (!strncmp(fp->fr_grhead, "0", FR_GROUPLEN))
4100                 *fp->fr_grhead = '\0';
4101         group = fp->fr_group;
4102         if (!strncmp(group, "0", FR_GROUPLEN))
4103                 *group = '\0';
4104
4105         if (FR_ISACCOUNT(fp->fr_flags))
4106                 unit = IPL_LOGCOUNT;
4107
4108         if ((req != (int)SIOCZRLST) && (*group != '\0')) {
4109                 fg = fr_findgroup(group, unit, set, NULL);
4110                 if (fg == NULL)
4111                         return ESRCH;
4112                 if (fg->fg_flags == 0)
4113                         fg->fg_flags = fp->fr_flags & FR_INOUT;
4114                 else if (fg->fg_flags != (fp->fr_flags & FR_INOUT))
4115                         return ESRCH;
4116         }
4117
4118         in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
4119
4120         /*
4121          * Work out which rule list this change is being applied to.
4122          */
4123         ftail = NULL;
4124         fprev = NULL;
4125         if (unit == IPL_LOGAUTH)
4126                 fprev = &ipauth;
4127         else if (v == 4) {
4128                 if (FR_ISACCOUNT(fp->fr_flags))
4129                         fprev = &ipacct[in][set];
4130                 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
4131                         fprev = &ipfilter[in][set];
4132         } else if (v == 6) {
4133                 if (FR_ISACCOUNT(fp->fr_flags))
4134                         fprev = &ipacct6[in][set];
4135                 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
4136                         fprev = &ipfilter6[in][set];
4137         }
4138         if (fprev == NULL)
4139                 return ESRCH;
4140
4141         if (*group != '\0') {
4142                 if (!fg && !(fg = fr_findgroup(group, unit, set, NULL)))
4143                         return ESRCH;
4144                 fprev = &fg->fg_start;
4145         }
4146
4147         ftail = fprev;
4148         for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) {
4149                 if (fp->fr_collect <= f->fr_collect) {
4150                         ftail = fprev;
4151                         f = NULL;
4152                         break;
4153                 }
4154                 fprev = ftail;
4155         }
4156
4157         /*
4158          * Copy in extra data for the rule.
4159          */
4160         if (fp->fr_dsize != 0) {
4161                 if (makecopy != 0) {
4162                         KMALLOCS(ptr, void *, fp->fr_dsize);
4163                         if (!ptr)
4164                                 return ENOMEM;
4165                         error = COPYIN(uptr, ptr, fp->fr_dsize);
4166                 } else {
4167                         ptr = uptr;
4168                         error = 0;
4169                 }
4170                 if (error != 0) {
4171                         KFREES(ptr, fp->fr_dsize);
4172                         return ENOMEM;
4173                 }
4174                 fp->fr_data = ptr;
4175         } else
4176                 fp->fr_data = NULL;
4177
4178         /*
4179          * Perform per-rule type sanity checks of their members.
4180          */
4181         switch (fp->fr_type & ~FR_T_BUILTIN)
4182         {
4183 #if defined(IPFILTER_BPF)
4184         case FR_T_BPFOPC :
4185                 if (fp->fr_dsize == 0)
4186                         return EINVAL;
4187                 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
4188                         if (makecopy && fp->fr_data != NULL) {
4189                                 KFREES(fp->fr_data, fp->fr_dsize);
4190                         }
4191                         return EINVAL;
4192                 }
4193                 break;
4194 #endif
4195         case FR_T_IPF :
4196                 if (fp->fr_dsize != sizeof(fripf_t))
4197                         return EINVAL;
4198
4199                 /*
4200                  * Allowing a rule with both "keep state" and "with oow" is
4201                  * pointless because adding a state entry to the table will
4202                  * fail with the out of window (oow) flag set.
4203                  */
4204                 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW))
4205                         return EINVAL;
4206
4207                 switch (fp->fr_satype)
4208                 {
4209                 case FRI_BROADCAST :
4210                 case FRI_DYNAMIC :
4211                 case FRI_NETWORK :
4212                 case FRI_NETMASKED :
4213                 case FRI_PEERADDR :
4214                         if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) {
4215                                 if (makecopy && fp->fr_data != NULL) {
4216                                         KFREES(fp->fr_data, fp->fr_dsize);
4217                                 }
4218                                 return EINVAL;
4219                         }
4220                         break;
4221 #ifdef  IPFILTER_LOOKUP
4222                 case FRI_LOOKUP :
4223                         fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype,
4224                                                          fp->fr_srcnum,
4225                                                          &fp->fr_srcfunc);
4226                         break;
4227 #endif
4228                 default :
4229                         break;
4230                 }
4231
4232                 switch (fp->fr_datype)
4233                 {
4234                 case FRI_BROADCAST :
4235                 case FRI_DYNAMIC :
4236                 case FRI_NETWORK :
4237                 case FRI_NETMASKED :
4238                 case FRI_PEERADDR :
4239                         if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) {
4240                                 if (makecopy && fp->fr_data != NULL) {
4241                                         KFREES(fp->fr_data, fp->fr_dsize);
4242                                 }
4243                                 return EINVAL;
4244                         }
4245                         break;
4246 #ifdef  IPFILTER_LOOKUP
4247                 case FRI_LOOKUP :
4248                         fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype,
4249                                                          fp->fr_dstnum,
4250                                                          &fp->fr_dstfunc);
4251                         break;
4252 #endif
4253                 default :
4254                         break;
4255                 }
4256                 break;
4257         case FR_T_NONE :
4258                 break;
4259         case FR_T_CALLFUNC :
4260                 break;
4261         case FR_T_COMPIPF :
4262                 break;
4263         default :
4264                 if (makecopy && fp->fr_data != NULL) {
4265                         KFREES(fp->fr_data, fp->fr_dsize);
4266                 }
4267                 return EINVAL;
4268         }
4269
4270         /*
4271          * Lookup all the interface names that are part of the rule.
4272          */
4273         frsynclist(fp, NULL);
4274         fp->fr_statecnt = 0;
4275
4276         /*
4277          * Look for an existing matching filter rule, but don't include the
4278          * next or interface pointer in the comparison (fr_next, fr_ifa).
4279          * This elminates rules which are indentical being loaded.  Checksum
4280          * the constant part of the filter rule to make comparisons quicker
4281          * (this meaning no pointers are included).
4282          */
4283         for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum;
4284              p < pp; p++)
4285                 fp->fr_cksum += *p;
4286         pp = (u_int *)(fp->fr_caddr + fp->fr_dsize);
4287         for (p = (u_int *)fp->fr_data; p < pp; p++)
4288                 fp->fr_cksum += *p;
4289
4290         WRITE_ENTER(&ipf_mutex);
4291         bzero((char *)frcache, sizeof(frcache));
4292
4293         for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
4294                 if ((fp->fr_cksum != f->fr_cksum) ||
4295                     (f->fr_dsize != fp->fr_dsize))
4296                         continue;
4297                 if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ))
4298                         continue;
4299                 if ((!ptr && !f->fr_data) ||
4300                     (ptr && f->fr_data &&
4301                      !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize)))
4302                         break;
4303         }
4304
4305         /*
4306          * If zero'ing statistics, copy current to caller and zero.
4307          */
4308         if (req == (ioctlcmd_t)SIOCZRLST) {
4309                 if (f == NULL)
4310                         error = ESRCH;
4311                 else {
4312                         /*
4313                          * Copy and reduce lock because of impending copyout.
4314                          * Well we should, but if we do then the atomicity of
4315                          * this call and the correctness of fr_hits and
4316                          * fr_bytes cannot be guaranteed.  As it is, this code
4317                          * only resets them to 0 if they are successfully
4318                          * copied out into user space.
4319                          */
4320                         bcopy((char *)f, (char *)fp, sizeof(*f));
4321                         /* MUTEX_DOWNGRADE(&ipf_mutex); */
4322
4323                         /*
4324                          * When we copy this rule back out, set the data
4325                          * pointer to be what it was in user space.
4326                          */
4327                         fp->fr_data = uptr;
4328                         error = fr_outobj(data, fp, IPFOBJ_FRENTRY);
4329
4330                         if (error == 0) {
4331                                 if ((f->fr_dsize != 0) && (uptr != NULL))
4332                                         error = COPYOUT(f->fr_data, uptr,
4333                                                         f->fr_dsize);
4334                                 if (error == 0) {
4335                                         f->fr_hits = 0;
4336                                         f->fr_bytes = 0;
4337                                 }
4338                         }
4339                 }
4340
4341                 if ((ptr != NULL) && (makecopy != 0)) {
4342                         KFREES(ptr, fp->fr_dsize);
4343                 }
4344                 RWLOCK_EXIT(&ipf_mutex);
4345                 return error;
4346         }
4347
4348         if (!f) {
4349                 /*
4350                  * At the end of this, ftail must point to the place where the
4351                  * new rule is to be saved/inserted/added.
4352                  * For SIOCAD*FR, this should be the last rule in the group of
4353                  * rules that have equal fr_collect fields.
4354                  * For SIOCIN*FR, ...
4355                  */
4356                 if (req == (ioctlcmd_t)SIOCADAFR ||
4357                     req == (ioctlcmd_t)SIOCADIFR) {
4358
4359                         for (ftail = fprev; (f = *ftail) != NULL; ) {
4360                                 if (f->fr_collect > fp->fr_collect)
4361                                         break;
4362                                 ftail = &f->fr_next;
4363                         }
4364                         f = NULL;
4365                         ptr = NULL;
4366                         error = 0;
4367                 } else if (req == (ioctlcmd_t)SIOCINAFR ||
4368                            req == (ioctlcmd_t)SIOCINIFR) {
4369                         while ((f = *fprev) != NULL) {
4370                                 if (f->fr_collect >= fp->fr_collect)
4371                                         break;
4372                                 fprev = &f->fr_next;
4373                         }
4374                         ftail = fprev;
4375                         if (fp->fr_hits != 0) {
4376                                 while (fp->fr_hits && (f = *ftail)) {
4377                                         if (f->fr_collect != fp->fr_collect)
4378                                                 break;
4379                                         fprev = ftail;
4380                                         ftail = &f->fr_next;
4381                                         fp->fr_hits--;
4382                                 }
4383                         }
4384                         f = NULL;
4385                         ptr = NULL;
4386                         error = 0;
4387                 }
4388         }
4389
4390         /*
4391          * Request to remove a rule.
4392          */
4393         if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) {
4394                 if (!f)
4395                         error = ESRCH;
4396                 else {
4397                         /*
4398                          * Do not allow activity from user space to interfere
4399                          * with rules not loaded that way.
4400                          */
4401                         if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
4402                                 error = EPERM;
4403                                 goto done;
4404                         }
4405
4406                         /*
4407                          * Return EBUSY if the rule is being reference by
4408                          * something else (eg state information.
4409                          */
4410                         if (f->fr_ref > 1) {
4411                                 error = EBUSY;
4412                                 goto done;
4413                         }
4414 #ifdef  IPFILTER_SCAN
4415                         if (f->fr_isctag[0] != '\0' &&
4416                             (f->fr_isc != (struct ipscan *)-1))
4417                                 ipsc_detachfr(f);
4418 #endif
4419                         if ((fg != NULL) && (fg->fg_head != NULL))
4420                                 fg->fg_head->fr_ref--;
4421                         if (unit == IPL_LOGAUTH) {
4422                                 error = fr_preauthcmd(req, f, ftail);
4423                                 goto done;
4424                         }
4425                         if (*f->fr_grhead != '\0')
4426                                 fr_delgroup(f->fr_grhead, unit, set);
4427                         fr_fixskip(ftail, f, -1);
4428                         *ftail = f->fr_next;
4429                         f->fr_next = NULL;
4430                         (void)fr_derefrule(&f);
4431                 }
4432         } else {
4433                 /*
4434                  * Not removing, so we must be adding/inserting a rule.
4435                  */
4436                 if (f)
4437                         error = EEXIST;
4438                 else {
4439                         if (unit == IPL_LOGAUTH) {
4440                                 error = fr_preauthcmd(req, fp, ftail);
4441                                 goto done;
4442                         }
4443                         if (makecopy) {
4444                                 KMALLOC(f, frentry_t *);
4445                         } else
4446                                 f = fp;
4447                         if (f != NULL) {
4448                                 if (fg != NULL && fg->fg_head != NULL)
4449                                         fg->fg_head->fr_ref++;
4450                                 if (fp != f)
4451                                         bcopy((char *)fp, (char *)f,
4452                                               sizeof(*f));
4453                                 MUTEX_NUKE(&f->fr_lock);
4454                                 MUTEX_INIT(&f->fr_lock, "filter rule lock");
4455 #ifdef  IPFILTER_SCAN
4456                                 if (f->fr_isctag[0] != '\0' &&
4457                                     ipsc_attachfr(f))
4458                                         f->fr_isc = (struct ipscan *)-1;
4459 #endif
4460                                 f->fr_hits = 0;
4461                                 if (makecopy != 0)
4462                                         f->fr_ref = 1;
4463                                 f->fr_next = *ftail;
4464                                 *ftail = f;
4465                                 if (req == (ioctlcmd_t)SIOCINIFR ||
4466                                     req == (ioctlcmd_t)SIOCINAFR)
4467                                         fr_fixskip(ftail, f, 1);
4468                                 f->fr_grp = NULL;
4469                                 group = f->fr_grhead;
4470                                 if (*group != '\0') {
4471                                         fg = fr_addgroup(group, f, f->fr_flags,
4472                                                          unit, set);
4473                                         if (fg != NULL)
4474                                                 f->fr_grp = &fg->fg_start;
4475                                 }
4476                         } else
4477                                 error = ENOMEM;
4478                 }
4479         }
4480 done:
4481         RWLOCK_EXIT(&ipf_mutex);
4482         if ((ptr != NULL) && (error != 0) && (makecopy != 0)) {
4483                 KFREES(ptr, fp->fr_dsize);
4484         }
4485         return (error);
4486 }
4487
4488
4489 /* ------------------------------------------------------------------------ */
4490 /* Function:    fr_funcinit                                                 */
4491 /* Returns:     int - 0 == success, else ESRCH: cannot resolve rule details */
4492 /* Parameters:  fr(I) - pointer to filter rule                              */
4493 /*                                                                          */
4494 /* If a rule is a call rule, then check if the function it points to needs  */
4495 /* an init function to be called now the rule has been loaded.              */
4496 /* ------------------------------------------------------------------------ */
4497 static int fr_funcinit(fr)
4498 frentry_t *fr;
4499 {
4500         ipfunc_resolve_t *ft;
4501         int err;
4502
4503         err = ESRCH;
4504
4505         for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
4506                 if (ft->ipfu_addr == fr->fr_func) {
4507                         err = 0;
4508                         if (ft->ipfu_init != NULL)
4509                                 err = (*ft->ipfu_init)(fr);
4510                         break;
4511                 }
4512         return err;
4513 }
4514
4515
4516 /* ------------------------------------------------------------------------ */
4517 /* Function:    fr_findfunc                                                 */
4518 /* Returns:     ipfunc_t - pointer to function if found, else NULL          */
4519 /* Parameters:  funcptr(I) - function pointer to lookup                     */
4520 /*                                                                          */
4521 /* Look for a function in the table of known functions.                     */
4522 /* ------------------------------------------------------------------------ */
4523 static ipfunc_t fr_findfunc(funcptr)
4524 ipfunc_t funcptr;
4525 {
4526         ipfunc_resolve_t *ft;
4527
4528         for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
4529                 if (ft->ipfu_addr == funcptr)
4530                         return funcptr;
4531         return NULL;
4532 }
4533
4534
4535 /* ------------------------------------------------------------------------ */
4536 /* Function:    fr_resolvefunc                                              */
4537 /* Returns:     int - 0 == success, else error                              */
4538 /* Parameters:  data(IO) - ioctl data pointer to ipfunc_resolve_t struct    */
4539 /*                                                                          */
4540 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */
4541 /* This will either be the function name (if the pointer is set) or the     */
4542 /* function pointer if the name is set.  When found, fill in the other one  */
4543 /* so that the entire, complete, structure can be copied back to user space.*/
4544 /* ------------------------------------------------------------------------ */
4545 int fr_resolvefunc(data)
4546 void *data;
4547 {
4548         ipfunc_resolve_t res, *ft;
4549
4550         BCOPYIN(data, &res, sizeof(res));
4551
4552         if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
4553                 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
4554                         if (strncmp(res.ipfu_name, ft->ipfu_name,
4555                                     sizeof(res.ipfu_name)) == 0) {
4556                                 res.ipfu_addr = ft->ipfu_addr;
4557                                 res.ipfu_init = ft->ipfu_init;
4558                                 if (COPYOUT(&res, data, sizeof(res)) != 0)
4559                                         return EFAULT;
4560                                 return 0;
4561                         }
4562         }
4563         if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
4564                 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
4565                         if (ft->ipfu_addr == res.ipfu_addr) {
4566                                 (void) strncpy(res.ipfu_name, ft->ipfu_name,
4567                                                sizeof(res.ipfu_name));
4568                                 res.ipfu_init = ft->ipfu_init;
4569                                 if (COPYOUT(&res, data, sizeof(res)) != 0)
4570                                         return EFAULT;
4571                                 return 0;
4572                         }
4573         }
4574         return ESRCH;
4575 }
4576
4577
4578 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \
4579     (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \
4580     (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \
4581     (defined(__OpenBSD__) && (OpenBSD < 200006))
4582 /*
4583  * From: NetBSD
4584  * ppsratecheck(): packets (or events) per second limitation.
4585  */
4586 int
4587 ppsratecheck(lasttime, curpps, maxpps)
4588         struct timeval *lasttime;
4589         int *curpps;
4590         int maxpps;     /* maximum pps allowed */
4591 {
4592         struct timeval tv, delta;
4593         int rv;
4594
4595         GETKTIME(&tv);
4596
4597         delta.tv_sec = tv.tv_sec - lasttime->tv_sec;
4598         delta.tv_usec = tv.tv_usec - lasttime->tv_usec;
4599         if (delta.tv_usec < 0) {
4600                 delta.tv_sec--;
4601                 delta.tv_usec += 1000000;
4602         }
4603
4604         /*
4605          * check for 0,0 is so that the message will be seen at least once.
4606          * if more than one second have passed since the last update of
4607          * lasttime, reset the counter.
4608          *
4609          * we do increment *curpps even in *curpps < maxpps case, as some may
4610          * try to use *curpps for stat purposes as well.
4611          */
4612         if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
4613             delta.tv_sec >= 1) {
4614                 *lasttime = tv;
4615                 *curpps = 0;
4616                 rv = 1;
4617         } else if (maxpps < 0)
4618                 rv = 1;
4619         else if (*curpps < maxpps)
4620                 rv = 1;
4621         else
4622                 rv = 0;
4623         *curpps = *curpps + 1;
4624
4625         return (rv);
4626 }
4627 #endif
4628
4629
4630 /* ------------------------------------------------------------------------ */
4631 /* Function:    fr_derefrule                                                */
4632 /* Returns:     int   - 0 == rule freed up, else rule not freed             */
4633 /* Parameters:  fr(I) - pointer to filter rule                              */
4634 /*                                                                          */
4635 /* Decrement the reference counter to a rule by one.  If it reaches zero,   */
4636 /* free it and any associated storage space being used by it.               */
4637 /* ------------------------------------------------------------------------ */
4638 int fr_derefrule(frp)
4639 frentry_t **frp;
4640 {
4641         frentry_t *fr;
4642
4643         fr = *frp;
4644
4645         MUTEX_ENTER(&fr->fr_lock);
4646         fr->fr_ref--;
4647         if (fr->fr_ref == 0) {
4648                 MUTEX_EXIT(&fr->fr_lock);
4649                 MUTEX_DESTROY(&fr->fr_lock);
4650
4651 #ifdef IPFILTER_LOOKUP
4652                 if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP)
4653                         ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr);
4654                 if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP)
4655                         ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr);
4656 #endif
4657
4658                 if (fr->fr_dsize) {
4659                         KFREES(fr->fr_data, fr->fr_dsize);
4660                 }
4661                 if ((fr->fr_flags & FR_COPIED) != 0) {
4662                         KFREE(fr);
4663                         return 0;
4664                 }
4665                 return 1;
4666         } else {
4667                 MUTEX_EXIT(&fr->fr_lock);
4668         }
4669         *frp = NULL;
4670         return -1;
4671 }
4672
4673
4674 #ifdef  IPFILTER_LOOKUP
4675 /* ------------------------------------------------------------------------ */
4676 /* Function:    fr_grpmapinit                                               */
4677 /* Returns:     int - 0 == success, else ESRCH because table entry not found*/
4678 /* Parameters:  fr(I) - pointer to rule to find hash table for              */
4679 /*                                                                          */
4680 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr.  */
4681 /* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap.                   */
4682 /* ------------------------------------------------------------------------ */
4683 static int fr_grpmapinit(fr)
4684 frentry_t *fr;
4685 {
4686         char name[FR_GROUPLEN];
4687         iphtable_t *iph;
4688
4689 #if defined(SNPRINTF) && defined(_KERNEL)
4690         SNPRINTF(name, sizeof(name), "%d", fr->fr_arg);
4691 #else
4692         (void) sprintf(name, "%d", fr->fr_arg);
4693 #endif
4694         iph = fr_findhtable(IPL_LOGIPF, name);
4695         if (iph == NULL)
4696                 return ESRCH;
4697         if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT))
4698                 return ESRCH;
4699         fr->fr_ptr = iph;
4700         return 0;
4701 }
4702
4703
4704 /* ------------------------------------------------------------------------ */
4705 /* Function:    fr_srcgrpmap                                                */
4706 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
4707 /* Parameters:  fin(I)    - pointer to packet information                   */
4708 /*              passp(IO) - pointer to current/new filter decision (unused) */
4709 /*                                                                          */
4710 /* Look for a rule group head in a hash table, using the source address as  */
4711 /* the key, and descend into that group and continue matching rules against */
4712 /* the packet.                                                              */
4713 /* ------------------------------------------------------------------------ */
4714 frentry_t *fr_srcgrpmap(fin, passp)
4715 fr_info_t *fin;
4716 u_32_t *passp;
4717 {
4718         frgroup_t *fg;
4719         void *rval;
4720
4721         rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_src);
4722         if (rval == NULL)
4723                 return NULL;
4724
4725         fg = rval;
4726         fin->fin_fr = fg->fg_start;
4727         (void) fr_scanlist(fin, *passp);
4728         return fin->fin_fr;
4729 }
4730
4731
4732 /* ------------------------------------------------------------------------ */
4733 /* Function:    fr_dstgrpmap                                                */
4734 /* Returns:     frentry_t * - pointer to "new last matching" rule or NULL   */
4735 /* Parameters:  fin(I)    - pointer to packet information                   */
4736 /*              passp(IO) - pointer to current/new filter decision (unused) */
4737 /*                                                                          */
4738 /* Look for a rule group head in a hash table, using the destination        */
4739 /* address as the key, and descend into that group and continue matching    */
4740 /* rules against  the packet.                                               */
4741 /* ------------------------------------------------------------------------ */
4742 frentry_t *fr_dstgrpmap(fin, passp)
4743 fr_info_t *fin;
4744 u_32_t *passp;
4745 {
4746         frgroup_t *fg;
4747         void *rval;
4748
4749         rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_dst);
4750         if (rval == NULL)
4751                 return NULL;
4752
4753         fg = rval;
4754         fin->fin_fr = fg->fg_start;
4755         (void) fr_scanlist(fin, *passp);
4756         return fin->fin_fr;
4757 }
4758 #endif /* IPFILTER_LOOKUP */
4759
4760 /*
4761  * Queue functions
4762  * ===============
4763  * These functions manage objects on queues for efficient timeouts.  There are
4764  * a number of system defined queues as well as user defined timeouts.  It is
4765  * expected that a lock is held in the domain in which the queue belongs
4766  * (i.e. either state or NAT) when calling any of these functions that prevents
4767  * fr_freetimeoutqueue() from being called at the same time as any other.
4768  */
4769
4770
4771 /* ------------------------------------------------------------------------ */
4772 /* Function:    fr_addtimeoutqueue                                          */
4773 /* Returns:     struct ifqtq * - NULL if malloc fails, else pointer to      */
4774 /*                               timeout queue with given interval.         */
4775 /* Parameters:  parent(I)  - pointer to pointer to parent node of this list */
4776 /*                           of interface queues.                           */
4777 /*              seconds(I) - timeout value in seconds for this queue.       */
4778 /*                                                                          */
4779 /* This routine first looks for a timeout queue that matches the interval   */
4780 /* being requested.  If it finds one, increments the reference counter and  */
4781 /* returns a pointer to it.  If none are found, it allocates a new one and  */
4782 /* inserts it at the top of the list.                                       */
4783 /*                                                                          */
4784 /* Locking.                                                                 */
4785 /* It is assumed that the caller of this function has an appropriate lock   */
4786 /* held (exclusively) in the domain that encompases 'parent'.               */
4787 /* ------------------------------------------------------------------------ */
4788 ipftq_t *fr_addtimeoutqueue(parent, seconds)
4789 ipftq_t **parent;
4790 u_int seconds;
4791 {
4792         ipftq_t *ifq;
4793         u_int period;
4794
4795         period = seconds * IPF_HZ_DIVIDE;
4796
4797         MUTEX_ENTER(&ipf_timeoutlock);
4798         for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
4799                 if (ifq->ifq_ttl == period) {
4800                         /*
4801                          * Reset the delete flag, if set, so the structure
4802                          * gets reused rather than freed and reallocated.
4803                          */
4804                         MUTEX_ENTER(&ifq->ifq_lock);
4805                         ifq->ifq_flags &= ~IFQF_DELETE;
4806                         ifq->ifq_ref++;
4807                         MUTEX_EXIT(&ifq->ifq_lock);
4808                         MUTEX_EXIT(&ipf_timeoutlock);
4809
4810                         return ifq;
4811                 }
4812         }
4813
4814         KMALLOC(ifq, ipftq_t *);
4815         if (ifq != NULL) {
4816                 ifq->ifq_ttl = period;
4817                 ifq->ifq_head = NULL;
4818                 ifq->ifq_tail = &ifq->ifq_head;
4819                 ifq->ifq_next = *parent;
4820                 ifq->ifq_pnext = parent;
4821                 ifq->ifq_ref = 1;
4822                 ifq->ifq_flags = IFQF_USER;
4823                 *parent = ifq;
4824                 fr_userifqs++;
4825                 MUTEX_NUKE(&ifq->ifq_lock);
4826                 MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex");
4827         }
4828         MUTEX_EXIT(&ipf_timeoutlock);
4829         return ifq;
4830 }
4831
4832
4833 /* ------------------------------------------------------------------------ */
4834 /* Function:    fr_deletetimeoutqueue                                       */
4835 /* Returns:     int    - new reference count value of the timeout queue     */
4836 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
4837 /* Locks:       ifq->ifq_lock                                               */
4838 /*                                                                          */
4839 /* This routine must be called when we're discarding a pointer to a timeout */
4840 /* queue object, taking care of the reference counter.                      */
4841 /*                                                                          */
4842 /* Now that this just sets a DELETE flag, it requires the expire code to    */
4843 /* check the list of user defined timeout queues and call the free function */
4844 /* below (currently commented out) to stop memory leaking.  It is done this */
4845 /* way because the locking may not be sufficient to safely do a free when   */
4846 /* this function is called.                                                 */
4847 /* ------------------------------------------------------------------------ */
4848 int fr_deletetimeoutqueue(ifq)
4849 ipftq_t *ifq;
4850 {
4851
4852         ifq->ifq_ref--;
4853         if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) {
4854                 ifq->ifq_flags |= IFQF_DELETE;
4855         }
4856
4857         return ifq->ifq_ref;
4858 }
4859
4860
4861 /* ------------------------------------------------------------------------ */
4862 /* Function:    fr_freetimeoutqueue                                         */
4863 /* Parameters:  ifq(I) - timeout queue which is losing a reference.         */
4864 /* Returns:     Nil                                                         */
4865 /*                                                                          */
4866 /* Locking:                                                                 */
4867 /* It is assumed that the caller of this function has an appropriate lock   */
4868 /* held (exclusively) in the domain that encompases the callers "domain".   */
4869 /* The ifq_lock for this structure should not be held.                      */
4870 /*                                                                          */
4871 /* Remove a user definde timeout queue from the list of queues it is in and */
4872 /* tidy up after this is done.                                              */
4873 /* ------------------------------------------------------------------------ */
4874 void fr_freetimeoutqueue(ifq)
4875 ipftq_t *ifq;
4876 {
4877
4878
4879         if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
4880             ((ifq->ifq_flags & IFQF_USER) == 0)) {
4881                 printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
4882                        (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
4883                        ifq->ifq_ref);
4884                 return;
4885         }
4886
4887         /*
4888          * Remove from its position in the list.
4889          */
4890         *ifq->ifq_pnext = ifq->ifq_next;
4891         if (ifq->ifq_next != NULL)
4892                 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
4893
4894         MUTEX_DESTROY(&ifq->ifq_lock);
4895         ATOMIC_DEC(fr_userifqs);
4896         KFREE(ifq);
4897 }
4898
4899
4900 /* ------------------------------------------------------------------------ */
4901 /* Function:    fr_deletequeueentry                                         */
4902 /* Returns:     Nil                                                         */
4903 /* Parameters:  tqe(I) - timeout queue entry to delete                      */
4904 /*              ifq(I) - timeout queue to remove entry from                 */
4905 /*                                                                          */
4906 /* Remove a tail queue entry from its queue and make it an orphan.          */
4907 /* fr_deletetimeoutqueue is called to make sure the reference count on the  */
4908 /* queue is correct.  We can't, however, call fr_freetimeoutqueue because   */
4909 /* the correct lock(s) may not be held that would make it safe to do so.    */
4910 /* ------------------------------------------------------------------------ */
4911 void fr_deletequeueentry(tqe)
4912 ipftqent_t *tqe;
4913 {
4914         ipftq_t *ifq;
4915
4916         ifq = tqe->tqe_ifq;
4917
4918         MUTEX_ENTER(&ifq->ifq_lock);
4919
4920         if (tqe->tqe_pnext != NULL) {
4921                 *tqe->tqe_pnext = tqe->tqe_next;
4922                 if (tqe->tqe_next != NULL)
4923                         tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
4924                 else    /* we must be the tail anyway */
4925                         ifq->ifq_tail = tqe->tqe_pnext;
4926
4927                 tqe->tqe_pnext = NULL;
4928                 tqe->tqe_ifq = NULL;
4929         }
4930
4931         (void) fr_deletetimeoutqueue(ifq);
4932
4933         MUTEX_EXIT(&ifq->ifq_lock);
4934 }
4935
4936
4937 /* ------------------------------------------------------------------------ */
4938 /* Function:    fr_queuefront                                               */
4939 /* Returns:     Nil                                                         */
4940 /* Parameters:  tqe(I) - pointer to timeout queue entry                     */
4941 /*                                                                          */
4942 /* Move a queue entry to the front of the queue, if it isn't already there. */
4943 /* ------------------------------------------------------------------------ */
4944 void fr_queuefront(tqe)
4945 ipftqent_t *tqe;
4946 {
4947         ipftq_t *ifq;
4948
4949         ifq = tqe->tqe_ifq;
4950         if (ifq == NULL)
4951                 return;
4952
4953         MUTEX_ENTER(&ifq->ifq_lock);
4954         if (ifq->ifq_head != tqe) {
4955                 *tqe->tqe_pnext = tqe->tqe_next;
4956                 if (tqe->tqe_next)
4957                         tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
4958                 else
4959                         ifq->ifq_tail = tqe->tqe_pnext;
4960
4961                 tqe->tqe_next = ifq->ifq_head;
4962                 ifq->ifq_head->tqe_pnext = &tqe->tqe_next;
4963                 ifq->ifq_head = tqe;
4964                 tqe->tqe_pnext = &ifq->ifq_head;
4965         }
4966         MUTEX_EXIT(&ifq->ifq_lock);
4967 }
4968
4969
4970 /* ------------------------------------------------------------------------ */
4971 /* Function:    fr_queueback                                                */
4972 /* Returns:     Nil                                                         */
4973 /* Parameters:  tqe(I) - pointer to timeout queue entry                     */
4974 /*                                                                          */
4975 /* Move a queue entry to the back of the queue, if it isn't already there.  */
4976 /* ------------------------------------------------------------------------ */
4977 void fr_queueback(tqe)
4978 ipftqent_t *tqe;
4979 {
4980         ipftq_t *ifq;
4981
4982         ifq = tqe->tqe_ifq;
4983         if (ifq == NULL)
4984                 return;
4985         tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
4986
4987         MUTEX_ENTER(&ifq->ifq_lock);
4988         if (tqe->tqe_next != NULL) {            /* at the end already ? */
4989                 /*
4990                  * Remove from list
4991                  */
4992                 *tqe->tqe_pnext = tqe->tqe_next;
4993                 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
4994
4995                 /*
4996                  * Make it the last entry.
4997                  */
4998                 tqe->tqe_next = NULL;
4999                 tqe->tqe_pnext = ifq->ifq_tail;
5000                 *ifq->ifq_tail = tqe;
5001                 ifq->ifq_tail = &tqe->tqe_next;
5002         }
5003         MUTEX_EXIT(&ifq->ifq_lock);
5004 }
5005
5006
5007 /* ------------------------------------------------------------------------ */
5008 /* Function:    fr_queueappend                                              */
5009 /* Returns:     Nil                                                         */
5010 /* Parameters:  tqe(I)    - pointer to timeout queue entry                  */
5011 /*              ifq(I)    - pointer to timeout queue                        */
5012 /*              parent(I) - owing object pointer                            */
5013 /*                                                                          */
5014 /* Add a new item to this queue and put it on the very end.                 */
5015 /* ------------------------------------------------------------------------ */
5016 void fr_queueappend(tqe, ifq, parent)
5017 ipftqent_t *tqe;
5018 ipftq_t *ifq;
5019 void *parent;
5020 {
5021
5022         MUTEX_ENTER(&ifq->ifq_lock);
5023         tqe->tqe_parent = parent;
5024         tqe->tqe_pnext = ifq->ifq_tail;
5025         *ifq->ifq_tail = tqe;
5026         ifq->ifq_tail = &tqe->tqe_next;
5027         tqe->tqe_next = NULL;
5028         tqe->tqe_ifq = ifq;
5029         tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
5030         ifq->ifq_ref++;
5031         MUTEX_EXIT(&ifq->ifq_lock);
5032 }
5033
5034
5035 /* ------------------------------------------------------------------------ */
5036 /* Function:    fr_movequeue                                                */
5037 /* Returns:     Nil                                                         */
5038 /* Parameters:  tq(I)   - pointer to timeout queue information              */
5039 /*              oifp(I) - old timeout queue entry was on                    */
5040 /*              nifp(I) - new timeout queue to put entry on                 */
5041 /*                                                                          */
5042 /* Move a queue entry from one timeout queue to another timeout queue.      */
5043 /* If it notices that the current entry is already last and does not need   */
5044 /* to move queue, the return.                                               */
5045 /* ------------------------------------------------------------------------ */
5046 void fr_movequeue(tqe, oifq, nifq)
5047 ipftqent_t *tqe;
5048 ipftq_t *oifq, *nifq;
5049 {
5050         /*
5051          * Is the operation here going to be a no-op ?
5052          */
5053         MUTEX_ENTER(&oifq->ifq_lock);
5054         if ((oifq != nifq) || (*oifq->ifq_tail != tqe)) {
5055                 /*
5056                  * Remove from the old queue
5057                  */
5058                 *tqe->tqe_pnext = tqe->tqe_next;
5059                 if (tqe->tqe_next)
5060                         tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
5061                 else
5062                         oifq->ifq_tail = tqe->tqe_pnext;
5063                 tqe->tqe_next = NULL;
5064
5065                 /*
5066                  * If we're moving from one queue to another, release the
5067                  * lock on the old queue and get a lock on the new queue.
5068                  * For user defined queues, if we're moving off it, call
5069                  * delete in case it can now be freed.
5070                  */
5071                 if (oifq != nifq) {
5072                         tqe->tqe_ifq = NULL;
5073
5074                         (void) fr_deletetimeoutqueue(oifq);
5075
5076                         MUTEX_EXIT(&oifq->ifq_lock);
5077
5078                         MUTEX_ENTER(&nifq->ifq_lock);
5079
5080                         tqe->tqe_ifq = nifq;
5081                         nifq->ifq_ref++;
5082                 }
5083
5084                 /*
5085                  * Add to the bottom of the new queue
5086                  */
5087                 tqe->tqe_die = fr_ticks + nifq->ifq_ttl;
5088                 tqe->tqe_pnext = nifq->ifq_tail;
5089                 *nifq->ifq_tail = tqe;
5090                 nifq->ifq_tail = &tqe->tqe_next;
5091         }
5092         MUTEX_EXIT(&nifq->ifq_lock);
5093 }
5094
5095
5096 /* ------------------------------------------------------------------------ */
5097 /* Function:    fr_updateipid                                               */
5098 /* Returns:     int - 0 == success, -1 == error (packet should be droppped) */
5099 /* Parameters:  fin(I) - pointer to packet information                      */
5100 /*                                                                          */
5101 /* When we are doing NAT, change the IP of every packet to represent a      */
5102 /* single sequence of packets coming from the host, hiding any host         */
5103 /* specific sequencing that might otherwise be revealed.  If the packet is  */
5104 /* a fragment, then store the 'new' IPid in the fragment cache and look up  */
5105 /* the fragment cache for non-leading fragments.  If a non-leading fragment */
5106 /* has no match in the cache, return an error.                              */
5107 /* ------------------------------------------------------------------------ */
5108 static int fr_updateipid(fin)
5109 fr_info_t *fin;
5110 {
5111         u_short id, ido, sums;
5112         u_32_t sumd, sum;
5113         ip_t *ip;
5114
5115         if (fin->fin_off != 0) {
5116                 sum = fr_ipid_knownfrag(fin);
5117                 if (sum == 0xffffffff)
5118                         return -1;
5119                 sum &= 0xffff;
5120                 id = (u_short)sum;
5121         } else {
5122                 id = fr_nextipid(fin);
5123                 if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0)
5124                         (void) fr_ipid_newfrag(fin, (u_32_t)id);
5125         }
5126
5127         ip = fin->fin_ip;
5128         ido = ntohs(ip->ip_id);
5129         if (id == ido)
5130                 return 0;
5131         ip->ip_id = htons(id);
5132         CALC_SUMD(ido, id, sumd);       /* DESTRUCTIVE MACRO! id,ido change */
5133         sum = (~ntohs(ip->ip_sum)) & 0xffff;
5134         sum += sumd;
5135         sum = (sum >> 16) + (sum & 0xffff);
5136         sum = (sum >> 16) + (sum & 0xffff);
5137         sums = ~(u_short)sum;
5138         ip->ip_sum = htons(sums);
5139         return 0;
5140 }
5141
5142
5143 #ifdef  NEED_FRGETIFNAME
5144 /* ------------------------------------------------------------------------ */
5145 /* Function:    fr_getifname                                                */
5146 /* Returns:     char *    - pointer to interface name                       */
5147 /* Parameters:  ifp(I)    - pointer to network interface                    */
5148 /*              buffer(O) - pointer to where to store interface name        */
5149 /*                                                                          */
5150 /* Constructs an interface name in the buffer passed.  The buffer passed is */
5151 /* expected to be at least LIFNAMSIZ in bytes big.  If buffer is passed in  */
5152 /* as a NULL pointer then return a pointer to a static array.               */
5153 /* ------------------------------------------------------------------------ */
5154 char *fr_getifname(ifp, buffer)
5155 struct ifnet *ifp;
5156 char *buffer;
5157 {
5158         static char namebuf[LIFNAMSIZ];
5159 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
5160      defined(__sgi) || defined(linux) || defined(_AIX51) || \
5161      (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
5162         int unit, space;
5163         char temp[20];
5164         char *s;
5165 # endif
5166
5167         if (buffer == NULL)
5168                 buffer = namebuf;
5169         (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ);
5170         buffer[LIFNAMSIZ - 1] = '\0';
5171 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
5172      defined(__sgi) || defined(_AIX51) || \
5173      (defined(sun) && !defined(__SVR4) && !defined(__svr4__))
5174         for (s = buffer; *s; s++)
5175                 ;
5176         unit = ifp->if_unit;
5177         space = LIFNAMSIZ - (s - buffer);
5178         if (space > 0) {
5179 #  if defined(SNPRINTF) && defined(_KERNEL)
5180                 SNPRINTF(temp, sizeof(temp), "%d", unit);
5181 #  else
5182                 (void) sprintf(temp, "%d", unit);
5183 #  endif
5184                 (void) strncpy(s, temp, space);
5185         }
5186 # endif
5187         return buffer;
5188 }
5189 #endif
5190
5191
5192 /* ------------------------------------------------------------------------ */
5193 /* Function:    fr_ioctlswitch                                              */
5194 /* Returns:     int     - -1 continue processing, else ioctl return value   */
5195 /* Parameters:  unit(I) - device unit opened                                */
5196 /*              data(I) - pointer to ioctl data                             */
5197 /*              cmd(I)  - ioctl command                                     */
5198 /*              mode(I) - mode value                                        */
5199 /*                                                                          */
5200 /* Based on the value of unit, call the appropriate ioctl handler or return */
5201 /* EIO if ipfilter is not running.   Also checks if write perms are req'd   */
5202 /* for the device in order to execute the ioctl.                            */
5203 /* ------------------------------------------------------------------------ */
5204 int fr_ioctlswitch(unit, data, cmd, mode)
5205 int unit, mode;
5206 ioctlcmd_t cmd;
5207 void *data;
5208 {
5209         int error = 0;
5210
5211         switch (unit)
5212         {
5213         case IPL_LOGIPF :
5214                 error = -1;
5215                 break;
5216         case IPL_LOGNAT :
5217                 if (fr_running > 0)
5218                         error = fr_nat_ioctl(data, cmd, mode);
5219                 else
5220                         error = EIO;
5221                 break;
5222         case IPL_LOGSTATE :
5223                 if (fr_running > 0)
5224                         error = fr_state_ioctl(data, cmd, mode);
5225                 else
5226                         error = EIO;
5227                 break;
5228         case IPL_LOGAUTH :
5229                 if (fr_running > 0) {
5230                         if ((cmd == (ioctlcmd_t)SIOCADAFR) ||
5231                             (cmd == (ioctlcmd_t)SIOCRMAFR)) {
5232                                 if (!(mode & FWRITE)) {
5233                                         error = EPERM;
5234                                 } else {
5235                                         error = frrequest(unit, cmd, data,
5236                                                           fr_active, 1);
5237                                 }
5238                         } else {
5239                                 error = fr_auth_ioctl(data, cmd, mode);
5240                         }
5241                 } else
5242                         error = EIO;
5243                 break;
5244         case IPL_LOGSYNC :
5245 #ifdef IPFILTER_SYNC
5246                 if (fr_running > 0)
5247                         error = fr_sync_ioctl(data, cmd, mode);
5248                 else
5249 #endif
5250                         error = EIO;
5251                 break;
5252         case IPL_LOGSCAN :
5253 #ifdef IPFILTER_SCAN
5254                 if (fr_running > 0)
5255                         error = fr_scan_ioctl(data, cmd, mode);
5256                 else
5257 #endif
5258                         error = EIO;
5259                 break;
5260         case IPL_LOGLOOKUP :
5261 #ifdef IPFILTER_LOOKUP
5262                 if (fr_running > 0)
5263                         error = ip_lookup_ioctl(data, cmd, mode);
5264                 else
5265 #endif
5266                         error = EIO;
5267                 break;
5268         default :
5269                 error = EIO;
5270                 break;
5271         }
5272
5273         return error;
5274 }
5275
5276
5277 /*
5278  * This array defines the expected size of objects coming into the kernel
5279  * for the various recognised object types.
5280  */
5281 #define NUM_OBJ_TYPES   14
5282
5283 static  int     fr_objbytes[NUM_OBJ_TYPES][2] = {
5284         { 1,    sizeof(struct frentry) },               /* frentry */
5285         { 0,    sizeof(struct friostat) },
5286         { 0,    sizeof(struct fr_info) },
5287         { 0,    sizeof(struct fr_authstat) },
5288         { 0,    sizeof(struct ipfrstat) },
5289         { 0,    sizeof(struct ipnat) },
5290         { 0,    sizeof(struct natstat) },
5291         { 0,    sizeof(struct ipstate_save) },
5292         { 1,    sizeof(struct nat_save) },              /* nat_save */
5293         { 0,    sizeof(struct natlookup) },
5294         { 1,    sizeof(struct ipstate) },               /* ipstate */
5295         { 0,    sizeof(struct ips_stat) },
5296         { 0,    sizeof(struct frauth) },
5297         { 0,    sizeof(struct ipftune) }
5298 };
5299
5300
5301 /* ------------------------------------------------------------------------ */
5302 /* Function:    fr_inobj                                                    */
5303 /* Returns:     int     - 0 = success, else failure                         */
5304 /* Parameters:  data(I) - pointer to ioctl data                             */
5305 /*              ptr(I)  - pointer to store real data in                     */
5306 /*              type(I) - type of structure being moved                     */
5307 /*                                                                          */
5308 /* Copy in the contents of what the ipfobj_t points to.  In future, we      */
5309 /* add things to check for version numbers, sizes, etc, to make it backward */
5310 /* compatible at the ABI for user land.                                     */
5311 /* ------------------------------------------------------------------------ */
5312 int fr_inobj(data, ptr, type)
5313 void *data;
5314 void *ptr;
5315 int type;
5316 {
5317         ipfobj_t obj;
5318         int error = 0;
5319
5320         if ((type < 0) || (type > NUM_OBJ_TYPES-1))
5321                 return EINVAL;
5322
5323         BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
5324
5325         if (obj.ipfo_type != type)
5326                 return EINVAL;
5327
5328 #ifndef IPFILTER_COMPAT
5329         if ((fr_objbytes[type][0] & 1) != 0) {
5330                 if (obj.ipfo_size < fr_objbytes[type][1])
5331                         return EINVAL;
5332         } else if (obj.ipfo_size != fr_objbytes[type][1])
5333                 return EINVAL;
5334 #else
5335         if (obj.ipfo_rev != IPFILTER_VERSION)
5336                 /* XXX compatibility hook here */
5337                 ;
5338         if ((fr_objbytes[type][0] & 1) != 0) {
5339                 if (obj.ipfo_size < fr_objbytes[type][1])
5340                         /* XXX compatibility hook here */
5341                         return EINVAL;
5342         } else if (obj.ipfo_size != fr_objbytes[type][1])
5343                 /* XXX compatibility hook here */
5344                 return EINVAL;
5345 #endif
5346
5347         if ((fr_objbytes[type][0] & 1) != 0) {
5348                 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr,
5349                                 fr_objbytes[type][1]);
5350         } else {
5351                 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr,
5352                                 obj.ipfo_size);
5353         }
5354         return error;
5355 }
5356
5357
5358 /* ------------------------------------------------------------------------ */
5359 /* Function:    fr_inobjsz                                                  */
5360 /* Returns:     int     - 0 = success, else failure                         */
5361 /* Parameters:  data(I) - pointer to ioctl data                             */
5362 /*              ptr(I)  - pointer to store real data in                     */
5363 /*              type(I) - type of structure being moved                     */
5364 /*              sz(I)   - size of data to copy                              */
5365 /*                                                                          */
5366 /* As per fr_inobj, except the size of the object to copy in is passed in   */
5367 /* but it must not be smaller than the size defined for the type and the    */
5368 /* type must allow for varied sized objects.  The extra requirement here is */
5369 /* that sz must match the size of the object being passed in - this is not  */
5370 /* not possible nor required in fr_inobj().                                 */
5371 /* ------------------------------------------------------------------------ */
5372 int fr_inobjsz(data, ptr, type, sz)
5373 void *data;
5374 void *ptr;
5375 int type, sz;
5376 {
5377         ipfobj_t obj;
5378         int error;
5379
5380         if ((type < 0) || (type > NUM_OBJ_TYPES-1))
5381                 return EINVAL;
5382         if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1]))
5383                 return EINVAL;
5384
5385         BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
5386
5387         if (obj.ipfo_type != type)
5388                 return EINVAL;
5389
5390 #ifndef IPFILTER_COMPAT
5391         if (obj.ipfo_size != sz)
5392                 return EINVAL;
5393 #else
5394         if (obj.ipfo_rev != IPFILTER_VERSION)
5395                 /* XXX compatibility hook here */
5396                 ;
5397         if (obj.ipfo_size != sz)
5398                 /* XXX compatibility hook here */
5399                 return EINVAL;
5400 #endif
5401
5402         error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, sz);
5403         return error;
5404 }
5405
5406
5407 /* ------------------------------------------------------------------------ */
5408 /* Function:    fr_outobjsz                                                 */
5409 /* Returns:     int     - 0 = success, else failure                         */
5410 /* Parameters:  data(I) - pointer to ioctl data                             */
5411 /*              ptr(I)  - pointer to store real data in                     */
5412 /*              type(I) - type of structure being moved                     */
5413 /*              sz(I)   - size of data to copy                              */
5414 /*                                                                          */
5415 /* As per fr_outobj, except the size of the object to copy out is passed in */
5416 /* but it must not be smaller than the size defined for the type and the    */
5417 /* type must allow for varied sized objects.  The extra requirement here is */
5418 /* that sz must match the size of the object being passed in - this is not  */
5419 /* not possible nor required in fr_outobj().                                */
5420 /* ------------------------------------------------------------------------ */
5421 int fr_outobjsz(data, ptr, type, sz)
5422 void *data;
5423 void *ptr;
5424 int type, sz;
5425 {
5426         ipfobj_t obj;
5427         int error;
5428
5429         if ((type < 0) || (type > NUM_OBJ_TYPES-1) ||
5430             ((fr_objbytes[type][0] & 1) == 0) ||
5431             (sz < fr_objbytes[type][1]))
5432                 return EINVAL;
5433
5434         BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
5435
5436         if (obj.ipfo_type != type)
5437                 return EINVAL;
5438
5439 #ifndef IPFILTER_COMPAT
5440         if (obj.ipfo_size != sz)
5441                 return EINVAL;
5442 #else
5443         if (obj.ipfo_rev != IPFILTER_VERSION)
5444                 /* XXX compatibility hook here */
5445                 ;
5446         if (obj.ipfo_size != sz)
5447                 /* XXX compatibility hook here */
5448                 return EINVAL;
5449 #endif
5450
5451         error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, sz);
5452         return error;
5453 }
5454
5455
5456 /* ------------------------------------------------------------------------ */
5457 /* Function:    fr_outobj                                                   */
5458 /* Returns:     int     - 0 = success, else failure                         */
5459 /* Parameters:  data(I) - pointer to ioctl data                             */
5460 /*              ptr(I)  - pointer to store real data in                     */
5461 /*              type(I) - type of structure being moved                     */
5462 /*                                                                          */
5463 /* Copy out the contents of what ptr is to where ipfobj points to.  In      */
5464 /* future, we add things to check for version numbers, sizes, etc, to make  */
5465 /* it backward  compatible at the ABI for user land.                        */
5466 /* ------------------------------------------------------------------------ */
5467 int fr_outobj(data, ptr, type)
5468 void *data;
5469 void *ptr;
5470 int type;
5471 {
5472         ipfobj_t obj;
5473         int error;
5474
5475         if ((type < 0) || (type > NUM_OBJ_TYPES-1))
5476                 return EINVAL;
5477
5478         BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj));
5479
5480         if (obj.ipfo_type != type)
5481                 return EINVAL;
5482
5483 #ifndef IPFILTER_COMPAT
5484         if ((fr_objbytes[type][0] & 1) != 0) {
5485                 if (obj.ipfo_size < fr_objbytes[type][1])
5486                         return EINVAL;
5487         } else if (obj.ipfo_size != fr_objbytes[type][1])
5488                 return EINVAL;
5489 #else
5490         if (obj.ipfo_rev != IPFILTER_VERSION)
5491                 /* XXX compatibility hook here */
5492                 ;
5493         if ((fr_objbytes[type][0] & 1) != 0) {
5494                 if (obj.ipfo_size < fr_objbytes[type][1])
5495                         /* XXX compatibility hook here */
5496                         return EINVAL;
5497         } else if (obj.ipfo_size != fr_objbytes[type][1])
5498                 /* XXX compatibility hook here */
5499                 return EINVAL;
5500 #endif
5501
5502         error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size);
5503         return error;
5504 }
5505
5506
5507 /* ------------------------------------------------------------------------ */
5508 /* Function:    fr_checkl4sum                                               */
5509 /* Returns:     int     - 0 = good, -1 = bad, 1 = cannot check              */
5510 /* Parameters:  fin(I) - pointer to packet information                      */
5511 /*                                                                          */
5512 /* If possible, calculate the layer 4 checksum for the packet.  If this is  */
5513 /* not possible, return without indicating a failure or success but in a    */
5514 /* way that is ditinguishable.                                              */
5515 /* ------------------------------------------------------------------------ */
5516 int fr_checkl4sum(fin)
5517 fr_info_t *fin;
5518 {
5519         u_short sum, hdrsum, *csump;
5520         udphdr_t *udp;
5521         int dosum;
5522
5523         if ((fin->fin_flx & FI_NOCKSUM) != 0)
5524                 return 0;
5525
5526         /*
5527          * If the TCP packet isn't a fragment, isn't too short and otherwise
5528          * isn't already considered "bad", then validate the checksum.  If
5529          * this check fails then considered the packet to be "bad".
5530          */
5531         if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0)
5532                 return 1;
5533
5534         csump = NULL;
5535         hdrsum = 0;
5536         dosum = 0;
5537         sum = 0;
5538
5539 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
5540         if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) {
5541                 hdrsum = 0;
5542                 sum = 0;
5543         } else {
5544 #endif
5545                 switch (fin->fin_p)
5546                 {
5547                 case IPPROTO_TCP :
5548                         csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
5549                         dosum = 1;
5550                         break;
5551
5552                 case IPPROTO_UDP :
5553                         udp = fin->fin_dp;
5554                         if (udp->uh_sum != 0) {
5555                                 csump = &udp->uh_sum;
5556                                 dosum = 1;
5557                         }
5558                         break;
5559
5560                 case IPPROTO_ICMP :
5561                         csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
5562                         dosum = 1;
5563                         break;
5564
5565                 default :
5566                         return 1;
5567                         /*NOTREACHED*/
5568                 }
5569
5570                 if (csump != NULL)
5571                         hdrsum = *csump;
5572
5573                 if (dosum)
5574                         sum = fr_cksum(fin->fin_m, fin->fin_ip,
5575                                        fin->fin_p, fin->fin_dp, fin->fin_plen);
5576 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
5577         }
5578 #endif
5579 #if !defined(_KERNEL)
5580         if (sum == hdrsum) {
5581                 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
5582         } else {
5583                 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
5584         }
5585 #endif
5586         if (hdrsum == sum)
5587                 return 0;
5588         return -1;
5589 }
5590
5591
5592 /* ------------------------------------------------------------------------ */
5593 /* Function:    fr_ifpfillv4addr                                            */
5594 /* Returns:     int     - 0 = address update, -1 = address not updated      */
5595 /* Parameters:  atype(I)   - type of network address update to perform      */
5596 /*              sin(I)     - pointer to source of address information       */
5597 /*              mask(I)    - pointer to source of netmask information       */
5598 /*              inp(I)     - pointer to destination address store           */
5599 /*              inpmask(I) - pointer to destination netmask store           */
5600 /*                                                                          */
5601 /* Given a type of network address update (atype) to perform, copy          */
5602 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
5603 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
5604 /* which case the operation fails.  For all values of atype other than      */
5605 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
5606 /* value.                                                                   */
5607 /* ------------------------------------------------------------------------ */
5608 int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask)
5609 int atype;
5610 struct sockaddr_in *sin, *mask;
5611 struct in_addr *inp, *inpmask;
5612 {
5613         if (inpmask != NULL && atype != FRI_NETMASKED)
5614                 inpmask->s_addr = 0xffffffff;
5615
5616         if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
5617                 if (atype == FRI_NETMASKED) {
5618                         if (inpmask == NULL)
5619                                 return -1;
5620                         inpmask->s_addr = mask->sin_addr.s_addr;
5621                 }
5622                 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr;
5623         } else {
5624                 inp->s_addr = sin->sin_addr.s_addr;
5625         }
5626         return 0;
5627 }
5628
5629
5630 #ifdef  USE_INET6
5631 /* ------------------------------------------------------------------------ */
5632 /* Function:    fr_ifpfillv6addr                                            */
5633 /* Returns:     int     - 0 = address update, -1 = address not updated      */
5634 /* Parameters:  atype(I)   - type of network address update to perform      */
5635 /*              sin(I)     - pointer to source of address information       */
5636 /*              mask(I)    - pointer to source of netmask information       */
5637 /*              inp(I)     - pointer to destination address store           */
5638 /*              inpmask(I) - pointer to destination netmask store           */
5639 /*                                                                          */
5640 /* Given a type of network address update (atype) to perform, copy          */
5641 /* information from sin/mask into inp/inpmask.  If ipnmask is NULL then no  */
5642 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in  */
5643 /* which case the operation fails.  For all values of atype other than      */
5644 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s  */
5645 /* value.                                                                   */
5646 /* ------------------------------------------------------------------------ */
5647 int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask)
5648 int atype;
5649 struct sockaddr_in6 *sin, *mask;
5650 struct in_addr *inp, *inpmask;
5651 {
5652         i6addr_t *src, *dst, *and, *dmask;
5653
5654         src = (i6addr_t *)&sin->sin6_addr;
5655         and = (i6addr_t *)&mask->sin6_addr;
5656         dst = (i6addr_t *)inp;
5657         dmask = (i6addr_t *)inpmask;
5658
5659         if (inpmask != NULL && atype != FRI_NETMASKED) {
5660                 dmask->i6[0] = 0xffffffff;
5661                 dmask->i6[1] = 0xffffffff;
5662                 dmask->i6[2] = 0xffffffff;
5663                 dmask->i6[3] = 0xffffffff;
5664         }
5665
5666         if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
5667                 if (atype == FRI_NETMASKED) {
5668                         if (inpmask == NULL)
5669                                 return -1;
5670                         dmask->i6[0] = and->i6[0];
5671                         dmask->i6[1] = and->i6[1];
5672                         dmask->i6[2] = and->i6[2];
5673                         dmask->i6[3] = and->i6[3];
5674                 }
5675
5676                 dst->i6[0] = src->i6[0] & and->i6[0];
5677                 dst->i6[1] = src->i6[1] & and->i6[1];
5678                 dst->i6[2] = src->i6[2] & and->i6[2];
5679                 dst->i6[3] = src->i6[3] & and->i6[3];
5680         } else {
5681                 dst->i6[0] = src->i6[0];
5682                 dst->i6[1] = src->i6[1];
5683                 dst->i6[2] = src->i6[2];
5684                 dst->i6[3] = src->i6[3];
5685         }
5686         return 0;
5687 }
5688 #endif
5689
5690
5691 /* ------------------------------------------------------------------------ */
5692 /* Function:    fr_matchtag                                                 */
5693 /* Returns:     0 == mismatch, 1 == match.                                  */
5694 /* Parameters:  tag1(I) - pointer to first tag to compare                   */
5695 /*              tag2(I) - pointer to second tag to compare                  */
5696 /*                                                                          */
5697 /* Returns true (non-zero) or false(0) if the two tag structures can be     */
5698 /* considered to be a match or not match, respectively.  The tag is 16      */
5699 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so    */
5700 /* compare the ints instead, for speed. tag1 is the master of the           */
5701 /* comparison.  This function should only be called with both tag1 and tag2 */
5702 /* as non-NULL pointers.                                                    */
5703 /* ------------------------------------------------------------------------ */
5704 int fr_matchtag(tag1, tag2)
5705 ipftag_t *tag1, *tag2;
5706 {
5707         if (tag1 == tag2)
5708                 return 1;
5709
5710         if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0))
5711                 return 1;
5712
5713         if ((tag1->ipt_num[0] == tag2->ipt_num[0]) &&
5714             (tag1->ipt_num[1] == tag2->ipt_num[1]) &&
5715             (tag1->ipt_num[2] == tag2->ipt_num[2]) &&
5716             (tag1->ipt_num[3] == tag2->ipt_num[3]))
5717                 return 1;
5718         return 0;
5719 }
5720
5721
5722 /* ------------------------------------------------------------------------ */
5723 /* Function:    fr_coalesce                                                 */
5724 /* Returns:     1 == success, -1 == failure, 0 == no change                 */
5725 /* Parameters:  fin(I) - pointer to packet information                      */
5726 /*                                                                          */
5727 /* Attempt to get all of the packet data into a single, contiguous buffer.  */
5728 /* If this call returns a failure then the buffers have also been freed.    */
5729 /* ------------------------------------------------------------------------ */
5730 int fr_coalesce(fin)
5731 fr_info_t *fin;
5732 {
5733         if ((fin->fin_flx & FI_COALESCE) != 0)
5734                 return 1;
5735
5736         /*
5737          * If the mbuf pointers indicate that there is no mbuf to work with,
5738          * return but do not indicate success or failure.
5739          */
5740         if (fin->fin_m == NULL || fin->fin_mp == NULL)
5741                 return 0;
5742
5743 #if defined(_KERNEL)
5744         if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
5745                 ATOMIC_INCL(fr_badcoalesces[fin->fin_out]);
5746 # ifdef MENTAT
5747                 FREE_MB_T(*fin->fin_mp);
5748 # endif
5749                 *fin->fin_mp = NULL;
5750                 fin->fin_m = NULL;
5751                 return -1;
5752         }
5753 #else
5754         fin = fin;      /* LINT */
5755 #endif
5756         return 1;
5757 }
5758
5759
5760 /*
5761  * The following table lists all of the tunable variables that can be
5762  * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt.  The format of each row
5763  * in the table below is as follows:
5764  *
5765  * pointer to value, name of value, minimum, maximum, size of the value's
5766  *     container, value attribute flags
5767  *
5768  * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED
5769  * means the value can only be written to when IPFilter is loaded but disabled.
5770  * The obvious implication is if neither of these are set then the value can be
5771  * changed at any time without harm.
5772  */
5773 ipftuneable_t ipf_tuneables[] = {
5774         /* filtering */
5775         { { &fr_flags },        "fr_flags",             0,      0xffffffff,
5776                         sizeof(fr_flags),               0 },
5777         { { &fr_active },       "fr_active",            0,      0,
5778                         sizeof(fr_active),              IPFT_RDONLY },
5779         { { &fr_control_forwarding },   "fr_control_forwarding",        0, 1,
5780                         sizeof(fr_control_forwarding),  0 },
5781         { { &fr_update_ipid },  "fr_update_ipid",       0,      1,
5782                         sizeof(fr_update_ipid),         0 },
5783         { { &fr_chksrc },       "fr_chksrc",            0,      1,
5784                         sizeof(fr_chksrc),              0 },
5785         { { &fr_minttl },       "fr_minttl",            0,      1,
5786                         sizeof(fr_minttl),              0 },
5787         { { &fr_icmpminfragmtu }, "fr_icmpminfragmtu",  0,      1,
5788                         sizeof(fr_icmpminfragmtu),      0 },
5789         { { &fr_pass },         "fr_pass",              0,      0xffffffff,
5790                         sizeof(fr_pass),                0 },
5791         /* state */
5792         { { &fr_tcpidletimeout }, "fr_tcpidletimeout",  1,      0x7fffffff,
5793                         sizeof(fr_tcpidletimeout),      IPFT_WRDISABLED },
5794         { { &fr_tcpclosewait }, "fr_tcpclosewait",      1,      0x7fffffff,
5795                         sizeof(fr_tcpclosewait),        IPFT_WRDISABLED },
5796         { { &fr_tcplastack },   "fr_tcplastack",        1,      0x7fffffff,
5797                         sizeof(fr_tcplastack),          IPFT_WRDISABLED },
5798         { { &fr_tcptimeout },   "fr_tcptimeout",        1,      0x7fffffff,
5799                         sizeof(fr_tcptimeout),          IPFT_WRDISABLED },
5800         { { &fr_tcpclosed },    "fr_tcpclosed",         1,      0x7fffffff,
5801                         sizeof(fr_tcpclosed),           IPFT_WRDISABLED },
5802         { { &fr_tcphalfclosed }, "fr_tcphalfclosed",    1,      0x7fffffff,
5803                         sizeof(fr_tcphalfclosed),       IPFT_WRDISABLED },
5804         { { &fr_udptimeout },   "fr_udptimeout",        1,      0x7fffffff,
5805                         sizeof(fr_udptimeout),          IPFT_WRDISABLED },
5806         { { &fr_udpacktimeout }, "fr_udpacktimeout",    1,      0x7fffffff,
5807                         sizeof(fr_udpacktimeout),       IPFT_WRDISABLED },
5808         { { &fr_icmptimeout },  "fr_icmptimeout",       1,      0x7fffffff,
5809                         sizeof(fr_icmptimeout),         IPFT_WRDISABLED },
5810         { { &fr_icmpacktimeout }, "fr_icmpacktimeout",  1,      0x7fffffff,
5811                         sizeof(fr_icmpacktimeout),      IPFT_WRDISABLED },
5812         { { &fr_iptimeout }, "fr_iptimeout",            1,      0x7fffffff,
5813                         sizeof(fr_iptimeout),           IPFT_WRDISABLED },
5814         { { &fr_statemax },     "fr_statemax",          1,      0x7fffffff,
5815                         sizeof(fr_statemax),            0 },
5816         { { &fr_statesize },    "fr_statesize",         1,      0x7fffffff,
5817                         sizeof(fr_statesize),           IPFT_WRDISABLED },
5818         { { &fr_state_lock },   "fr_state_lock",        0,      1,
5819                         sizeof(fr_state_lock),          IPFT_RDONLY },
5820         { { &fr_state_maxbucket }, "fr_state_maxbucket", 1,     0x7fffffff,
5821                         sizeof(fr_state_maxbucket),     IPFT_WRDISABLED },
5822         { { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset",    0, 1,
5823                         sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED },
5824         { { &ipstate_logging }, "ipstate_logging",      0,      1,
5825                         sizeof(ipstate_logging),        0 },
5826         /* nat */
5827         { { &fr_nat_lock },             "fr_nat_lock",          0,      1,
5828                         sizeof(fr_nat_lock),            IPFT_RDONLY },
5829         { { &ipf_nattable_sz }, "ipf_nattable_sz",      1,      0x7fffffff,
5830                         sizeof(ipf_nattable_sz),        IPFT_WRDISABLED },
5831         { { &ipf_nattable_max }, "ipf_nattable_max",    1,      0x7fffffff,
5832                         sizeof(ipf_nattable_max),       0 },
5833         { { &ipf_natrules_sz }, "ipf_natrules_sz",      1,      0x7fffffff,
5834                         sizeof(ipf_natrules_sz),        IPFT_WRDISABLED },
5835         { { &ipf_rdrrules_sz }, "ipf_rdrrules_sz",      1,      0x7fffffff,
5836                         sizeof(ipf_rdrrules_sz),        IPFT_WRDISABLED },
5837         { { &ipf_hostmap_sz },  "ipf_hostmap_sz",       1,      0x7fffffff,
5838                         sizeof(ipf_hostmap_sz),         IPFT_WRDISABLED },
5839         { { &fr_nat_maxbucket }, "fr_nat_maxbucket",    1,      0x7fffffff,
5840                         sizeof(fr_nat_maxbucket),       IPFT_WRDISABLED },
5841         { { &fr_nat_maxbucket_reset },  "fr_nat_maxbucket_reset",       0, 1,
5842                         sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED },
5843         { { &nat_logging },             "nat_logging",          0,      1,
5844                         sizeof(nat_logging),            0 },
5845         { { &fr_defnatage },    "fr_defnatage",         1,      0x7fffffff,
5846                         sizeof(fr_defnatage),           IPFT_WRDISABLED },
5847         { { &fr_defnatipage },  "fr_defnatipage",       1,      0x7fffffff,
5848                         sizeof(fr_defnatipage),         IPFT_WRDISABLED },
5849         { { &fr_defnaticmpage }, "fr_defnaticmpage",    1,      0x7fffffff,
5850                         sizeof(fr_defnaticmpage),       IPFT_WRDISABLED },
5851         /* frag */
5852         { { &ipfr_size },       "ipfr_size",            1,      0x7fffffff,
5853                         sizeof(ipfr_size),              IPFT_WRDISABLED },
5854         { { &fr_ipfrttl },      "fr_ipfrttl",           1,      0x7fffffff,
5855                         sizeof(fr_ipfrttl),             IPFT_WRDISABLED },
5856 #ifdef IPFILTER_LOG
5857         /* log */
5858         { { &ipl_suppress },    "ipl_suppress",         0,      1,
5859                         sizeof(ipl_suppress),           0 },
5860         { { &ipl_buffer_sz },   "ipl_buffer_sz",        0,      0,
5861                         sizeof(ipl_buffer_sz),          IPFT_RDONLY },
5862         { { &ipl_logmax },      "ipl_logmax",           0,      0x7fffffff,
5863                         sizeof(ipl_logmax),             IPFT_WRDISABLED },
5864         { { &ipl_logall },      "ipl_logall",           0,      1,
5865                         sizeof(ipl_logall),             0 },
5866         { { &ipl_logsize },     "ipl_logsize",          0,      0x80000,
5867                         sizeof(ipl_logsize),            0 },
5868 #endif
5869         { { NULL },             NULL,                   0,      0 }
5870 };
5871
5872 static ipftuneable_t *ipf_tunelist = NULL;
5873
5874
5875 /* ------------------------------------------------------------------------ */
5876 /* Function:    fr_findtunebycookie                                         */
5877 /* Returns:     NULL = search failed, else pointer to tune struct           */
5878 /* Parameters:  cookie(I) - cookie value to search for amongst tuneables    */
5879 /*              next(O)   - pointer to place to store the cookie for the    */
5880 /*                          "next" tuneable, if it is desired.              */
5881 /*                                                                          */
5882 /* This function is used to walk through all of the existing tunables with  */
5883 /* successive calls.  It searches the known tunables for the one which has  */
5884 /* a matching value for "cookie" - ie its address.  When returning a match, */
5885 /* the next one to be found may be returned inside next.                    */
5886 /* ------------------------------------------------------------------------ */
5887 static ipftuneable_t *fr_findtunebycookie(cookie, next)
5888 void *cookie, **next;
5889 {
5890         ipftuneable_t *ta, **tap;
5891
5892         for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
5893                 if (ta == cookie) {
5894                         if (next != NULL) {
5895                                 /*
5896                                  * If the next entry in the array has a name
5897                                  * present, then return a pointer to it for
5898                                  * where to go next, else return a pointer to
5899                                  * the dynaminc list as a key to search there
5900                                  * next.  This facilitates a weak linking of
5901                                  * the two "lists" together.
5902                                  */
5903                                 if ((ta + 1)->ipft_name != NULL)
5904                                         *next = ta + 1;
5905                                 else
5906                                         *next = &ipf_tunelist;
5907                         }
5908                         return ta;
5909                 }
5910
5911         for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
5912                 if (tap == cookie) {
5913                         if (next != NULL)
5914                                 *next = &ta->ipft_next;
5915                         return ta;
5916                 }
5917
5918         if (next != NULL)
5919                 *next = NULL;
5920         return NULL;
5921 }
5922
5923
5924 /* ------------------------------------------------------------------------ */
5925 /* Function:    fr_findtunebyname                                           */
5926 /* Returns:     NULL = search failed, else pointer to tune struct           */
5927 /* Parameters:  name(I) - name of the tuneable entry to find.               */
5928 /*                                                                          */
5929 /* Search the static array of tuneables and the list of dynamic tuneables   */
5930 /* for an entry with a matching name.  If we can find one, return a pointer */
5931 /* to the matching structure.                                               */
5932 /* ------------------------------------------------------------------------ */
5933 static ipftuneable_t *fr_findtunebyname(name)
5934 const char *name;
5935 {
5936         ipftuneable_t *ta;
5937
5938         for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
5939                 if (!strcmp(ta->ipft_name, name)) {
5940                         return ta;
5941                 }
5942
5943         for (ta = ipf_tunelist; ta != NULL; ta = ta->ipft_next)
5944                 if (!strcmp(ta->ipft_name, name)) {
5945                         return ta;
5946                 }
5947
5948         return NULL;
5949 }
5950
5951
5952 /* ------------------------------------------------------------------------ */
5953 /* Function:    fr_addipftune                                               */
5954 /* Returns:     int - 0 == success, else failure                            */
5955 /* Parameters:  newtune - pointer to new tune struct to add to tuneables    */
5956 /*                                                                          */
5957 /* Appends the tune structure pointer to by "newtune" to the end of the     */
5958 /* current list of "dynamic" tuneable parameters.  Once added, the owner    */
5959 /* of the object is not expected to ever change "ipft_next".                */
5960 /* ------------------------------------------------------------------------ */
5961 int fr_addipftune(newtune)
5962 ipftuneable_t *newtune;
5963 {
5964         ipftuneable_t *ta, **tap;
5965
5966         ta = fr_findtunebyname(newtune->ipft_name);
5967         if (ta != NULL)
5968                 return EEXIST;
5969
5970         for (tap = &ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next)
5971                 ;
5972
5973         newtune->ipft_next = NULL;
5974         *tap = newtune;
5975         return 0;
5976 }
5977
5978
5979 /* ------------------------------------------------------------------------ */
5980 /* Function:    fr_delipftune                                               */
5981 /* Returns:     int - 0 == success, else failure                            */
5982 /* Parameters:  oldtune - pointer to tune struct to remove from the list of */
5983 /*                        current dynamic tuneables                         */
5984 /*                                                                          */
5985 /* Search for the tune structure, by pointer, in the list of those that are */
5986 /* dynamically added at run time.  If found, adjust the list so that this   */
5987 /* structure is no longer part of it.                                       */
5988 /* ------------------------------------------------------------------------ */
5989 int fr_delipftune(oldtune)
5990 ipftuneable_t *oldtune;
5991 {
5992         ipftuneable_t *ta, **tap;
5993
5994         for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
5995                 if (ta == oldtune) {
5996                         *tap = oldtune->ipft_next;
5997                         oldtune->ipft_next = NULL;
5998                         return 0;
5999                 }
6000
6001         return ESRCH;
6002 }
6003
6004
6005 /* ------------------------------------------------------------------------ */
6006 /* Function:    fr_ipftune                                                  */
6007 /* Returns:     int - 0 == success, else failure                            */
6008 /* Parameters:  cmd(I)  - ioctl command number                              */
6009 /*              data(I) - pointer to ioctl data structure                   */
6010 /*                                                                          */
6011 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET.  These  */
6012 /* three ioctls provide the means to access and control global variables    */
6013 /* within IPFilter, allowing (for example) timeouts and table sizes to be   */
6014 /* changed without rebooting, reloading or recompiling.  The initialisation */
6015 /* and 'destruction' routines of the various components of ipfilter are all */
6016 /* each responsible for handling their own values being too big.            */
6017 /* ------------------------------------------------------------------------ */
6018 int fr_ipftune(cmd, data)
6019 ioctlcmd_t cmd;
6020 void *data;
6021 {
6022         ipftuneable_t *ta;
6023         ipftune_t tu;
6024         void *cookie;
6025         int error;
6026
6027         error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE);
6028         if (error != 0)
6029                 return error;
6030
6031         tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
6032         cookie = tu.ipft_cookie;
6033         ta = NULL;
6034
6035         switch (cmd)
6036         {
6037         case SIOCIPFGETNEXT :
6038                 /*
6039                  * If cookie is non-NULL, assume it to be a pointer to the last
6040                  * entry we looked at, so find it (if possible) and return a
6041                  * pointer to the next one after it.  The last entry in the
6042                  * the table is a NULL entry, so when we get to it, set cookie
6043                  * to NULL and return that, indicating end of list, erstwhile
6044                  * if we come in with cookie set to NULL, we are starting anew
6045                  * at the front of the list.
6046                  */
6047                 if (cookie != NULL) {
6048                         ta = fr_findtunebycookie(cookie, &tu.ipft_cookie);
6049                 } else {
6050                         ta = ipf_tuneables;
6051                         tu.ipft_cookie = ta + 1;
6052                 }
6053                 if (ta != NULL) {
6054                         /*
6055                          * Entry found, but does the data pointed to by that
6056                          * row fit in what we can return?
6057                          */
6058                         if (ta->ipft_sz > sizeof(tu.ipft_un))
6059                                 return EINVAL;
6060
6061                         tu.ipft_vlong = 0;
6062                         if (ta->ipft_sz == sizeof(u_long))
6063                                 tu.ipft_vlong = *ta->ipft_plong;
6064                         else if (ta->ipft_sz == sizeof(u_int))
6065                                 tu.ipft_vint = *ta->ipft_pint;
6066                         else if (ta->ipft_sz == sizeof(u_short))
6067                                 tu.ipft_vshort = *ta->ipft_pshort;
6068                         else if (ta->ipft_sz == sizeof(u_char))
6069                                 tu.ipft_vchar = *ta->ipft_pchar;
6070
6071                         tu.ipft_sz = ta->ipft_sz;
6072                         tu.ipft_min = ta->ipft_min;
6073                         tu.ipft_max = ta->ipft_max;
6074                         tu.ipft_flags = ta->ipft_flags;
6075                         bcopy(ta->ipft_name, tu.ipft_name,
6076                               MIN(sizeof(tu.ipft_name),
6077                                   strlen(ta->ipft_name) + 1));
6078                 }
6079                 error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
6080                 break;
6081
6082         case SIOCIPFGET :
6083         case SIOCIPFSET :
6084                 /*
6085                  * Search by name or by cookie value for a particular entry
6086                  * in the tuning paramter table.
6087                  */
6088                 error = ESRCH;
6089                 if (cookie != NULL) {
6090                         ta = fr_findtunebycookie(cookie, NULL);
6091                         if (ta != NULL)
6092                                 error = 0;
6093                 } else if (tu.ipft_name[0] != '\0') {
6094                         ta = fr_findtunebyname(tu.ipft_name);
6095                         if (ta != NULL)
6096                                 error = 0;
6097                 }
6098                 if (error != 0)
6099                         break;
6100
6101                 if (cmd == (ioctlcmd_t)SIOCIPFGET) {
6102                         /*
6103                          * Fetch the tuning parameters for a particular value
6104                          */
6105                         tu.ipft_vlong = 0;
6106                         if (ta->ipft_sz == sizeof(u_long))
6107                                 tu.ipft_vlong = *ta->ipft_plong;
6108                         else if (ta->ipft_sz == sizeof(u_int))
6109                                 tu.ipft_vint = *ta->ipft_pint;
6110                         else if (ta->ipft_sz == sizeof(u_short))
6111                                 tu.ipft_vshort = *ta->ipft_pshort;
6112                         else if (ta->ipft_sz == sizeof(u_char))
6113                                 tu.ipft_vchar = *ta->ipft_pchar;
6114                         tu.ipft_cookie = ta;
6115                         tu.ipft_sz = ta->ipft_sz;
6116                         tu.ipft_min = ta->ipft_min;
6117                         tu.ipft_max = ta->ipft_max;
6118                         tu.ipft_flags = ta->ipft_flags;
6119                         error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
6120
6121                 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
6122                         /*
6123                          * Set an internal parameter.  The hard part here is
6124                          * getting the new value safely and correctly out of
6125                          * the kernel (given we only know its size, not type.)
6126                          */
6127                         u_long in;
6128
6129                         if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
6130                             (fr_running > 0)) {
6131                                 error = EBUSY;
6132                                 break;
6133                         }
6134
6135                         in = tu.ipft_vlong;
6136                         if (in < ta->ipft_min || in > ta->ipft_max) {
6137                                 error = EINVAL;
6138                                 break;
6139                         }
6140
6141                         if (ta->ipft_sz == sizeof(u_long)) {
6142                                 tu.ipft_vlong = *ta->ipft_plong;
6143                                 *ta->ipft_plong = in;
6144                         } else if (ta->ipft_sz == sizeof(u_int)) {
6145                                 tu.ipft_vint = *ta->ipft_pint;
6146                                 *ta->ipft_pint = (u_int)(in & 0xffffffff);
6147                         } else if (ta->ipft_sz == sizeof(u_short)) {
6148                                 tu.ipft_vshort = *ta->ipft_pshort;
6149                                 *ta->ipft_pshort = (u_short)(in & 0xffff);
6150                         } else if (ta->ipft_sz == sizeof(u_char)) {
6151                                 tu.ipft_vchar = *ta->ipft_pchar;
6152                                 *ta->ipft_pchar = (u_char)(in & 0xff);
6153                         }
6154                         error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
6155                 }
6156                 break;
6157
6158         default :
6159                 error = EINVAL;
6160                 break;
6161         }
6162
6163         return error;
6164 }
6165
6166
6167 /* ------------------------------------------------------------------------ */
6168 /* Function:    fr_initialise                                               */
6169 /* Returns:     int - 0 == success,  < 0 == failure                         */
6170 /* Parameters:  None.                                                       */
6171 /*                                                                          */
6172 /* Call of the initialise functions for all the various subsystems inside   */
6173 /* of IPFilter.  If any of them should fail, return immeadiately a failure  */
6174 /* BUT do not try to recover from the error here.                           */
6175 /* ------------------------------------------------------------------------ */
6176 int fr_initialise()
6177 {
6178         int i;
6179
6180 #ifdef IPFILTER_LOG
6181         i = fr_loginit();
6182         if (i < 0)
6183                 return -10 + i;
6184 #endif
6185         i = fr_natinit();
6186         if (i < 0)
6187                 return -20 + i;
6188
6189         i = fr_stateinit();
6190         if (i < 0)
6191                 return -30 + i;
6192
6193         i = fr_authinit();
6194         if (i < 0)
6195                 return -40 + i;
6196
6197         i = fr_fraginit();
6198         if (i < 0)
6199                 return -50 + i;
6200
6201         i = appr_init();
6202         if (i < 0)
6203                 return -60 + i;
6204
6205 #ifdef IPFILTER_SYNC
6206         i = ipfsync_init();
6207         if (i < 0)
6208                 return -70 + i;
6209 #endif
6210 #ifdef IPFILTER_SCAN
6211         i = ipsc_init();
6212         if (i < 0)
6213                 return -80 + i;
6214 #endif
6215 #ifdef IPFILTER_LOOKUP
6216         i = ip_lookup_init();
6217         if (i < 0)
6218                 return -90 + i;
6219 #endif
6220 #ifdef IPFILTER_COMPILED
6221         ipfrule_add();
6222 #endif
6223         return 0;
6224 }
6225
6226
6227 /* ------------------------------------------------------------------------ */
6228 /* Function:    fr_deinitialise                                             */
6229 /* Returns:     None.                                                       */
6230 /* Parameters:  None.                                                       */
6231 /*                                                                          */
6232 /* Call all the various subsystem cleanup routines to deallocate memory or  */
6233 /* destroy locks or whatever they've done that they need to now undo.       */
6234 /* The order here IS important as there are some cross references of        */
6235 /* internal data structures.                                                */
6236 /* ------------------------------------------------------------------------ */
6237 void fr_deinitialise()
6238 {
6239         fr_fragunload();
6240         fr_authunload();
6241         fr_natunload();
6242         fr_stateunload();
6243 #ifdef IPFILTER_SCAN
6244         fr_scanunload();
6245 #endif
6246         appr_unload();
6247
6248 #ifdef IPFILTER_COMPILED
6249         ipfrule_remove();
6250 #endif
6251
6252         (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
6253         (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
6254         (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
6255         (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE);
6256
6257 #ifdef IPFILTER_LOOKUP
6258         ip_lookup_unload();
6259 #endif
6260
6261 #ifdef IPFILTER_LOG
6262         fr_logunload();
6263 #endif
6264 }
6265
6266
6267 /* ------------------------------------------------------------------------ */
6268 /* Function:    fr_zerostats                                                */
6269 /* Returns:     int - 0 = success, else failure                             */
6270 /* Parameters:  data(O) - pointer to pointer for copying data back to       */
6271 /*                                                                          */
6272 /* Copies the current statistics out to userspace and then zero's the       */
6273 /* current ones in the kernel. The lock is only held across the bzero() as  */
6274 /* the copyout may result in paging (ie network activity.)                  */
6275 /* ------------------------------------------------------------------------ */
6276 int     fr_zerostats(data)
6277 caddr_t data;
6278 {
6279         friostat_t fio;
6280         int error;
6281
6282         fr_getstat(&fio);
6283         error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
6284         if (error)
6285                 return EFAULT;
6286
6287         WRITE_ENTER(&ipf_mutex);
6288         bzero((char *)frstats, sizeof(*frstats) * 2);
6289         RWLOCK_EXIT(&ipf_mutex);
6290
6291         return 0;
6292 }
6293
6294
6295 /* ------------------------------------------------------------------------ */
6296 /* Function:    fr_resolvedest                                              */
6297 /* Returns:     Nil                                                         */
6298 /* Parameters:  fdp(IO) - pointer to destination information to resolve     */
6299 /*              v(I)    - IP protocol version to match                      */
6300 /*                                                                          */
6301 /* Looks up an interface name in the frdest structure pointed to by fdp and */
6302 /* if a matching name can be found for the particular IP protocol version   */
6303 /* then store the interface pointer in the frdest struct.  If no match is   */
6304 /* found, then set the interface pointer to be -1 as NULL is considered to  */
6305 /* indicate there is no information at all in the structure.                */
6306 /* ------------------------------------------------------------------------ */
6307 void fr_resolvedest(fdp, v)
6308 frdest_t *fdp;
6309 int v;
6310 {
6311         void *ifp;
6312
6313         ifp = NULL;
6314         v = v;          /* LINT */
6315
6316         if (*fdp->fd_ifname != '\0') {
6317                 ifp = GETIFP(fdp->fd_ifname, v);
6318                 if (ifp == NULL)
6319                         ifp = (void *)-1;
6320         }
6321         fdp->fd_ifp = ifp;
6322 }
6323
6324
6325 /* ------------------------------------------------------------------------ */
6326 /* Function:    fr_resolvenic                                               */
6327 /* Returns:     void* - NULL = wildcard name, -1 = failed to find NIC, else */
6328 /*                      pointer to interface structure for NIC              */
6329 /* Parameters:  name(I) - complete interface name                           */
6330 /*              v(I)    - IP protocol version                               */
6331 /*                                                                          */
6332 /* Look for a network interface structure that firstly has a matching name  */
6333 /* to that passed in and that is also being used for that IP protocol       */
6334 /* version (necessary on some platforms where there are separate listings   */
6335 /* for both IPv4 and IPv6 on the same physical NIC.                         */
6336 /*                                                                          */
6337 /* One might wonder why name gets terminated with a \0 byte in here.  The   */
6338 /* reason is an interface name could get into the kernel structures of ipf  */
6339 /* in any number of ways and so long as they all use the same sized array   */
6340 /* to put the name in, it makes sense to ensure it gets null terminated     */
6341 /* before it is used for its intended purpose - finding its match in the    */
6342 /* kernel's list of configured interfaces.                                  */
6343 /*                                                                          */
6344 /* NOTE: This SHOULD ONLY be used with IPFilter structures that have an     */
6345 /*       array for the name that is LIFNAMSIZ bytes (at least) in length.   */
6346 /* ------------------------------------------------------------------------ */
6347 void *fr_resolvenic(name, v)
6348 char *name;
6349 int v;
6350 {
6351         void *nic;
6352
6353         if (name[0] == '\0')
6354                 return NULL;
6355
6356         if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) {
6357                 return NULL;
6358         }
6359
6360         name[LIFNAMSIZ - 1] = '\0';
6361
6362         nic = GETIFP(name, v);
6363         if (nic == NULL)
6364                 nic = (void *)-1;
6365         return nic;
6366 }