]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ipfilter/netinet/fil.c
Elminate 1 LOR (actually a recursive mutex grab) involving ipfilter where
[FreeBSD/FreeBSD.git] / sys / contrib / ipfilter / netinet / fil.c
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #if defined(__sgi) && (IRIX > 602)
7 # include <sys/ptimers.h>
8 #endif
9 #include <sys/errno.h>
10 #include <sys/types.h>
11 #include <sys/param.h>
12 #include <sys/time.h>
13 #include <sys/file.h>
14 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
15     defined(_KERNEL)
16 # include "opt_ipfilter_log.h"
17 #endif
18 #if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \
19     (__FreeBSD_version >= 220000)
20 # if (__FreeBSD_version >= 400000)
21 #  ifndef KLD_MODULE
22 #   include "opt_inet6.h"
23 #  endif
24 #  if (__FreeBSD_version == 400019)
25 #   define CSUM_DELAY_DATA
26 #  endif
27 # endif
28 # include <sys/filio.h>
29 # include <sys/fcntl.h>
30 #else
31 # include <sys/ioctl.h>
32 #endif
33 #if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
34 # include <sys/systm.h>
35 #else
36 # include <stdio.h>
37 # include <string.h>
38 # include <stdlib.h>
39 #endif
40 #if !defined(__SVR4) && !defined(__svr4__)
41 # ifndef linux
42 #  include <sys/mbuf.h>
43 # endif
44 #else
45 # include <sys/cmn_err.h>
46 # include <sys/byteorder.h>
47 # if SOLARIS2 < 5
48 #  include <sys/dditypes.h>
49 # endif
50 #  include <sys/stream.h>
51 #endif
52 #ifndef linux
53 # include <sys/protosw.h>
54 # include <sys/socket.h>
55 #endif
56 #include <net/if.h>
57 #ifdef sun
58 # include <net/af.h>
59 #endif
60 #include <net/route.h>
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #ifndef linux
65 # include <netinet/ip_var.h>
66 #endif
67 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
68 # include <sys/hashing.h>
69 # include <netinet/in_var.h>
70 #endif
71 #include <netinet/tcp.h>
72 #include <netinet/udp.h>
73 #include <netinet/ip_icmp.h>
74 #include "netinet/ip_compat.h"
75 #ifdef  USE_INET6
76 # include <netinet/icmp6.h>
77 # if !SOLARIS && defined(_KERNEL)
78 #  include <netinet6/in6_var.h>
79 # endif
80 #endif
81 #include <netinet/tcpip.h>
82 #include "netinet/ip_fil.h"
83 #include "netinet/ip_nat.h"
84 #include "netinet/ip_frag.h"
85 #include "netinet/ip_state.h"
86 #include "netinet/ip_proxy.h"
87 #include "netinet/ip_auth.h"
88 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
89 #  include <sys/malloc.h>
90 #  if defined(_KERNEL) && !defined(IPFILTER_LKM)
91 #   include "opt_ipfilter.h"
92 #  endif
93 # endif
94 #ifndef MIN
95 # define        MIN(a,b)        (((a)<(b))?(a):(b))
96 #endif
97 #include "netinet/ipl.h"
98
99 #include <machine/in_cksum.h>
100
101 #if !defined(lint)
102 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
103 static const char rcsid[] = "@(#)$FreeBSD$";
104 #endif
105
106 #ifndef _KERNEL
107 # include "ipf.h"
108 # include "ipt.h"
109 extern  int     opts;
110
111 # define        FR_VERBOSE(verb_pr)                     verbose verb_pr
112 # define        FR_DEBUG(verb_pr)                       debug verb_pr
113 # define        IPLLOG(a, c, d, e)              ipflog(a, c, d, e)
114 #else /* #ifndef _KERNEL */
115 # define        FR_VERBOSE(verb_pr)
116 # define        FR_DEBUG(verb_pr)
117 # define        IPLLOG(a, c, d, e)              ipflog(a, c, d, e)
118 # ifdef USE_MUTEX
119 extern  KRWLOCK_T       ipf_mutex, ipf_auth, ipf_nat;
120 extern  kmutex_t        ipf_rw;
121 # endif /* USE_MUTEX */
122 #endif /* _KERNEL */
123
124
125 struct  filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
126 struct  frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
127 #ifdef  USE_INET6
128                 *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } },
129                 *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } },
130 #endif
131                 *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
132 struct  frgroup *ipfgroups[3][2];
133 int     fr_flags = IPF_LOGGING;
134 int     fr_active = 0;
135 int     fr_chksrc = 0;
136 int     fr_minttl = 3;
137 int     fr_minttllog = 1;
138 #if defined(IPFILTER_DEFAULT_BLOCK)
139 int     fr_pass = FR_NOMATCH|FR_BLOCK;
140 #else
141 int     fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH);
142 #endif
143 char    ipfilter_version[] = IPL_VERSION;
144
145 fr_info_t       frcache[2];
146
147 static  int     frflushlist __P((int, minor_t, int *, frentry_t **));
148 #ifdef  _KERNEL
149 static  void    frsynclist __P((frentry_t *));
150 # ifndef __sgi
151 static  void    *ipf_pullup __P((mb_t *, fr_info_t *, int, void *));
152 # endif
153 #endif
154
155
156 /*
157  * bit values for identifying presence of individual IP options
158  */
159 struct  optlist ipopts[20] = {
160         { IPOPT_NOP,    0x000001 },
161         { IPOPT_RR,     0x000002 },
162         { IPOPT_ZSU,    0x000004 },
163         { IPOPT_MTUP,   0x000008 },
164         { IPOPT_MTUR,   0x000010 },
165         { IPOPT_ENCODE, 0x000020 },
166         { IPOPT_TS,     0x000040 },
167         { IPOPT_TR,     0x000080 },
168         { IPOPT_SECURITY, 0x000100 },
169         { IPOPT_LSRR,   0x000200 },
170         { IPOPT_E_SEC,  0x000400 },
171         { IPOPT_CIPSO,  0x000800 },
172         { IPOPT_SATID,  0x001000 },
173         { IPOPT_SSRR,   0x002000 },
174         { IPOPT_ADDEXT, 0x004000 },
175         { IPOPT_VISA,   0x008000 },
176         { IPOPT_IMITD,  0x010000 },
177         { IPOPT_EIP,    0x020000 },
178         { IPOPT_FINN,   0x040000 },
179         { 0,            0x000000 }
180 };
181
182 /*
183  * bit values for identifying presence of individual IP security options
184  */
185 struct  optlist secopt[8] = {
186         { IPSO_CLASS_RES4,      0x01 },
187         { IPSO_CLASS_TOPS,      0x02 },
188         { IPSO_CLASS_SECR,      0x04 },
189         { IPSO_CLASS_RES3,      0x08 },
190         { IPSO_CLASS_CONF,      0x10 },
191         { IPSO_CLASS_UNCL,      0x20 },
192         { IPSO_CLASS_RES2,      0x40 },
193         { IPSO_CLASS_RES1,      0x80 }
194 };
195
196
197 /*
198  * compact the IP header into a structure which contains just the info.
199  * which is useful for comparing IP headers with.
200  */
201 int     fr_makefrip(hlen, ip, fin)
202 int hlen;
203 ip_t *ip;
204 fr_info_t *fin;
205 {
206         u_short optmsk = 0, secmsk = 0, auth = 0;
207         int i, mv, ol, off, p, plen, v;
208 #if defined(_KERNEL)
209 # if SOLARIS
210         mb_t *m = fin->fin_qfm;
211 # else
212         mb_t *m = fin->fin_mp ? *fin->fin_mp : NULL;
213 # endif
214 #endif
215         fr_ip_t *fi = &fin->fin_fi;
216         struct optlist *op;
217         u_char *s, opt;
218         tcphdr_t *tcp;
219
220         fin->fin_rev = 0;
221         fin->fin_dp = NULL;
222         fin->fin_fr = NULL;
223         fin->fin_tcpf = 0;
224         fin->fin_data[0] = 0;
225         fin->fin_data[1] = 0;
226         fin->fin_rule = -1;
227         fin->fin_group = -1;
228         fin->fin_icode = ipl_unreach;
229         v = fin->fin_v;
230         fi->fi_v = v;
231         fin->fin_hlen = hlen;
232         if (v == 4) {
233                 fin->fin_id = ip->ip_id;
234                 fi->fi_tos = ip->ip_tos;
235 #if (OpenBSD >= 200311) && defined(_KERNEL)
236                 ip->ip_off = ntohs(ip->ip_off);
237 #endif
238                 off = (ip->ip_off & IP_OFFMASK);
239                 (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
240                 fi->fi_src.i6[1] = 0;
241                 fi->fi_src.i6[2] = 0;
242                 fi->fi_src.i6[3] = 0;
243                 fi->fi_dst.i6[1] = 0;
244                 fi->fi_dst.i6[2] = 0;
245                 fi->fi_dst.i6[3] = 0;
246                 fi->fi_saddr = ip->ip_src.s_addr;
247                 fi->fi_daddr = ip->ip_dst.s_addr;
248                 p = ip->ip_p;
249                 fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0;
250                 if (ip->ip_off & (IP_MF|IP_OFFMASK))
251                         fi->fi_fl |= FI_FRAG;
252 #if (OpenBSD >= 200311) && defined(_KERNEL)
253                 ip->ip_len = ntohs(ip->ip_len);
254 #endif
255                 plen = ip->ip_len;
256                 fin->fin_dlen = plen - hlen;
257         }
258 #ifdef  USE_INET6
259         else if (v == 6) {
260                 ip6_t *ip6 = (ip6_t *)ip;
261
262                 off = 0;
263                 p = ip6->ip6_nxt;
264                 fi->fi_p = p;
265                 fi->fi_ttl = ip6->ip6_hlim;
266                 fi->fi_src.in6 = ip6->ip6_src;
267                 fi->fi_dst.in6 = ip6->ip6_dst;
268                 fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff);
269                 fi->fi_tos = 0;
270                 fi->fi_fl = 0;
271                 plen = ntohs(ip6->ip6_plen);
272                 fin->fin_dlen = plen;
273                 plen += sizeof(*ip6);
274         }
275 #endif
276         else
277                 return -1;
278
279         fin->fin_off = off;
280         fin->fin_plen = plen;
281         tcp = (tcphdr_t *)((char *)ip + hlen);
282         fin->fin_misc = 0;
283         off <<= 3;
284
285         /*
286          * For both ICMPV6 & ICMP, we attempt to pullup the entire packet into
287          * a single buffer for recognised error return packets.  Why?  Because 
288          * the entire data section of the ICMP payload is considered to be of
289          * significance and maybe required in NAT/state processing, so rather
290          * than be careful later, attempt to get it all in one buffeer first.
291          * For TCP we just make sure the _entire_ TCP header is in the first
292          * buffer for convienience.
293          */
294         switch (p)
295         {
296 #ifdef USE_INET6
297         case IPPROTO_ICMPV6 :
298         {
299                 int minicmpsz = sizeof(struct icmp6_hdr);
300                 struct icmp6_hdr *icmp6;
301
302                 if (!(fin->fin_fl & FI_SHORT) && (fin->fin_dlen > 1)) {
303                         fin->fin_data[0] = *(u_short *)tcp;
304
305                         icmp6 = (struct icmp6_hdr *)tcp;
306
307                         switch (icmp6->icmp6_type)
308                         {
309                         case ICMP6_ECHO_REPLY :
310                         case ICMP6_ECHO_REQUEST :
311                                 minicmpsz = ICMP6_MINLEN;
312                                 break;
313                         case ICMP6_DST_UNREACH :
314                         case ICMP6_PACKET_TOO_BIG :
315                         case ICMP6_TIME_EXCEEDED :
316                         case ICMP6_PARAM_PROB :
317 # if defined(KERNEL) && !defined(__sgi)
318                                 if ((m != NULL) && (M_BLEN(m) < plen)) {
319                                         ip = ipf_pullup(m, fin, plen, ip);
320                                         if (ip == NULL)
321                                                 return -1;
322                                         tcp = (tcphdr_t *)((char *)ip + hlen);
323                                 }
324 # endif /* KERNEL && !__sgi */
325                                 minicmpsz = ICMP6ERR_IPICMPHLEN;
326                                 break;
327                         default :
328                                 break;
329                         }
330                 }
331
332                 if (!(fin->fin_dlen >= minicmpsz))
333                         fi->fi_fl |= FI_SHORT;
334
335                 break;
336         }
337 #endif /* USE_INET6 */
338
339         case IPPROTO_ICMP :
340         {
341                 int minicmpsz = sizeof(struct icmp);
342                 icmphdr_t *icmp;
343
344                 if (!off && (fin->fin_dlen > 1) && !(fin->fin_fl & FI_SHORT)) {
345                         fin->fin_data[0] = *(u_short *)tcp;
346
347                         icmp = (icmphdr_t *)tcp;
348
349                         /*
350                          * Minimum ICMP packet is type(1) code(1) cksum(2)
351                          * plus 4 bytes following, totalling 8 bytes.
352                          */
353                         switch (icmp->icmp_type)
354                         {
355                         case ICMP_ECHOREPLY :
356                         case ICMP_ECHO :
357                         /* Router discovery messages - RFC 1256 */
358                         case ICMP_ROUTERADVERT :
359                         case ICMP_ROUTERSOLICIT :
360                                 minicmpsz = ICMP_MINLEN;
361                                 break;
362                         /*
363                          * type(1) + code(1) + cksum(2) + id(2) seq(2) +
364                          * 3*timestamp(3*4)
365                          */
366                         case ICMP_TSTAMP :
367                         case ICMP_TSTAMPREPLY :
368                                 minicmpsz = ICMP_MINLEN + 12;
369                                 break;
370                         /*
371                          * type(1) + code(1) + cksum(2) + id(2) seq(2) +
372                          * mask(4)
373                          */
374                         case ICMP_MASKREQ :
375                         case ICMP_MASKREPLY :
376                                 minicmpsz = ICMP_MINLEN + 4;
377                                 break;
378                         /*
379                          * type(1) + code(1) + cksum(2) + arg(4) ip(20+)
380                          */
381                         case ICMP_UNREACH :
382                         case ICMP_SOURCEQUENCH :
383                         case ICMP_REDIRECT :
384                         case ICMP_TIMXCEED :
385                         case ICMP_PARAMPROB :
386 #if defined(KERNEL) && !defined(__sgi)
387                                 if ((m != NULL) && (M_BLEN(m) < plen)) {
388                                         ip = ipf_pullup(m, fin, plen, ip);
389                                         if (ip == NULL)
390                                                 return -1;
391                                         tcp = (tcphdr_t *)((char *)ip + hlen);
392                                 }
393 #endif /* KERNEL && !__sgi */
394                                 minicmpsz = ICMPERR_MINPKTLEN - sizeof(ip_t);
395                                 break;
396                         default :
397                                 minicmpsz = ICMP_MINLEN;
398                                 break;
399                         }
400                 }
401
402                 if ((!(plen >= hlen + minicmpsz) && !off) ||
403                     (off && off < sizeof(struct icmp)))
404                         fi->fi_fl |= FI_SHORT;
405                 break;
406         }
407
408         case IPPROTO_TCP :
409                 fi->fi_fl |= FI_TCPUDP;
410 #ifdef  USE_INET6
411                 if (v == 6) {
412                         if (plen < sizeof(struct tcphdr))
413                                 fi->fi_fl |= FI_SHORT;
414                 } else
415 #endif
416                 if (v == 4) {
417                         if ((!IPMINLEN(ip, tcphdr) && !off) ||
418                              (off && off < sizeof(struct tcphdr)))
419                                 fi->fi_fl |= FI_SHORT;
420                 }
421
422 #if defined(KERNEL) && !defined(__sgi)
423                 if (!off && !(fi->fi_fl & FI_SHORT)) {
424                         int tlen = hlen + (tcp->th_off << 2);
425
426                         if ((m != NULL) && (M_BLEN(m) < tlen)) {
427                                 ip = ipf_pullup(m, fin, tlen, ip);
428                                 if (ip == NULL)
429                                         return -1;
430                                 tcp = (tcphdr_t *)((char *)ip + hlen);
431                         }
432                 }
433 #endif /* _KERNEL && !_sgi */
434
435                 if (!(fi->fi_fl & FI_SHORT) && !off)
436                         fin->fin_tcpf = tcp->th_flags;
437                 goto getports;
438         case IPPROTO_UDP :
439                 fi->fi_fl |= FI_TCPUDP;
440 #ifdef  USE_INET6
441                 if (v == 6) {
442                         if (plen < sizeof(struct udphdr))
443                                 fi->fi_fl |= FI_SHORT;
444                 } else
445 #endif
446                 if (v == 4) {
447                         if ((!IPMINLEN(ip, udphdr) && !off) ||
448                             (off && off < sizeof(struct udphdr)))
449                                 fi->fi_fl |= FI_SHORT;
450                 }
451 getports:
452                 if (!off && (fin->fin_dlen > 3)) {
453                         fin->fin_data[0] = ntohs(tcp->th_sport);
454                         fin->fin_data[1] = ntohs(tcp->th_dport);
455                 }
456                 break;
457         case IPPROTO_ESP :
458 #ifdef  USE_INET6
459                 if (v == 6) {
460                         if (plen < 8)
461                                 fi->fi_fl |= FI_SHORT;
462                 } else
463 #endif
464                 if (v == 4) {
465                         if (((ip->ip_len < hlen + 8) && !off) ||
466                             (off && off < 8))
467                                 fi->fi_fl |= FI_SHORT;
468                 }
469                 break;
470         default :
471                 break;
472         }
473
474         fin->fin_dp = (char *)tcp;
475
476 #ifdef  USE_INET6
477         if (v == 6) {
478                 fi->fi_optmsk = 0;
479                 fi->fi_secmsk = 0;
480                 fi->fi_auth = 0;
481                 return 0;
482         }
483 #endif
484
485         for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) {
486                 opt = *s;
487                 if (opt == '\0')
488                         break;
489                 else if (opt == IPOPT_NOP)
490                         ol = 1;
491                 else {
492                         if (hlen < 2)
493                                 break;
494                         ol = (int)*(s + 1);
495                         if (ol < 2 || ol > hlen)
496                                 break;
497                 }
498                 for (i = 9, mv = 4; mv >= 0; ) {
499                         op = ipopts + i;
500                         if (opt == (u_char)op->ol_val) {
501                                 optmsk |= op->ol_bit;
502                                 if (opt == IPOPT_SECURITY) {
503                                         struct optlist *sp;
504                                         u_char  sec;
505                                         int j, m;
506
507                                         sec = *(s + 2); /* classification */
508                                         for (j = 3, m = 2; m >= 0; ) {
509                                                 sp = secopt + j;
510                                                 if (sec == sp->ol_val) {
511                                                         secmsk |= sp->ol_bit;
512                                                         auth = *(s + 3);
513                                                         auth *= 256;
514                                                         auth += *(s + 4);
515                                                         break;
516                                                 }
517                                                 if (sec < sp->ol_val)
518                                                         j -= m--;
519                                                 else
520                                                         j += m--;
521                                         }
522                                 }
523                                 break;
524                         }
525                         if (opt < op->ol_val)
526                                 i -= mv--;
527                         else
528                                 i += mv--;
529                 }
530                 hlen -= ol;
531                 s += ol;
532         }
533         if (auth && !(auth & 0x0100))
534                 auth &= 0xff00;
535         fi->fi_optmsk = optmsk;
536         fi->fi_secmsk = secmsk;
537         fi->fi_auth = auth;
538         return 0;
539 }
540
541
542 /*
543  * check an IP packet for TCP/UDP characteristics such as ports and flags.
544  */
545 int fr_tcpudpchk(ft, fin)
546 frtuc_t *ft;
547 fr_info_t *fin;
548 {
549         register u_short po, tup;
550         register char i;
551         register int err = 1;
552
553         /*
554          * Both ports should *always* be in the first fragment.
555          * So far, I cannot find any cases where they can not be.
556          *
557          * compare destination ports
558          */
559         if ((i = (int)ft->ftu_dcmp)) {
560                 po = ft->ftu_dport;
561                 tup = fin->fin_data[1];
562                 /*
563                  * Do opposite test to that required and
564                  * continue if that succeeds.
565                  */
566                 if (!--i && tup != po) /* EQUAL */
567                         err = 0;
568                 else if (!--i && tup == po) /* NOTEQUAL */
569                         err = 0;
570                 else if (!--i && tup >= po) /* LESSTHAN */
571                         err = 0;
572                 else if (!--i && tup <= po) /* GREATERTHAN */
573                         err = 0;
574                 else if (!--i && tup > po) /* LT or EQ */
575                         err = 0;
576                 else if (!--i && tup < po) /* GT or EQ */
577                         err = 0;
578                 else if (!--i &&           /* Out of range */
579                          (tup >= po && tup <= ft->ftu_dtop))
580                         err = 0;
581                 else if (!--i &&           /* In range */
582                          (tup <= po || tup >= ft->ftu_dtop))
583                         err = 0;
584         }
585         /*
586          * compare source ports
587          */
588         if (err && (i = (int)ft->ftu_scmp)) {
589                 po = ft->ftu_sport;
590                 tup = fin->fin_data[0];
591                 if (!--i && tup != po)
592                         err = 0;
593                 else if (!--i && tup == po)
594                         err = 0;
595                 else if (!--i && tup >= po)
596                         err = 0;
597                 else if (!--i && tup <= po)
598                         err = 0;
599                 else if (!--i && tup > po)
600                         err = 0;
601                 else if (!--i && tup < po)
602                         err = 0;
603                 else if (!--i &&           /* Out of range */
604                          (tup >= po && tup <= ft->ftu_stop))
605                         err = 0;
606                 else if (!--i &&           /* In range */
607                          (tup <= po || tup >= ft->ftu_stop))
608                         err = 0;
609         }
610
611         /*
612          * If we don't have all the TCP/UDP header, then how can we
613          * expect to do any sort of match on it ?  If we were looking for
614          * TCP flags, then NO match.  If not, then match (which should
615          * satisfy the "short" class too).
616          */
617         if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) {
618                 if (fin->fin_fl & FI_SHORT)
619                         return !(ft->ftu_tcpf | ft->ftu_tcpfm);
620                 /*
621                  * Match the flags ?  If not, abort this match.
622                  */
623                 if (ft->ftu_tcpfm &&
624                     ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) {
625                         FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
626                                  ft->ftu_tcpfm, ft->ftu_tcpf));
627                         err = 0;
628                 }
629         }
630         return err;
631 }
632
633 /*
634  * Check the input/output list of rules for a match and result.
635  * Could be per interface, but this gets real nasty when you don't have
636  * kernel sauce.
637  */
638 int fr_scanlist(passin, ip, fin, m)
639 u_32_t passin;
640 ip_t *ip;
641 register fr_info_t *fin;
642 void *m;
643 {
644         register struct frentry *fr;
645         register fr_ip_t *fi = &fin->fin_fi;
646         int rulen, portcmp = 0, off, skip = 0, logged = 0;
647         u_32_t pass, passt, passl;
648         frentry_t *frl;
649
650         frl = NULL;
651         pass = passin;
652         fr = fin->fin_fr;
653         fin->fin_fr = NULL;
654         off = fin->fin_off;
655
656         if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
657                 portcmp = 1;
658
659         for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
660                 if (skip) {
661                         FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags));
662                         skip--;
663                         continue;
664                 }
665                 /*
666                  * In all checks below, a null (zero) value in the
667                  * filter struture is taken to mean a wildcard.
668                  *
669                  * check that we are working for the right interface
670                  */
671 #ifdef  _KERNEL
672 # if    (BSD >= 199306)
673                 if (fin->fin_out != 0) {
674                         if ((fr->fr_oifa &&
675                              (fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif)))
676                                 continue;
677                 }
678 # endif
679 #else
680                 if (opts & (OPT_VERBOSE|OPT_DEBUG))
681                         printf("\n");
682 #endif
683
684                 FR_VERBOSE(("%c", fr->fr_skip ? 's' :
685                                   (pass & FR_PASS) ? 'p' : 
686                                   (pass & FR_AUTH) ? 'a' :
687                                   (pass & FR_ACCOUNT) ? 'A' :
688                                   (pass & FR_NOMATCH) ? 'n' : 'b'));
689
690                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
691                         continue;
692
693                 FR_VERBOSE((":i"));
694                 {
695                         register u_32_t *ld, *lm, *lip;
696                         register int i;
697
698                         lip = (u_32_t *)fi;
699                         lm = (u_32_t *)&fr->fr_mip;
700                         ld = (u_32_t *)&fr->fr_ip;
701                         i = ((*lip & *lm) != *ld);
702                         FR_DEBUG(("0. %#08x & %#08x != %#08x\n",
703                                    *lip, *lm, *ld));
704                         if (i)
705                                 continue;
706                         /*
707                          * We now know whether the packet version and the
708                          * rule version match, along with protocol, ttl and
709                          * tos.
710                          */
711                         lip++, lm++, ld++;
712                         /*
713                          * Unrolled loops (4 each, for 32 bits).
714                          */
715                         FR_DEBUG(("1a. %#08x & %#08x != %#08x\n",
716                                    *lip, *lm, *ld));
717                         i |= ((*lip++ & *lm++) != *ld++) << 5;
718                         if (fi->fi_v == 6) {
719                                 FR_DEBUG(("1b. %#08x & %#08x != %#08x\n",
720                                            *lip, *lm, *ld));
721                                 i |= ((*lip++ & *lm++) != *ld++) << 5;
722                                 FR_DEBUG(("1c. %#08x & %#08x != %#08x\n",
723                                            *lip, *lm, *ld));
724                                 i |= ((*lip++ & *lm++) != *ld++) << 5;
725                                 FR_DEBUG(("1d. %#08x & %#08x != %#08x\n",
726                                            *lip, *lm, *ld));
727                                 i |= ((*lip++ & *lm++) != *ld++) << 5;
728                         } else {
729                                 lip += 3;
730                                 lm += 3;
731                                 ld += 3;
732                         }
733                         i ^= (fr->fr_flags & FR_NOTSRCIP);
734                         if (i)
735                                 continue;
736                         FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
737                                    *lip, *lm, *ld));
738                         i |= ((*lip++ & *lm++) != *ld++) << 6;
739                         if (fi->fi_v == 6) {
740                                 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n",
741                                            *lip, *lm, *ld));
742                                 i |= ((*lip++ & *lm++) != *ld++) << 6;
743                                 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n",
744                                            *lip, *lm, *ld));
745                                 i |= ((*lip++ & *lm++) != *ld++) << 6;
746                                 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n",
747                                            *lip, *lm, *ld));
748                                 i |= ((*lip++ & *lm++) != *ld++) << 6;
749                         } else {
750                                 lip += 3;
751                                 lm += 3;
752                                 ld += 3;
753                         }
754                         i ^= (fr->fr_flags & FR_NOTDSTIP);
755                         if (i)
756                                 continue;
757                         FR_DEBUG(("3. %#08x & %#08x != %#08x\n",
758                                    *lip, *lm, *ld));
759                         i |= ((*lip++ & *lm++) != *ld++);
760                         FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
761                                    *lip, *lm, *ld));
762                         i |= ((*lip & *lm) != *ld);
763                         if (i)
764                                 continue;
765                 }
766
767                 /*
768                  * If a fragment, then only the first has what we're looking
769                  * for here...
770                  */
771                 if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
772                                  fr->fr_tcpfm))
773                         continue;
774                 if (fi->fi_fl & FI_TCPUDP) {
775                         if (!fr_tcpudpchk(&fr->fr_tuc, fin))
776                                 continue;
777                 } else if (fr->fr_icmpm || fr->fr_icmp) {
778                         if (((fi->fi_p != IPPROTO_ICMP) &&
779                             (fi->fi_p != IPPROTO_ICMPV6)) || off ||
780                             (fin->fin_dlen < 2))
781                                 continue;
782                         if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) {
783                                 FR_DEBUG(("i. %#x & %#x != %#x\n",
784                                          fin->fin_data[0], fr->fr_icmpm,
785                                          fr->fr_icmp));
786                                 continue;
787                         }
788                 }
789                 FR_VERBOSE(("*"));
790
791                 if (fr->fr_flags & FR_NOMATCH) {
792                         passt = passl;
793                         passl = passin;
794                         fin->fin_fr = frl;
795                         frl = NULL;
796                         if (fr->fr_flags & FR_QUICK)
797                                 break;
798                         continue;
799                 }
800
801                 passl = passt;
802                 passt = fr->fr_flags;
803                 frl = fin->fin_fr;
804                 fin->fin_fr = fr;
805 #if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL))
806                 if (securelevel <= 0)
807 #endif
808                         if ((passt & FR_CALLNOW) && fr->fr_func)
809                                 passt = (*fr->fr_func)(passt, ip, fin);
810 #ifdef  IPFILTER_LOG
811                 /*
812                  * Just log this packet...
813                  */
814                 if ((passt & FR_LOGMASK) == FR_LOG) {
815                         if (!IPLLOG(passt, ip, fin, m)) {
816                                 if (passt & FR_LOGORBLOCK)
817                                         passt |= FR_BLOCK|FR_QUICK;
818                                 ATOMIC_INCL(frstats[fin->fin_out].fr_skip);
819                         }
820                         ATOMIC_INCL(frstats[fin->fin_out].fr_pkl);
821                         logged = 1;
822                 }
823 #endif /* IPFILTER_LOG */
824                 ATOMIC_INCL(fr->fr_hits);
825                 if (passt & FR_ACCOUNT)
826                         fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
827                 else
828                         fin->fin_icode = fr->fr_icode;
829                 fin->fin_rule = rulen;
830                 fin->fin_group = fr->fr_group;
831                 if (fr->fr_grp != NULL) {
832                         fin->fin_fr = fr->fr_grp;
833                         passt = fr_scanlist(passt, ip, fin, m);
834                         if (fin->fin_fr == NULL) {
835                                 fin->fin_rule = rulen;
836                                 fin->fin_group = fr->fr_group;
837                                 fin->fin_fr = fr;
838                         }
839                         if (passt & FR_DONTCACHE)
840                                 logged = 1;
841                 }
842                 if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG)
843                         pass = passt;
844                 FR_DEBUG(("pass %#x\n", pass));
845                 if (passt & FR_QUICK)
846                         break;
847         }
848         if (logged)
849                 pass |= FR_DONTCACHE;
850         pass |= (fi->fi_fl << 24);
851         return pass;
852 }
853
854
855 /*
856  * frcheck - filter check
857  * check using source and destination addresses/ports in a packet whether
858  * or not to pass it on or not.
859  */
860 int fr_check(ip, hlen, ifp, out
861 #if defined(_KERNEL) && SOLARIS
862 , qif, mp)
863 qif_t *qif;
864 #else
865 , mp)
866 #endif
867 mb_t **mp;
868 ip_t *ip;
869 int hlen;
870 void *ifp;
871 int out;
872 {
873         /*
874          * The above really sucks, but short of writing a diff
875          */
876         fr_info_t frinfo, *fc;
877         register fr_info_t *fin = &frinfo;
878         int changed, error = EHOSTUNREACH, v = ip->ip_v;
879         frentry_t *fr = NULL, *list;
880         u_32_t pass, apass;
881 #if !SOLARIS || !defined(_KERNEL)
882         register mb_t *m = *mp;
883 #endif
884
885 #ifdef  _KERNEL
886         int p, len, drop = 0, logit = 0;
887         mb_t *mc = NULL;
888 # if !defined(__SVR4) && !defined(__svr4__)
889         /*
890          * We don't do this section for Solaris because fr_precheck() does a
891          * pullupmsg() instead, effectively achieving the same result as here
892          * so no need to duplicate it.
893          */
894 #  ifdef __sgi
895         char hbuf[128];
896 #  endif
897         int up;
898
899 #  if !defined(NETBSD_PF) && \
900       ((defined(__FreeBSD__) && (__FreeBSD_version < 500011)) || \
901        defined(__OpenBSD__) || defined(_BSDI_VERSION))
902         if (fr_checkp != fr_check && fr_running > 0) {
903                 static int counter = 0;
904
905                 if (counter == 0) {
906                         printf("WARNING: fr_checkp corrupt: value %lx\n",
907                                 (u_long)fr_checkp);
908                         printf("WARNING: fr_checkp should be %lx\n",
909                                 (u_long)fr_check);
910                         printf("WARNING: fixing fr_checkp\n");
911                 }
912                 fr_checkp = fr_check;
913                 counter++;
914                 if (counter == 10000)
915                         counter = 0;
916         }
917 #  endif
918
919 #  ifdef M_CANFASTFWD
920         /*
921          * XXX For now, IP Filter and fast-forwarding of cached flows
922          * XXX are mutually exclusive.  Eventually, IP Filter should
923          * XXX get a "can-fast-forward" filter rule.
924          */
925         m->m_flags &= ~M_CANFASTFWD;
926 #  endif /* M_CANFASTFWD */
927 #  ifdef CSUM_DELAY_DATA
928         /*
929          * disable delayed checksums.
930          */
931         if ((out != 0) && (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)) {
932                 in_delayed_cksum(m);
933                 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
934         }
935 #  endif /* CSUM_DELAY_DATA */
936
937 #  ifdef        USE_INET6
938         if (v == 6) {
939                 len = ntohs(((ip6_t*)ip)->ip6_plen);
940                 if (!len)
941                         return -1;      /* potential jumbo gram */
942                 len += sizeof(ip6_t);
943                 p = ((ip6_t *)ip)->ip6_nxt;
944         } else
945 #  endif
946         {
947                 p = ip->ip_p;
948                 len = ip->ip_len;
949         }
950
951         fin->fin_mp = mp;
952         fin->fin_out = out;
953
954         if ((p == IPPROTO_TCP || p == IPPROTO_UDP ||
955             (v == 4 && p == IPPROTO_ICMP)
956 #  ifdef USE_INET6
957             || (v == 6 && p == IPPROTO_ICMPV6)
958 #  endif
959            )) {
960                 int plen = 0;
961
962                 if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0)
963                         switch(p)
964                         {
965                         case IPPROTO_TCP:
966                                 plen = sizeof(tcphdr_t);
967                                 break;
968                         case IPPROTO_UDP:
969                                 plen = sizeof(udphdr_t);
970                                 break;
971                         /* 96 - enough for complete ICMP error IP header */
972                         case IPPROTO_ICMP:
973                                 plen = ICMPERR_MAXPKTLEN - sizeof(ip_t);
974                                 break;
975                         case IPPROTO_ESP:
976                                 plen = 8;
977                                 break;
978 #  ifdef USE_INET6
979                         case IPPROTO_ICMPV6 :
980                                 /*
981                                  * XXX does not take intermediate header
982                                  * into account
983                                  */
984                                 plen = ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t);
985                                 break;
986 #  endif
987                         }
988                 if ((plen > 0) && (len < hlen + plen))
989                         fin->fin_fl |= FI_SHORT;
990                 up = MIN(hlen + plen, len);
991
992                 if (up > m->m_len) {
993 #  ifdef __sgi
994         /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */
995                         if ((up > sizeof(hbuf)) || (m_length(m) < up)) {
996                                 ATOMIC_INCL(frstats[out].fr_pull[1]);
997                                 return -1;
998                         }
999                         m_copydata(m, 0, up, hbuf);
1000                         ATOMIC_INCL(frstats[out].fr_pull[0]);
1001                         ip = (ip_t *)hbuf;
1002 #  else /* __ sgi */
1003 #   ifndef linux
1004                         /*
1005                          * Having determined that we need to pullup some data,
1006                          * try to bring as much of the packet up into a single
1007                          * buffer with the first pullup.  This hopefully means
1008                          * less need for doing futher pullups.  Not needed for
1009                          * Solaris because fr_precheck() does it anyway.
1010                          *
1011                          * The main potential for trouble here is if MLEN/MHLEN
1012                          * become quite small, lets say < 64 bytes...but if
1013                          * that did happen, BSD networking as a whole would be
1014                          * slow/inefficient.
1015                          */
1016 #    ifdef MHLEN
1017                         /*
1018                          * Assume that M_PKTHDR is set and just work with what
1019                          * is left rather than check..  Should not make any
1020                          * real difference, anyway.
1021                          */
1022                         if ((MHLEN > up) && (len > up))
1023                                 up = MIN(len, MHLEN);
1024 #    else
1025                         if ((MLEN > up) && (len > up))
1026                                 up = MIN(len, MLEN);
1027 #    endif
1028                         ip = ipf_pullup(m, fin, up, ip);
1029                         if (ip == NULL)
1030                                 return -1;
1031                         m = *mp;
1032 #   endif /* !linux */
1033 #  endif /* __sgi */
1034                 } else
1035                         up = 0;
1036         } else
1037                 up = 0;
1038 # endif /* !defined(__SVR4) && !defined(__svr4__) */
1039 # if SOLARIS
1040         mb_t *m = qif->qf_m;
1041
1042         if ((u_int)ip & 0x3)
1043                 return 2;
1044         fin->fin_mp = mp;
1045         fin->fin_out = out;
1046         fin->fin_qfm = m;
1047         fin->fin_qif = qif;
1048 # endif
1049 #else
1050         fin->fin_mp = mp;
1051         fin->fin_out = out;
1052 #endif /* _KERNEL */
1053         
1054         changed = 0;
1055         fin->fin_v = v;
1056         fin->fin_ifp = ifp;
1057         if (fr_makefrip(hlen, ip, fin) == -1)
1058                 return -1;
1059
1060 #ifdef _KERNEL
1061 # ifdef USE_INET6
1062         if (v == 6) {
1063                 ATOMIC_INCL(frstats[0].fr_ipv6[out]);
1064                 if (((ip6_t *)ip)->ip6_hlim < fr_minttl) {
1065                         ATOMIC_INCL(frstats[0].fr_badttl);
1066                         if (fr_minttllog & 1)
1067                                 logit = -3;
1068                         if (fr_minttllog & 2)
1069                                 drop = 1;
1070                 }
1071         } else
1072 # endif
1073         if (!out) {
1074                 if (fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) {
1075                         ATOMIC_INCL(frstats[0].fr_badsrc);
1076                         if (fr_chksrc & 1)
1077                                 drop = 1;
1078                         if (fr_chksrc & 2)
1079                                 logit = -2;
1080                 } else if (ip->ip_ttl < fr_minttl) {
1081                         ATOMIC_INCL(frstats[0].fr_badttl);
1082                         if (fr_minttllog & 1)
1083                                 logit = -3;
1084                         if (fr_minttllog & 2)
1085                                 drop = 1;
1086                 }
1087         }
1088         if (drop) {
1089 # ifdef IPFILTER_LOG
1090                 if (logit) {
1091                         fin->fin_group = logit;
1092                         pass = FR_INQUE|FR_NOMATCH|FR_LOGB;
1093                         (void) IPLLOG(pass, ip, fin, m);
1094                 }
1095 # endif
1096 # if !SOLARIS
1097                 m_freem(m);
1098 # endif
1099                 return error;
1100         }
1101 #endif
1102         pass = fr_pass;
1103         if (fin->fin_fl & FI_SHORT) {
1104                 ATOMIC_INCL(frstats[out].fr_short);
1105         }
1106
1107         READ_ENTER(&ipf_mutex);
1108
1109         /*
1110          * Check auth now.  This, combined with the check below to see if apass
1111          * is 0 is to ensure that we don't count the packet twice, which can
1112          * otherwise occur when we reprocess it.  As it is, we only count it
1113          * after it has no auth. table matchup.  This also stops NAT from
1114          * occuring until after the packet has been auth'd.
1115          */
1116         apass = fr_checkauth(ip, fin);
1117
1118         if (!out) {
1119 #ifdef  USE_INET6
1120                 if (v == 6)
1121                         list = ipacct6[0][fr_active];
1122                 else
1123 #endif
1124                         list = ipacct[0][fr_active];
1125                 changed = ip_natin(ip, fin);
1126                 if (!apass && (fin->fin_fr = list) &&
1127                     (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
1128                         ATOMIC_INCL(frstats[0].fr_acct);
1129                 }
1130         }
1131
1132         if (!apass) {
1133                 if ((fin->fin_fl & FI_FRAG) == FI_FRAG)
1134                         fr = ipfr_knownfrag(ip, fin);
1135                 if (!fr && !(fin->fin_fl & FI_SHORT))
1136                         fr = fr_checkstate(ip, fin);
1137                 if (fr != NULL)
1138                         pass = fr->fr_flags;
1139                 if (fr && (pass & FR_LOGFIRST))
1140                         pass &= ~(FR_LOGFIRST|FR_LOG);
1141         }
1142
1143         if (apass || !fr) {
1144                 /*
1145                  * If a packet is found in the auth table, then skip checking
1146                  * the access lists for permission but we do need to consider
1147                  * the result as if it were from the ACL's.
1148                  */
1149                 if (!apass) {
1150                         fc = frcache + out;
1151                         if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
1152                                 /*
1153                                  * copy cached data so we can unlock the mutex
1154                                  * earlier.
1155                                  */
1156                                 bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
1157                                 ATOMIC_INCL(frstats[out].fr_chit);
1158                                 if ((fr = fin->fin_fr)) {
1159                                         ATOMIC_INCL(fr->fr_hits);
1160                                         pass = fr->fr_flags;
1161                                 }
1162                         } else {
1163 #ifdef  USE_INET6
1164                                 if (v == 6)
1165                                         list = ipfilter6[out][fr_active];
1166                                 else
1167 #endif
1168                                         list = ipfilter[out][fr_active];
1169                                 if ((fin->fin_fr = list))
1170                                         pass = fr_scanlist(fr_pass, ip, fin, m);
1171                                 if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE)))
1172                                         bcopy((char *)fin, (char *)fc,
1173                                               FI_COPYSIZE);
1174                                 if (pass & FR_NOMATCH) {
1175                                         ATOMIC_INCL(frstats[out].fr_nom);
1176                                         fin->fin_fr = NULL;
1177                                 }
1178                         }
1179                 } else
1180                         pass = apass;
1181                 fr = fin->fin_fr;
1182
1183                 /*
1184                  * If we fail to add a packet to the authorization queue,
1185                  * then we drop the packet later.  However, if it was added
1186                  * then pretend we've dropped it already.
1187                  */
1188                 if ((pass & FR_AUTH)) {
1189                         if (fr_newauth((mb_t *)m, fin, ip) != 0) {
1190                                 m = *mp = NULL;
1191                                 error = 0;
1192                         } else
1193                                 error = ENOSPC;
1194                 }
1195
1196                 if (pass & FR_PREAUTH) {
1197                         READ_ENTER(&ipf_auth);
1198                         if ((fin->fin_fr = ipauth) &&
1199                             (pass = fr_scanlist(0, ip, fin, m))) {
1200                                 ATOMIC_INCL(fr_authstats.fas_hits);
1201                         } else {
1202                                 ATOMIC_INCL(fr_authstats.fas_miss);
1203                         }
1204                         RWLOCK_EXIT(&ipf_auth);
1205                 }
1206
1207                 fin->fin_fr = fr;
1208                 if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
1209                         if (fin->fin_fl & FI_FRAG) {
1210                                 if (ipfr_newfrag(ip, fin) == -1) {
1211                                         ATOMIC_INCL(frstats[out].fr_bnfr);
1212                                 } else {
1213                                         ATOMIC_INCL(frstats[out].fr_nfr);
1214                                 }
1215                         } else {
1216                                 ATOMIC_INCL(frstats[out].fr_cfr);
1217                         }
1218                 }
1219                 if (pass & FR_KEEPSTATE) {
1220                         if (fr_addstate(ip, fin, NULL, 0) == NULL) {
1221                                 ATOMIC_INCL(frstats[out].fr_bads);
1222                                 if (pass & FR_PASS) {
1223                                         pass &= ~FR_PASS;
1224                                         pass |= FR_BLOCK;
1225                                 }
1226                         } else {
1227                                 ATOMIC_INCL(frstats[out].fr_ads);
1228                         }
1229                 }
1230         } else if (fr != NULL) {
1231                 pass = fr->fr_flags;
1232                 if (pass & FR_LOGFIRST)
1233                         pass &= ~(FR_LOGFIRST|FR_LOG);
1234         }
1235
1236 #if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL))
1237         if (securelevel <= 0)
1238 #endif
1239                 if (fr && fr->fr_func && !(pass & FR_CALLNOW))
1240                         pass = (*fr->fr_func)(pass, ip, fin);
1241
1242         /*
1243          * Only count/translate packets which will be passed on, out the
1244          * interface.
1245          */
1246         if (out && (pass & FR_PASS)) {
1247 #ifdef  USE_INET6
1248                 if (v == 6)
1249                         list = ipacct6[1][fr_active];
1250                 else
1251 #endif
1252                         list = ipacct[1][fr_active];
1253                 if (list != NULL) {
1254                         u_32_t sg, sr;
1255
1256                         fin->fin_fr = list;
1257                         sg = fin->fin_group;
1258                         sr = fin->fin_rule;
1259                         if (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT) {
1260                                 ATOMIC_INCL(frstats[1].fr_acct);
1261                         }
1262                         fin->fin_group = sg;
1263                         fin->fin_rule = sr;
1264                         fin->fin_fr = fr;
1265                 }
1266                 changed = ip_natout(ip, fin);
1267         } else
1268                 fin->fin_fr = fr;
1269         RWLOCK_EXIT(&ipf_mutex);
1270
1271 #ifdef  IPFILTER_LOG
1272         if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
1273                 if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
1274                         pass |= FF_LOGNOMATCH;
1275                         ATOMIC_INCL(frstats[out].fr_npkl);
1276                         goto logit;
1277                 } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
1278                     ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
1279                         if ((pass & FR_LOGMASK) != FR_LOGP)
1280                                 pass |= FF_LOGPASS;
1281                         ATOMIC_INCL(frstats[out].fr_ppkl);
1282                         goto logit;
1283                 } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
1284                            ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
1285                         if ((pass & FR_LOGMASK) != FR_LOGB)
1286                                 pass |= FF_LOGBLOCK;
1287                         ATOMIC_INCL(frstats[out].fr_bpkl);
1288 logit:
1289                         if (!IPLLOG(pass, ip, fin, m)) {
1290                                 ATOMIC_INCL(frstats[out].fr_skip);
1291                                 if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
1292                                     (FR_PASS|FR_LOGORBLOCK))
1293                                         pass ^= FR_PASS|FR_BLOCK;
1294                         }
1295                 }
1296         }
1297 #endif /* IPFILTER_LOG */
1298
1299 #ifdef  _KERNEL
1300         /*
1301          * Only allow FR_DUP to work if a rule matched - it makes no sense to
1302          * set FR_DUP as a "default" as there are no instructions about where
1303          * to send the packet.
1304          */
1305         if (fr && (pass & FR_DUP))
1306 # if    SOLARIS
1307                 mc = dupmsg(m);
1308 # else
1309 #  if defined(__OpenBSD__) && (OpenBSD >= 199905)
1310                 mc = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
1311 #  else
1312                 mc = m_copy(m, 0, M_COPYALL);
1313 #  endif
1314 # endif
1315 #endif
1316         if (pass & FR_PASS) {
1317                 ATOMIC_INCL(frstats[out].fr_pass);
1318         } else if (pass & FR_BLOCK) {
1319                 ATOMIC_INCL(frstats[out].fr_block);
1320                 /*
1321                  * Should we return an ICMP packet to indicate error
1322                  * status passing through the packet filter ?
1323                  * WARNING: ICMP error packets AND TCP RST packets should
1324                  * ONLY be sent in repsonse to incoming packets.  Sending them
1325                  * in response to outbound packets can result in a panic on
1326                  * some operating systems.
1327                  */
1328                 if (!out) {
1329                         if (changed == -1)
1330                                 /*
1331                                  * If a packet results in a NAT error, do not
1332                                  * send a reset or ICMP error as it may disrupt
1333                                  * an existing flow.  This is the proxy saying
1334                                  * the content is bad so just drop the packet
1335                                  * silently.
1336                                  */
1337                                 ;
1338                         else if (pass & FR_RETICMP) {
1339                                 int dst;
1340
1341                                 if ((pass & FR_RETMASK) == FR_FAKEICMP)
1342                                         dst = 1;
1343                                 else
1344                                         dst = 0;
1345                                 send_icmp_err(ip, ICMP_UNREACH, fin, dst);
1346                                 ATOMIC_INCL(frstats[0].fr_ret);
1347                         } else if (((pass & FR_RETMASK) == FR_RETRST) &&
1348                                    !(fin->fin_fl & FI_SHORT)) {
1349                                 if (send_reset(ip, fin) == 0) {
1350                                         ATOMIC_INCL(frstats[1].fr_ret);
1351                                 }
1352                         }
1353                 } else {
1354                         if (pass & FR_RETRST)
1355                                 error = ECONNRESET;
1356                 }
1357         }
1358
1359         /*
1360          * If we didn't drop off the bottom of the list of rules (and thus
1361          * the 'current' rule fr is not NULL), then we may have some extra
1362          * instructions about what to do with a packet.
1363          * Once we're finished return to our caller, freeing the packet if
1364          * we are dropping it (* BSD ONLY *).
1365          */
1366         if ((changed == -1) && (pass & FR_PASS)) {
1367                 pass &= ~FR_PASS;
1368                 pass |= FR_BLOCK;
1369         }
1370 #if defined(_KERNEL)
1371 # if !SOLARIS
1372 #  if !defined(linux)
1373         if (fr) {
1374                 frdest_t *fdp = &fr->fr_tif;
1375
1376                 if (((pass & FR_FASTROUTE) && !out) ||
1377                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
1378                         (void) ipfr_fastroute(m, mp, fin, fdp);
1379                         m = *mp;
1380                 }
1381
1382                 if (mc != NULL)
1383                         (void) ipfr_fastroute(mc, &mc, fin, &fr->fr_dif);
1384         }
1385
1386         if (!(pass & FR_PASS) && m) {
1387                 m_freem(m);
1388                 m = *mp = NULL;
1389         }
1390 #   ifdef __sgi
1391         else if (changed && up && m)
1392                 m_copyback(m, 0, up, hbuf);
1393 #   endif
1394 #  endif /* !linux */
1395 # else /* !SOLARIS */
1396         if (fr) {
1397                 frdest_t *fdp = &fr->fr_tif;
1398
1399                 if (((pass & FR_FASTROUTE) && !out) ||
1400                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1))
1401                         (void) ipfr_fastroute(ip, m, mp, fin, fdp);
1402
1403                 if (mc != NULL)
1404                         (void) ipfr_fastroute(ip, mc, &mc, fin, &fr->fr_dif);
1405         }
1406 # endif /* !SOLARIS */
1407 #if (OpenBSD >= 200311) && defined(_KERNEL)
1408         if (pass & FR_PASS) {
1409                 ip->ip_len = htons(ip->ip_len);
1410                 ip->ip_off = htons(ip->ip_off);
1411         }
1412 #endif
1413         return (pass & FR_PASS) ? 0 : error;
1414 #else /* _KERNEL */
1415         if (pass & FR_NOMATCH)
1416                 return 1;
1417         if (pass & FR_PASS)
1418                 return 0;
1419         if (pass & FR_AUTH)
1420                 return -2;
1421         if ((pass & FR_RETMASK) == FR_RETRST)
1422                 return -3;
1423         if ((pass & FR_RETMASK) == FR_RETICMP)
1424                 return -4;
1425         if ((pass & FR_RETMASK) == FR_FAKEICMP)
1426                 return -5;
1427         return -1;
1428 #endif /* _KERNEL */
1429 }
1430
1431
1432 /*
1433  * ipf_cksum
1434  * addr should be 16bit aligned and len is in bytes.
1435  * length is in bytes
1436  */
1437 u_short ipf_cksum(addr, len)
1438 register u_short *addr;
1439 register int len;
1440 {
1441         register u_32_t sum = 0;
1442
1443         for (sum = 0; len > 1; len -= 2)
1444                 sum += *addr++;
1445
1446         /* mop up an odd byte, if necessary */
1447         if (len == 1)
1448                 sum += *(u_char *)addr;
1449
1450         /*
1451          * add back carry outs from top 16 bits to low 16 bits
1452          */
1453         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
1454         sum += (sum >> 16);                     /* add carry */
1455         return (u_short)(~sum);
1456 }
1457
1458
1459 /*
1460  * NB: This function assumes we've pullup'd enough for all of the IP header
1461  * and the TCP header.  We also assume that data blocks aren't allocated in
1462  * odd sizes.
1463  */
1464 u_short fr_tcpsum(m, ip, tcp)
1465 mb_t *m;
1466 ip_t *ip;
1467 tcphdr_t *tcp;
1468 {
1469         u_short *sp, slen, ts;
1470         u_int sum, sum2;
1471         int hlen;
1472
1473         /*
1474          * Add up IP Header portion
1475          */
1476         hlen = ip->ip_hl << 2;
1477         slen = ip->ip_len - hlen;
1478         sum = htons((u_short)ip->ip_p);
1479         sum += htons(slen);
1480         sp = (u_short *)&ip->ip_src;
1481         sum += *sp++;   /* ip_src */
1482         sum += *sp++;
1483         sum += *sp++;   /* ip_dst */
1484         sum += *sp++;
1485         ts = tcp->th_sum;
1486         tcp->th_sum = 0;
1487 #ifdef  KERNEL
1488 # if SOLARIS
1489         sum2 = ip_cksum(m, hlen, sum);  /* hlen == offset */
1490         sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1491         sum2 = ~sum2 & 0xffff;
1492 # else /* SOLARIS */
1493 #  if defined(BSD) || defined(sun)
1494 #   if BSD >= 199306
1495         m->m_data += hlen;
1496 #   else
1497         m->m_off += hlen;
1498 #   endif
1499         m->m_len -= hlen;
1500         sum2 = in_cksum(m, slen);
1501         m->m_len += hlen;
1502 #   if BSD >= 199306
1503         m->m_data -= hlen;
1504 #   else
1505         m->m_off -= hlen;
1506 #   endif
1507         /*
1508          * Both sum and sum2 are partial sums, so combine them together.
1509          */
1510         sum += ~sum2 & 0xffff;
1511         while (sum > 0xffff)
1512                 sum = (sum & 0xffff) + (sum >> 16);
1513         sum2 = ~sum & 0xffff;
1514 #  else /* defined(BSD) || defined(sun) */
1515 {
1516         union {
1517                 u_char  c[2];
1518                 u_short s;
1519         } bytes;
1520         u_short len = ip->ip_len;
1521 # if defined(__sgi)
1522         int add;
1523 # endif
1524
1525         /*
1526          * Add up IP Header portion
1527          */
1528         sp = (u_short *)&ip->ip_src;
1529         len -= (ip->ip_hl << 2);
1530         sum = ntohs(IPPROTO_TCP);
1531         sum += htons(len);
1532         sum += *sp++;   /* ip_src */
1533         sum += *sp++;
1534         sum += *sp++;   /* ip_dst */
1535         sum += *sp++;
1536         if (sp != (u_short *)tcp)
1537                 sp = (u_short *)tcp;
1538         sum += *sp++;   /* sport */
1539         sum += *sp++;   /* dport */
1540         sum += *sp++;   /* seq */
1541         sum += *sp++;
1542         sum += *sp++;   /* ack */
1543         sum += *sp++;
1544         sum += *sp++;   /* off */
1545         sum += *sp++;   /* win */
1546         sum += *sp++;   /* Skip over checksum */
1547         sum += *sp++;   /* urp */
1548
1549 # ifdef __sgi
1550         /*
1551          * In case we had to copy the IP & TCP header out of mbufs,
1552          * skip over the mbuf bits which are the header
1553          */
1554         if ((caddr_t)ip != mtod(m, caddr_t)) {
1555                 hlen = (caddr_t)sp - (caddr_t)ip;
1556                 while (hlen) {
1557                         add = MIN(hlen, m->m_len);
1558                         sp = (u_short *)(mtod(m, caddr_t) + add);
1559                         hlen -= add;
1560                         if (add == m->m_len) {
1561                                 m = m->m_next;
1562                                 if (!hlen) {
1563                                         if (!m)
1564                                                 break;
1565                                         sp = mtod(m, u_short *);
1566                                 }
1567                                 PANIC((!m),("fr_tcpsum(1): not enough data"));
1568                         }
1569                 }
1570         }
1571 # endif
1572
1573         if (!(len -= sizeof(*tcp)))
1574                 goto nodata;
1575         while (len > 1) {
1576                 if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) {
1577                         m = m->m_next;
1578                         PANIC((!m),("fr_tcpsum(2): not enough data"));
1579                         sp = mtod(m, u_short *);
1580                 }
1581                 if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) {
1582                         bytes.c[0] = *(u_char *)sp;
1583                         m = m->m_next;
1584                         PANIC((!m),("fr_tcpsum(3): not enough data"));
1585                         sp = mtod(m, u_short *);
1586                         bytes.c[1] = *(u_char *)sp;
1587                         sum += bytes.s;
1588                         sp = (u_short *)((u_char *)sp + 1);
1589                 }
1590                 if ((u_long)sp & 1) {
1591                         bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
1592                         sum += bytes.s;
1593                 } else
1594                         sum += *sp++;
1595                 len -= 2;
1596         }
1597         if (len)
1598                 sum += ntohs(*(u_char *)sp << 8);
1599 nodata:
1600         while (sum > 0xffff)
1601                 sum = (sum & 0xffff) + (sum >> 16);
1602         sum2 = (u_short)(~sum & 0xffff);
1603 }
1604 #  endif /*  defined(BSD) || defined(sun) */
1605 # endif /* SOLARIS */
1606 #else /* KERNEL */
1607         for (; slen > 1; slen -= 2)
1608                 sum += *sp++;
1609         if (slen)
1610                 sum += ntohs(*(u_char *)sp << 8);
1611         while (sum > 0xffff)
1612                 sum = (sum & 0xffff) + (sum >> 16);
1613         sum2 = (u_short)(~sum & 0xffff);
1614 #endif /* KERNEL */
1615         tcp->th_sum = ts;
1616         return sum2;
1617 }
1618
1619
1620 #if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) )
1621 /*
1622  * Copyright (c) 1982, 1986, 1988, 1991, 1993
1623  *      The Regents of the University of California.  All rights reserved.
1624  *
1625  * Redistribution and use in source and binary forms, with or without
1626  * modification, are permitted provided that the following conditions
1627  * are met:
1628  * 1. Redistributions of source code must retain the above copyright
1629  *    notice, this list of conditions and the following disclaimer.
1630  * 2. Redistributions in binary form must reproduce the above copyright
1631  *    notice, this list of conditions and the following disclaimer in the
1632  *    documentation and/or other materials provided with the distribution.
1633  * 4. Neither the name of the University nor the names of its contributors
1634  *    may be used to endorse or promote products derived from this software
1635  *    without specific prior written permission.
1636  *
1637  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1638  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1639  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1640  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1641  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1642  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1643  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1644  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1645  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1646  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1647  * SUCH DAMAGE.
1648  *
1649  *      @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
1650  * $Id: fil.c,v 2.35.2.82 2004/06/20 10:27:47 darrenr Exp $
1651  */
1652 /*
1653  * Copy data from an mbuf chain starting "off" bytes from the beginning,
1654  * continuing for "len" bytes, into the indicated buffer.
1655  */
1656 void
1657 m_copydata(m, off, len, cp)
1658         register mb_t *m;
1659         register int off;
1660         register int len;
1661         caddr_t cp;
1662 {
1663         register unsigned count;
1664
1665         if (off < 0 || len < 0)
1666                 panic("m_copydata");
1667         while (off > 0) {
1668                 if (m == 0)
1669                         panic("m_copydata");
1670                 if (off < m->m_len)
1671                         break;
1672                 off -= m->m_len;
1673                 m = m->m_next;
1674         }
1675         while (len > 0) {
1676                 if (m == 0)
1677                         panic("m_copydata");
1678                 count = MIN(m->m_len - off, len);
1679                 bcopy(mtod(m, caddr_t) + off, cp, count);
1680                 len -= count;
1681                 cp += count;
1682                 off = 0;
1683                 m = m->m_next;
1684         }
1685 }
1686
1687
1688 # ifndef linux
1689 /*
1690  * Copy data from a buffer back into the indicated mbuf chain,
1691  * starting "off" bytes from the beginning, extending the mbuf
1692  * chain if necessary.
1693  */
1694 void
1695 m_copyback(m0, off, len, cp)
1696         struct  mbuf *m0;
1697         register int off;
1698         register int len;
1699         caddr_t cp;
1700 {
1701         register int mlen;
1702         register struct mbuf *m = m0, *n;
1703         int totlen = 0;
1704
1705         if (m0 == 0)
1706                 return;
1707         while (off > (mlen = m->m_len)) {
1708                 off -= mlen;
1709                 totlen += mlen;
1710                 if (m->m_next == 0) {
1711                         n = m_getclr(M_DONTWAIT, m->m_type);
1712                         if (n == 0)
1713                                 goto out;
1714                         n->m_len = min(MLEN, len + off);
1715                         m->m_next = n;
1716                 }
1717                 m = m->m_next;
1718         }
1719         while (len > 0) {
1720                 mlen = min (m->m_len - off, len);
1721                 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
1722                 cp += mlen;
1723                 len -= mlen;
1724                 mlen += off;
1725                 off = 0;
1726                 totlen += mlen;
1727                 if (len == 0)
1728                         break;
1729                 if (m->m_next == 0) {
1730                         n = m_get(M_DONTWAIT, m->m_type);
1731                         if (n == 0)
1732                                 break;
1733                         n->m_len = min(MLEN, len);
1734                         m->m_next = n;
1735                 }
1736                 m = m->m_next;
1737         }
1738 out:
1739 #if 0
1740         if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
1741                 m->m_pkthdr.len = totlen;
1742 #endif
1743         return;
1744 }
1745 # endif /* linux */
1746 #endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */
1747
1748
1749 frgroup_t *fr_findgroup(num, flags, which, set, fgpp)
1750 u_32_t num, flags;
1751 minor_t which;
1752 int set;
1753 frgroup_t ***fgpp;
1754 {
1755         frgroup_t *fg, **fgp;
1756
1757         if (which == IPL_LOGAUTH)
1758                 fgp = &ipfgroups[2][set];
1759         else if (flags & FR_ACCOUNT)
1760                 fgp = &ipfgroups[1][set];
1761         else if (flags & (FR_OUTQUE|FR_INQUE))
1762                 fgp = &ipfgroups[0][set];
1763         else
1764                 return NULL;
1765
1766         while ((fg = *fgp))
1767                 if (fg->fg_num == num)
1768                         break;
1769                 else
1770                         fgp = &fg->fg_next;
1771         if (fgpp)
1772                 *fgpp = fgp;
1773         return fg;
1774 }
1775
1776
1777 frgroup_t *fr_addgroup(num, fp, which, set)
1778 u_32_t num;
1779 frentry_t *fp;
1780 minor_t which;
1781 int set;
1782 {
1783         frgroup_t *fg, **fgp;
1784
1785         if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp)))
1786                 return fg;
1787
1788         KMALLOC(fg, frgroup_t *);
1789         if (fg) {
1790                 fg->fg_num = num;
1791                 fg->fg_next = *fgp;
1792                 fg->fg_head = fp;
1793                 fg->fg_start = &fp->fr_grp;
1794                 *fgp = fg;
1795         }
1796         return fg;
1797 }
1798
1799
1800 void fr_delgroup(num, flags, which, set)
1801 u_32_t num, flags;
1802 minor_t which;
1803 int set;
1804 {
1805         frgroup_t *fg, **fgp;
1806  
1807         if (!(fg = fr_findgroup(num, flags, which, set, &fgp)))
1808                 return;
1809  
1810         *fgp = fg->fg_next;
1811         KFREE(fg);
1812 }
1813
1814
1815
1816 /*
1817  * recursively flush rules from the list, descending groups as they are
1818  * encountered.  if a rule is the head of a group and it has lost all its
1819  * group members, then also delete the group reference.
1820  */
1821 static int frflushlist(set, unit, nfreedp, listp)
1822 int set;
1823 minor_t unit;
1824 int *nfreedp;
1825 frentry_t **listp;
1826 {
1827         register int freed = 0, i;
1828         register frentry_t *fp;
1829
1830         while ((fp = *listp)) {
1831                 *listp = fp->fr_next;
1832                 if (fp->fr_grp) {
1833                         i = frflushlist(set, unit, nfreedp, &fp->fr_grp);
1834                         MUTEX_ENTER(&ipf_rw);
1835                         fp->fr_ref -= i;
1836                         MUTEX_EXIT(&ipf_rw);
1837                 }
1838
1839                 ATOMIC_DEC32(fp->fr_ref);
1840                 if (fp->fr_grhead) {
1841                         fr_delgroup(fp->fr_grhead, fp->fr_flags, 
1842                                     unit, set);
1843                         fp->fr_grhead = 0;
1844                 }
1845                 if (fp->fr_ref == 0) {
1846                         KFREE(fp);
1847                         freed++;
1848                 } else
1849                         fp->fr_next = NULL;
1850         }
1851         *nfreedp += freed;
1852         return freed;
1853 }
1854
1855
1856 int frflush(unit, proto, flags)
1857 minor_t unit;
1858 int proto, flags;
1859 {
1860         int flushed = 0, set;
1861
1862         if (unit != IPL_LOGIPF)
1863                 return 0;
1864         WRITE_ENTER(&ipf_mutex);
1865         bzero((char *)frcache, sizeof(frcache[0]) * 2);
1866
1867         set = fr_active;
1868         if (flags & FR_INACTIVE)
1869                 set = 1 - set;
1870
1871         if (flags & FR_OUTQUE) {
1872 #ifdef  USE_INET6
1873                 if (proto == 0 || proto == 6) {
1874                         (void) frflushlist(set, unit,
1875                                            &flushed, &ipfilter6[1][set]);
1876                         (void) frflushlist(set, unit,
1877                                            &flushed, &ipacct6[1][set]);
1878                 }
1879 #endif
1880                 if (proto == 0 || proto == 4) {
1881                         (void) frflushlist(set, unit,
1882                                            &flushed, &ipfilter[1][set]);
1883                         (void) frflushlist(set, unit,
1884                                            &flushed, &ipacct[1][set]);
1885                 }
1886         }
1887         if (flags & FR_INQUE) {
1888 #ifdef  USE_INET6
1889                 if (proto == 0 || proto == 6) {
1890                         (void) frflushlist(set, unit,
1891                                             &flushed, &ipfilter6[0][set]);
1892                         (void) frflushlist(set, unit,
1893                                            &flushed, &ipacct6[0][set]);
1894                 }
1895 #endif
1896                 if (proto == 0 || proto == 4) {
1897                         (void) frflushlist(set, unit,
1898                                            &flushed, &ipfilter[0][set]);
1899                         (void) frflushlist(set, unit,
1900                                            &flushed, &ipacct[0][set]);
1901                 }
1902         }
1903         RWLOCK_EXIT(&ipf_mutex);
1904         return flushed;
1905 }
1906
1907
1908 char *memstr(src, dst, slen, dlen)
1909 char *src, *dst;
1910 int slen, dlen;
1911 {
1912         char *s = NULL;
1913
1914         while (dlen >= slen) {
1915                 if (bcmp(src, dst, slen) == 0) {
1916                         s = dst;
1917                         break;
1918                 }
1919                 dst++;
1920                 dlen--;
1921         }
1922         return s;
1923 }
1924
1925
1926 void fixskip(listp, rp, addremove)
1927 frentry_t **listp, *rp;
1928 int addremove;
1929 {
1930         frentry_t *fp;
1931         int rules = 0, rn = 0;
1932
1933         for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++)
1934                 ;
1935
1936         if (!fp)
1937                 return;
1938
1939         for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
1940                 if (fp->fr_skip && (rn + fp->fr_skip >= rules))
1941                         fp->fr_skip += addremove;
1942 }
1943
1944
1945 #ifdef  _KERNEL
1946 /*
1947  * count consecutive 1's in bit mask.  If the mask generated by counting
1948  * consecutive 1's is different to that passed, return -1, else return #
1949  * of bits.
1950  */
1951 int     countbits(ip)
1952 u_32_t  ip;
1953 {
1954         u_32_t  ipn;
1955         int     cnt = 0, i, j;
1956
1957         ip = ipn = ntohl(ip);
1958         for (i = 32; i; i--, ipn *= 2)
1959                 if (ipn & 0x80000000)
1960                         cnt++;
1961                 else
1962                         break;
1963         ipn = 0;
1964         for (i = 32, j = cnt; i; i--, j--) {
1965                 ipn *= 2;
1966                 if (j > 0)
1967                         ipn++;
1968         }
1969         if (ipn == ip)
1970                 return cnt;
1971         return -1;
1972 }
1973
1974
1975 /*
1976  * return the first IP Address associated with an interface
1977  */
1978 int fr_ifpaddr(v, ifptr, inp)
1979 int v;
1980 void *ifptr;
1981 struct in_addr *inp;
1982 {
1983 # ifdef USE_INET6
1984         struct in6_addr *inp6 = NULL;
1985 # endif
1986 # if SOLARIS
1987         ill_t *ill = ifptr;
1988 # else
1989         struct ifnet *ifp = ifptr;
1990 # endif
1991         struct in_addr in;
1992
1993 # if SOLARIS
1994 #  ifdef        USE_INET6
1995         if (v == 6) {
1996                 struct in6_addr in6;
1997
1998                 /*
1999                  * First is always link local.
2000                  */
2001                 if (ill->ill_ipif->ipif_next)
2002                         in6 = ill->ill_ipif->ipif_next->ipif_v6lcl_addr;
2003                 else
2004                         bzero((char *)&in6, sizeof(in6));
2005                 bcopy((char *)&in6, (char *)inp, sizeof(in6));
2006         } else
2007 #  endif
2008         {
2009                 in.s_addr = ill->ill_ipif->ipif_local_addr;
2010                 *inp = in;
2011         }
2012 # else /* SOLARIS */
2013 #  if linux
2014         ;
2015 #  else /* linux */
2016         struct sockaddr_in *sin;
2017         struct ifaddr *ifa;
2018
2019 #   if  (__FreeBSD_version >= 300000)
2020         ifa = TAILQ_FIRST(&ifp->if_addrhead);
2021 #   else
2022 #    if defined(__NetBSD__) || defined(__OpenBSD__)
2023         ifa = ifp->if_addrlist.tqh_first;
2024 #    else
2025 #     if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
2026         ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa;
2027 #     else
2028         ifa = ifp->if_addrlist;
2029 #     endif
2030 #    endif /* __NetBSD__ || __OpenBSD__ */
2031 #   endif /* __FreeBSD_version >= 300000 */
2032 #   if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK))
2033         sin = (struct sockaddr_in *)&ifa->ifa_addr;
2034 #   else
2035         sin = (struct sockaddr_in *)ifa->ifa_addr;
2036         while (sin && ifa) {
2037                 if ((v == 4) && (sin->sin_family == AF_INET))
2038                         break;
2039 #    ifdef USE_INET6
2040                 if ((v == 6) && (sin->sin_family == AF_INET6)) {
2041                         inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr;
2042                         if (!IN6_IS_ADDR_LINKLOCAL(inp6) &&
2043                             !IN6_IS_ADDR_LOOPBACK(inp6))
2044                                 break;
2045                 }
2046 #    endif
2047 #    if (__FreeBSD_version >= 300000)
2048                 ifa = TAILQ_NEXT(ifa, ifa_link);
2049 #    else
2050 #     if defined(__NetBSD__) || defined(__OpenBSD__)
2051                 ifa = ifa->ifa_list.tqe_next;
2052 #     else
2053                 ifa = ifa->ifa_next;
2054 #     endif
2055 #    endif /* __FreeBSD_version >= 300000 */
2056                 if (ifa)
2057                         sin = (struct sockaddr_in *)ifa->ifa_addr;
2058         }
2059         if (ifa == NULL)
2060                 sin = NULL;
2061         if (sin == NULL)
2062                 return -1;
2063 #   endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */
2064 #    ifdef      USE_INET6
2065         if (v == 6)
2066                 bcopy((char *)inp6, (char *)inp, sizeof(*inp6));
2067         else
2068 #    endif
2069         {
2070                 in = sin->sin_addr;
2071                 *inp = in;
2072         }
2073 #  endif /* linux */
2074 # endif /* SOLARIS */
2075         return 0;
2076 }
2077
2078
2079 static void frsynclist(fr)
2080 register frentry_t *fr;
2081 {
2082         frdest_t *fdp;
2083         int i;
2084
2085         for (; fr; fr = fr->fr_next) {
2086                 for (i = 0; i < 4; i++) {
2087                         if ((fr->fr_ifnames[i][1] == '\0') &&
2088                             ((fr->fr_ifnames[i][0] == '-') ||
2089                              (fr->fr_ifnames[i][0] == '*'))) {
2090                                 fr->fr_ifas[i] = NULL;
2091                         } else if (*fr->fr_ifnames[i]) {
2092                                 fr->fr_ifas[i] = GETUNIT(fr->fr_ifnames[i],
2093                                                          fr->fr_v);
2094                                 if (!fr->fr_ifas[i])
2095                                         fr->fr_ifas[i] = (void *)-1;
2096                         }
2097                 }
2098
2099                 fdp = &fr->fr_dif;
2100                 fr->fr_flags &= ~FR_DUP;
2101                 if (*fdp->fd_ifname) {
2102                         fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fr->fr_v);
2103                         if (!fdp->fd_ifp)
2104                                 fdp->fd_ifp = (struct ifnet *)-1;
2105                         else
2106                                 fr->fr_flags |= FR_DUP;
2107                 }
2108
2109                 fdp = &fr->fr_tif;
2110                 if (*fdp->fd_ifname) {
2111                         fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fr->fr_v);
2112                         if (!fdp->fd_ifp)
2113                                 fdp->fd_ifp = (struct ifnet *)-1;
2114                 }
2115
2116                 if (fr->fr_grp)
2117                         frsynclist(fr->fr_grp);
2118         }
2119 }
2120
2121
2122 void frsync()
2123 {
2124         ip_natsync(NULL);
2125         ip_statesync(NULL);
2126
2127         WRITE_ENTER(&ipf_mutex);
2128         frsynclist(ipacct[0][fr_active]);
2129         frsynclist(ipacct[1][fr_active]);
2130         frsynclist(ipfilter[0][fr_active]);
2131         frsynclist(ipfilter[1][fr_active]);
2132 #ifdef  USE_INET6
2133         frsynclist(ipacct6[0][fr_active]);
2134         frsynclist(ipacct6[1][fr_active]);
2135         frsynclist(ipfilter6[0][fr_active]);
2136         frsynclist(ipfilter6[1][fr_active]);
2137 #endif
2138         RWLOCK_EXIT(&ipf_mutex);
2139 }
2140
2141
2142 /*
2143  * In the functions below, bcopy() is called because the pointer being
2144  * copied _from_ in this instance is a pointer to a char buf (which could
2145  * end up being unaligned) and on the kernel's local stack.
2146  */
2147 int ircopyptr(a, b, c)
2148 void *a, *b;
2149 size_t c;
2150 {
2151         caddr_t ca;
2152         int err;
2153
2154 #if SOLARIS
2155         if (copyin(a, (char *)&ca, sizeof(ca)))
2156                 return EFAULT;
2157 #else
2158         bcopy(a, &ca, sizeof(ca));
2159 #endif
2160         err = copyin(ca, b, c);
2161         if (err)
2162                 err = EFAULT;
2163         return err;
2164 }
2165
2166
2167 int iwcopyptr(a, b, c)
2168 void *a, *b;
2169 size_t c;
2170 {
2171         caddr_t ca;
2172         int err;
2173
2174 #if SOLARIS
2175         if (copyin(b, (char *)&ca, sizeof(ca)))
2176                 return EFAULT;
2177 #else
2178         bcopy(b, &ca, sizeof(ca));
2179 #endif
2180         err = copyout(a, ca, c);
2181         if (err)
2182                 err = EFAULT;
2183         return err;
2184 }
2185
2186 #else /* _KERNEL */
2187
2188
2189 /*
2190  * return the first IP Address associated with an interface
2191  */
2192 int fr_ifpaddr(v, ifptr, inp)
2193 int v;
2194 void *ifptr;
2195 struct in_addr *inp;
2196 {
2197         return 0;
2198 }
2199
2200
2201 int ircopyptr(a, b, c)
2202 void *a, *b;
2203 size_t c;
2204 {
2205         caddr_t ca;
2206
2207         bcopy(a, &ca, sizeof(ca));
2208         bcopy(ca, b, c);
2209         return 0;
2210 }
2211
2212
2213 int iwcopyptr(a, b, c)
2214 void *a, *b;
2215 size_t c;
2216 {
2217         caddr_t ca;
2218
2219         bcopy(b, &ca, sizeof(ca));
2220         bcopy(a, ca, c);
2221         return 0;
2222 }
2223
2224
2225 #endif
2226
2227
2228 int fr_lock(data, lockp)
2229 caddr_t data;
2230 int *lockp;
2231 {
2232         int arg, error;
2233
2234         error = IRCOPY(data, (caddr_t)&arg, sizeof(arg));
2235         if (!error) {
2236                 error = IWCOPY((caddr_t)lockp, data, sizeof(*lockp));
2237                 if (!error)
2238                         *lockp = arg;
2239         }
2240         return error;
2241 }
2242
2243
2244 void fr_getstat(fiop)
2245 friostat_t *fiop;
2246 {
2247         bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2);
2248         fiop->f_locks[0] = fr_state_lock;
2249         fiop->f_locks[1] = fr_nat_lock;
2250         fiop->f_locks[2] = fr_frag_lock;
2251         fiop->f_locks[3] = fr_auth_lock;
2252         fiop->f_fin[0] = ipfilter[0][0];
2253         fiop->f_fin[1] = ipfilter[0][1];
2254         fiop->f_fout[0] = ipfilter[1][0];
2255         fiop->f_fout[1] = ipfilter[1][1];
2256         fiop->f_acctin[0] = ipacct[0][0];
2257         fiop->f_acctin[1] = ipacct[0][1];
2258         fiop->f_acctout[0] = ipacct[1][0];
2259         fiop->f_acctout[1] = ipacct[1][1];
2260 #ifdef  USE_INET6
2261         fiop->f_fin6[0] = ipfilter6[0][0];
2262         fiop->f_fin6[1] = ipfilter6[0][1];
2263         fiop->f_fout6[0] = ipfilter6[1][0];
2264         fiop->f_fout6[1] = ipfilter6[1][1];
2265         fiop->f_acctin6[0] = ipacct6[0][0];
2266         fiop->f_acctin6[1] = ipacct6[0][1];
2267         fiop->f_acctout6[0] = ipacct6[1][0];
2268         fiop->f_acctout6[1] = ipacct6[1][1];
2269 #else
2270         fiop->f_fin6[0] = NULL;
2271         fiop->f_fin6[1] = NULL;
2272         fiop->f_fout6[0] = NULL;
2273         fiop->f_fout6[1] = NULL;
2274         fiop->f_acctin6[0] = NULL;
2275         fiop->f_acctin6[1] = NULL;
2276         fiop->f_acctout6[0] = NULL;
2277         fiop->f_acctout6[1] = NULL;
2278 #endif
2279         fiop->f_active = fr_active;
2280         fiop->f_froute[0] = ipl_frouteok[0];
2281         fiop->f_froute[1] = ipl_frouteok[1];
2282
2283         fiop->f_running = fr_running;
2284         fiop->f_groups[0][0] = ipfgroups[0][0];
2285         fiop->f_groups[0][1] = ipfgroups[0][1];
2286         fiop->f_groups[1][0] = ipfgroups[1][0];
2287         fiop->f_groups[1][1] = ipfgroups[1][1];
2288         fiop->f_groups[2][0] = ipfgroups[2][0];
2289         fiop->f_groups[2][1] = ipfgroups[2][1];
2290 #ifdef  IPFILTER_LOG
2291         fiop->f_logging = 1;
2292 #else
2293         fiop->f_logging = 0;
2294 #endif
2295         fiop->f_defpass = fr_pass;
2296         strncpy(fiop->f_version, ipfilter_version, sizeof(fiop->f_version));
2297 }
2298
2299
2300 #ifdef  USE_INET6
2301 int icmptoicmp6types[ICMP_MAXTYPE+1] = {
2302         ICMP6_ECHO_REPLY,       /* 0: ICMP_ECHOREPLY */
2303         -1,                     /* 1: UNUSED */
2304         -1,                     /* 2: UNUSED */
2305         ICMP6_DST_UNREACH,      /* 3: ICMP_UNREACH */
2306         -1,                     /* 4: ICMP_SOURCEQUENCH */
2307         ND_REDIRECT,            /* 5: ICMP_REDIRECT */
2308         -1,                     /* 6: UNUSED */
2309         -1,                     /* 7: UNUSED */
2310         ICMP6_ECHO_REQUEST,     /* 8: ICMP_ECHO */
2311         -1,                     /* 9: UNUSED */
2312         -1,                     /* 10: UNUSED */
2313         ICMP6_TIME_EXCEEDED,    /* 11: ICMP_TIMXCEED */
2314         ICMP6_PARAM_PROB,       /* 12: ICMP_PARAMPROB */
2315         -1,                     /* 13: ICMP_TSTAMP */
2316         -1,                     /* 14: ICMP_TSTAMPREPLY */
2317         -1,                     /* 15: ICMP_IREQ */
2318         -1,                     /* 16: ICMP_IREQREPLY */
2319         -1,                     /* 17: ICMP_MASKREQ */
2320         -1,                     /* 18: ICMP_MASKREPLY */
2321 };
2322
2323
2324 int     icmptoicmp6unreach[ICMP_MAX_UNREACH] = {
2325         ICMP6_DST_UNREACH_ADDR,         /* 0: ICMP_UNREACH_NET */
2326         ICMP6_DST_UNREACH_ADDR,         /* 1: ICMP_UNREACH_HOST */
2327         -1,                             /* 2: ICMP_UNREACH_PROTOCOL */
2328         ICMP6_DST_UNREACH_NOPORT,       /* 3: ICMP_UNREACH_PORT */
2329         -1,                             /* 4: ICMP_UNREACH_NEEDFRAG */
2330         ICMP6_DST_UNREACH_NOTNEIGHBOR,  /* 5: ICMP_UNREACH_SRCFAIL */
2331         ICMP6_DST_UNREACH_ADDR,         /* 6: ICMP_UNREACH_NET_UNKNOWN */
2332         ICMP6_DST_UNREACH_ADDR,         /* 7: ICMP_UNREACH_HOST_UNKNOWN */
2333         -1,                             /* 8: ICMP_UNREACH_ISOLATED */
2334         ICMP6_DST_UNREACH_ADMIN,        /* 9: ICMP_UNREACH_NET_PROHIB */
2335         ICMP6_DST_UNREACH_ADMIN,        /* 10: ICMP_UNREACH_HOST_PROHIB */
2336         -1,                             /* 11: ICMP_UNREACH_TOSNET */
2337         -1,                             /* 12: ICMP_UNREACH_TOSHOST */
2338         ICMP6_DST_UNREACH_ADMIN,        /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */
2339 };
2340 #endif
2341
2342
2343 #ifndef _KERNEL
2344 int mbuflen(buf)
2345 mb_t *buf;
2346 {
2347         ip_t *ip;
2348
2349         ip = (ip_t *)buf;
2350         return ip->ip_len;
2351 }
2352 #endif
2353
2354
2355 #if defined(_KERNEL) && !defined(__sgi)
2356 void *ipf_pullup(m, fin, len, ipin)
2357 mb_t *m;
2358 fr_info_t *fin;
2359 int len;
2360 void *ipin;
2361 {
2362 # if SOLARIS
2363         qif_t *qf = fin->fin_qif;
2364 # endif
2365         int out = fin->fin_out, dpoff, ipoff;
2366         char *ip;
2367
2368         if (m == NULL)
2369                 return NULL;
2370
2371         ipoff = (char *)ipin - MTOD(m, char *);
2372         if (fin->fin_dp != NULL)
2373                 dpoff = (char *)fin->fin_dp - (char *)ipin;
2374         else
2375                 dpoff = 0;
2376
2377         if (M_BLEN(m) < len) {
2378 # if SOLARIS
2379                 qif_t *qf = fin->fin_qif;
2380                 int inc = 0;
2381
2382                 if (ipoff > 0) {
2383                         if ((ipoff & 3) != 0) {
2384                                 inc = 4 - (ipoff & 3);
2385                                 if (m->b_rptr - inc >= m->b_datap->db_base)
2386                                         m->b_rptr -= inc;
2387                                 else
2388                                         inc = 0;
2389                         }
2390                 }
2391                 if (!pullupmsg(m, len + ipoff + inc)) {
2392                         ATOMIC_INCL(frstats[out].fr_pull[1]);
2393                         return NULL;
2394                 }
2395                 m->b_rptr += inc;
2396                 ATOMIC_INCL(frstats[out].fr_pull[0]);
2397                 qf->qf_data = MTOD(m, char *) + ipoff;
2398 # else
2399 #  if (__FreeBSD_version >= 490000)
2400                 if ((len > MHLEN) && ((m->m_flags & M_PKTHDR) != 0))
2401                         m = m_defrag(m, M_DONTWAIT);
2402                 else
2403 #  endif
2404                         m = m_pullup(m, len);
2405                 *fin->fin_mp = m;
2406                 if (m == NULL) {
2407                         ATOMIC_INCL(frstats[out].fr_pull[1]);
2408                         return NULL;
2409                 }
2410                 ATOMIC_INCL(frstats[out].fr_pull[0]);
2411 # endif /* SOLARIS */
2412         }
2413         ip = MTOD(m, char *) + ipoff;
2414         if (fin->fin_dp != NULL)
2415                 fin->fin_dp = (char *)ip + dpoff;
2416         return ip;
2417 }
2418 #endif /* _KERNEL */