]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/fil.c
Import IP Filter version 3.2alpha4 to bring in working LKM for 2.2
[FreeBSD/FreeBSD.git] / contrib / ipfilter / fil.c
1 /*
2  * (C)opyright 1993-1996 by Darren Reed.
3  *
4  * Redistribution and use in source and binary forms are permitted
5  * provided that this notice is preserved and due credit is given
6  * to the original author and the contributors.
7  */
8 #if !defined(lint) && defined(LIBC_SCCS)
9 static  char    sccsid[] = "@(#)fil.c   1.36 6/5/96 (C) 1993-1996 Darren Reed";
10 static  char    rcsid[] = "$Id: fil.c,v 2.0.2.7 1997/04/02 12:23:15 darrenr Exp $";
11 #endif
12
13 #include <sys/errno.h>
14 #include <sys/types.h>
15 #include <sys/param.h>
16 #include <sys/time.h>
17 #include <sys/file.h>
18 #include <sys/ioctl.h>
19 #if defined(_KERNEL) || defined(KERNEL)
20 # include <sys/systm.h>
21 #else
22 # include <stdio.h>
23 # include <string.h>
24 #endif
25 #include <sys/uio.h>
26 #if !defined(__SVR4) && !defined(__svr4__)
27 # include <sys/mbuf.h>
28 #else
29 # include <sys/byteorder.h>
30 # include <sys/dditypes.h>
31 # include <sys/stream.h>
32 #endif
33 #include <sys/protosw.h>
34 #include <sys/socket.h>
35 #include <net/if.h>
36 #ifdef sun
37 # include <net/af.h>
38 #endif
39 #include <net/route.h>
40 #include <netinet/in.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/ip.h>
43 #include <netinet/ip_var.h>
44 #include <netinet/tcp.h>
45 #include <netinet/udp.h>
46 #include <netinet/tcpip.h>
47 #include <netinet/ip_icmp.h>
48 #include "ip_compat.h"
49 #include "ip_fil.h"
50 #include "ip_nat.h"
51 #include "ip_frag.h"
52 #include "ip_state.h"
53 #ifndef MIN
54 #define MIN(a,b)        (((a)<(b))?(a):(b))
55 #endif
56
57 #ifndef _KERNEL
58 # include "ipf.h"
59 # include "ipt.h"
60 extern  int     opts;
61
62 # define        FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; \
63                                                           second; }
64 # define        FR_IFDEBUG(ex,second,verb_pr)   if (ex) { debug verb_pr; \
65                                                           second; }
66 # define        FR_VERBOSE(verb_pr)                     verbose verb_pr
67 # define        FR_DEBUG(verb_pr)                       debug verb_pr
68 # define        FR_SCANLIST(p, ip, fi, m)       fr_scanlist(p, ip, fi, m)
69 # define        SEND_RESET(ip, qif, q, if)              send_reset(ip, if)
70 # define        IPLLOG(a, c, d, e)              ipllog()
71 # if SOLARIS
72 #  define       ICMP_ERROR(b, ip, t, c, if, src)        icmp_error(ip)
73 #  define       bcmp    memcmp
74 # else
75 #  define       ICMP_ERROR(b, ip, t, c, if, src)        icmp_error(b, ip, if)
76 # endif
77
78 #else /* #ifndef _KERNEL */
79 # define        FR_IFVERBOSE(ex,second,verb_pr) ;
80 # define        FR_IFDEBUG(ex,second,verb_pr)   ;
81 # define        FR_VERBOSE(verb_pr)
82 # define        FR_DEBUG(verb_pr)
83 # define        FR_SCANLIST(p, ip, fi, m)       fr_scanlist(p, ip, fi, m)
84 # define        IPLLOG(a, c, d, e)              ipllog(a, IPL_LOGIPF, c, d, e)
85 # if SOLARIS
86 extern  kmutex_t        ipf_mutex;
87 #  define       SEND_RESET(ip, qif, q, if)      send_reset(ip, qif, q)
88 #  define       ICMP_ERROR(b, ip, t, c, if, src) \
89                         icmp_error(b, ip, t, c, if, src)
90 # else
91 #  define       FR_SCANLIST(p, ip, fi, m)       fr_scanlist(p, ip, fi, m)
92 #  define       SEND_RESET(ip, qif, q, if)      send_reset((struct tcpiphdr *)ip)
93 #  if BSD < 199103
94 #   define      ICMP_ERROR(b, ip, t, c, if, src) \
95                         icmp_error(mtod(b, ip_t *), t, c, if, src)
96 #  else
97 #   define      ICMP_ERROR(b, ip, t, c, if, src) \
98                         icmp_error(b, t, c, (src).s_addr, if)
99 #  endif
100 # endif
101 #endif
102
103 #ifndef IPF_LOGGING
104 #define IPF_LOGGING     0
105 #endif
106 #ifdef  IPF_DEFAULT_PASS
107 #define IPF_NOMATCH     (IPF_DEFAULT_PASS|FR_NOMATCH)
108 #else
109 #define IPF_NOMATCH     (FR_PASS|FR_NOMATCH)
110 #endif
111
112 struct  filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
113 struct  frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
114                 *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
115 int     fr_flags = IPF_LOGGING, fr_active = 0;
116
117 fr_info_t       frcache[2];
118
119 static  void    fr_makefrip __P((int, ip_t *, fr_info_t *));
120 static  int     fr_tcpudpchk __P((frentry_t *, fr_info_t *));
121 static  int     fr_scanlist __P((int, ip_t *, fr_info_t *, void *));
122
123
124 /*
125  * bit values for identifying presence of individual IP options
126  */
127 struct  optlist ipopts[20] = {
128         { IPOPT_NOP,    0x000001 },
129         { IPOPT_RR,     0x000002 },
130         { IPOPT_ZSU,    0x000004 },
131         { IPOPT_MTUP,   0x000008 },
132         { IPOPT_MTUR,   0x000010 },
133         { IPOPT_ENCODE, 0x000020 },
134         { IPOPT_TS,     0x000040 },
135         { IPOPT_TR,     0x000080 },
136         { IPOPT_SECURITY, 0x000100 },
137         { IPOPT_LSRR,   0x000200 },
138         { IPOPT_E_SEC,  0x000400 },
139         { IPOPT_CIPSO,  0x000800 },
140         { IPOPT_SATID,  0x001000 },
141         { IPOPT_SSRR,   0x002000 },
142         { IPOPT_ADDEXT, 0x004000 },
143         { IPOPT_VISA,   0x008000 },
144         { IPOPT_IMITD,  0x010000 },
145         { IPOPT_EIP,    0x020000 },
146         { IPOPT_FINN,   0x040000 },
147         { 0,            0x000000 }
148 };
149
150 /*
151  * bit values for identifying presence of individual IP security options
152  */
153 struct  optlist secopt[8] = {
154         { IPSO_CLASS_RES4,      0x01 },
155         { IPSO_CLASS_TOPS,      0x02 },
156         { IPSO_CLASS_SECR,      0x04 },
157         { IPSO_CLASS_RES3,      0x08 },
158         { IPSO_CLASS_CONF,      0x10 },
159         { IPSO_CLASS_UNCL,      0x20 },
160         { IPSO_CLASS_RES2,      0x40 },
161         { IPSO_CLASS_RES1,      0x80 }
162 };
163
164
165 /*
166  * compact the IP header into a structure which contains just the info.
167  * which is useful for comparing IP headers with.
168  */
169 static  void    fr_makefrip(hlen, ip, fin)
170 int hlen;
171 ip_t *ip;
172 fr_info_t *fin;
173 {
174         struct optlist *op;
175         tcphdr_t *tcp;
176         fr_ip_t *fi = &fin->fin_fi;
177         u_short optmsk = 0, secmsk = 0, auth = 0;
178         int i, mv, ol, off;
179         u_char *s, opt;
180
181         fin->fin_fr = NULL;
182         fin->fin_tcpf = 0;
183         fin->fin_data[0] = 0;
184         fin->fin_data[1] = 0;
185         fin->fin_rule = -1;
186 #ifdef  _KERNEL
187         fin->fin_icode = ipl_unreach;
188 #endif
189         fi->fi_v = ip->ip_v;
190         fi->fi_tos = ip->ip_tos;
191         fin->fin_hlen = hlen;
192         fin->fin_dlen = ip->ip_len - hlen;
193         tcp = (tcphdr_t *)((char *)ip + hlen);
194         fin->fin_dp = (void *)tcp;
195         (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
196         (*(((u_long *)fi) + 1)) = (*(((u_long *)ip) + 3));
197         (*(((u_long *)fi) + 2)) = (*(((u_long *)ip) + 4));
198
199         fi->fi_fl = (hlen > sizeof(struct ip)) ? FI_OPTIONS : 0;
200         off = (ip->ip_off & 0x1fff) << 3;
201         if (ip->ip_off & 0x3fff)
202                 fi->fi_fl |= FI_FRAG;
203         switch (ip->ip_p)
204         {
205         case IPPROTO_ICMP :
206                 if ((!IPMINLEN(ip, icmp) && !off) ||
207                     (off && off < sizeof(struct icmp)))
208                         fi->fi_fl |= FI_SHORT;
209                 if (fin->fin_dlen > 1)
210                         fin->fin_data[0] = *(u_short *)tcp;
211                 break;
212         case IPPROTO_TCP :
213                 fi->fi_fl |= FI_TCPUDP;
214                 if ((!IPMINLEN(ip, tcphdr) && !off) ||
215                     (off && off < sizeof(struct tcphdr)))
216                         fi->fi_fl |= FI_SHORT;
217                 if (!(fi->fi_fl & FI_SHORT) && !off)
218                         fin->fin_tcpf = tcp->th_flags;
219                 goto getports;
220         case IPPROTO_UDP :
221                 fi->fi_fl |= FI_TCPUDP;
222                 if ((!IPMINLEN(ip, udphdr) && !off) ||
223                     (off && off < sizeof(struct udphdr)))
224                         fi->fi_fl |= FI_SHORT;
225 getports:
226                 if (!off && (fin->fin_dlen > 3)) {
227                         fin->fin_data[0] = ntohs(tcp->th_sport);
228                         fin->fin_data[1] = ntohs(tcp->th_dport);
229                 }
230                 break;
231         default :
232                 break;
233         }
234
235
236         for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) {
237                 if (!(opt = *s))
238                         break;
239                 ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1);
240                 if (opt > 1 && (ol < 2 || ol > hlen))
241                         break;
242                 for (i = 9, mv = 4; mv >= 0; ) {
243                         op = ipopts + i;
244                         if (opt == (u_char)op->ol_val) {
245                                 optmsk |= op->ol_bit;
246                                 if (opt == IPOPT_SECURITY) {
247                                         struct optlist *sp;
248                                         u_char  sec;
249                                         int j, m;
250
251                                         sec = *(s + 2); /* classification */
252                                         for (j = 3, m = 2; m >= 0; ) {
253                                                 sp = secopt + j;
254                                                 if (sec == sp->ol_val) {
255                                                         secmsk |= sp->ol_bit;
256                                                         auth = *(s + 3);
257                                                         auth *= 256;
258                                                         auth += *(s + 4);
259                                                         break;
260                                                 }
261                                                 if (sec < sp->ol_val)
262                                                         j -= m--;
263                                                 else
264                                                         j += m--;
265                                         }
266                                 }
267                                 break;
268                         }
269                         if (opt < op->ol_val)
270                                 i -= mv--;
271                         else
272                                 i += mv--;
273                 }
274                 hlen -= ol;
275                 s += ol;
276         }
277         if (auth && !(auth & 0x0100))
278                 auth &= 0xff00;
279         fi->fi_optmsk = optmsk;
280         fi->fi_secmsk = secmsk;
281         fi->fi_auth = auth;
282 }
283
284
285 /*
286  * check an IP packet for TCP/UDP characteristics such as ports and flags.
287  */
288 static int fr_tcpudpchk(fr, fin)
289 frentry_t *fr;
290 fr_info_t *fin;
291 {
292         register u_short po, tup;
293         register char i;
294         register int err = 1;
295
296         /*
297          * Both ports should *always* be in the first fragment.
298          * So far, I cannot find any cases where they can not be.
299          *
300          * compare destination ports
301          */
302         if ((i = (int)fr->fr_dcmp)) {
303                 po = fr->fr_dport;
304                 tup = fin->fin_data[1];
305                 /*
306                  * Do opposite test to that required and
307                  * continue if that succeeds.
308                  */
309                 if (!--i && tup != po) /* EQUAL */
310                         err = 0;
311                 else if (!--i && tup == po) /* NOTEQUAL */
312                         err = 0;
313                 else if (!--i && tup >= po) /* LESSTHAN */
314                         err = 0;
315                 else if (!--i && tup <= po) /* GREATERTHAN */
316                         err = 0;
317                 else if (!--i && tup > po) /* LT or EQ */
318                         err = 0;
319                 else if (!--i && tup < po) /* GT or EQ */
320                         err = 0;
321                 else if (!--i &&           /* Out of range */
322                          (tup >= po && tup <= fr->fr_dtop))
323                         err = 0;
324                 else if (!--i &&           /* In range */
325                          (tup <= po || tup >= fr->fr_dtop))
326                         err = 0;
327         }
328         /*
329          * compare source ports
330          */
331         if (err && (i = (int)fr->fr_scmp)) {
332                 po = fr->fr_sport;
333                 tup = fin->fin_data[0];
334                 if (!--i && tup != po)
335                         err = 0;
336                 else if (!--i && tup == po)
337                         err = 0;
338                 else if (!--i && tup >= po)
339                         err = 0;
340                 else if (!--i && tup <= po)
341                         err = 0;
342                 else if (!--i && tup > po)
343                         err = 0;
344                 else if (!--i && tup < po)
345                         err = 0;
346                 else if (!--i &&           /* Out of range */
347                          (tup >= po && tup <= fr->fr_stop))
348                         err = 0;
349                 else if (!--i &&           /* In range */
350                          (tup <= po || tup >= fr->fr_stop))
351                         err = 0;
352         }
353
354         /*
355          * If we don't have all the TCP/UDP header, then how can we
356          * expect to do any sort of match on it ?  If we were looking for
357          * TCP flags, then NO match.  If not, then match (which should
358          * satisfy the "short" class too).
359          */
360         if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) {
361                 if (fin->fin_fi.fi_fl & FI_SHORT)
362                         return !(fr->fr_tcpf | fr->fr_tcpfm);
363                 /*
364                  * Match the flags ?  If not, abort this match.
365                  */
366                 if (fr->fr_tcpf &&
367                     fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) {
368                         FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
369                                  fr->fr_tcpfm, fr->fr_tcpf));
370                         err = 0;
371                 }
372         }
373         return err;
374 }
375
376 /*
377  * Check the input/output list of rules for a match and result.
378  * Could be per interface, but this gets real nasty when you don't have
379  * kernel sauce.
380  */
381 static int fr_scanlist(pass, ip, fin, m)
382 int pass;
383 ip_t *ip;
384 register fr_info_t *fin;
385 void *m;
386 {
387         register struct frentry *fr;
388         register fr_ip_t *fi = &fin->fin_fi;
389         int rulen, portcmp = 0, off;
390
391         fr = fin->fin_fr;
392         fin->fin_fr = NULL;
393         fin->fin_rule = 0;
394         off = ip->ip_off & 0x1fff;
395         pass |= (fi->fi_fl << 20);
396
397         if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
398                 portcmp = 1;
399
400         for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
401                 /*
402                  * In all checks below, a null (zero) value in the
403                  * filter struture is taken to mean a wildcard.
404                  *
405                  * check that we are working for the right interface
406                  */
407 #ifdef  _KERNEL
408                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
409                         continue;
410 #else
411                 if (opts & (OPT_VERBOSE|OPT_DEBUG))
412                         printf("\n");
413                 FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 'b'));
414                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
415                         continue;
416                 FR_VERBOSE((":i"));
417 #endif
418                 {
419                         register u_long *ld, *lm, *lip;
420                         register int i;
421
422                         lip = (u_long *)fi;
423                         lm = (u_long *)&fr->fr_mip;
424                         ld = (u_long *)&fr->fr_ip;
425                         i = ((lip[0] & lm[0]) != ld[0]);
426                         FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n",
427                                    lip[0], lm[0], ld[0]));
428                         i |= ((lip[1] & lm[1]) != ld[1]);
429                         FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
430                                    lip[1], lm[1], ld[1]));
431                         i |= ((lip[2] & lm[2]) != ld[2]);
432                         FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
433                                    lip[2], lm[2], ld[2]));
434                         i |= ((lip[3] & lm[3]) != ld[3]);
435                         FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n",
436                                    lip[3], lm[3], ld[3]));
437                         i |= ((lip[4] & lm[4]) != ld[4]);
438                         FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
439                                    lip[4], lm[4], ld[4]));
440                         if (i)
441                                 continue;
442                 }
443
444                 /*
445                  * If a fragment, then only the first has what we're looking
446                  * for here...
447                  */
448                 if (fi->fi_fl & FI_TCPUDP) {
449                         if (portcmp) {
450                                 if (!fr_tcpudpchk(fr, fin))
451                                         continue;
452                         } else if (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
453                                    fr->fr_tcpfm)
454                                 continue;
455                 } else if (fi->fi_p == IPPROTO_ICMP) {
456                         if (!off && (fin->fin_dlen > 1)) {
457                                 if ((fin->fin_data[0] & fr->fr_icmpm) !=
458                                     fr->fr_icmp) {
459                                         FR_DEBUG(("i. %#x & %#x != %#x\n",
460                                                  fin->fin_data[0],
461                                                  fr->fr_icmpm, fr->fr_icmp));
462                                         continue;
463                                 }
464                         } else if (fr->fr_icmpm || fr->fr_icmp)
465                                 continue;
466                 }
467                 FR_VERBOSE(("*"));
468                 /*
469                  * Just log this packet...
470                  */
471                 pass = fr->fr_flags;
472                 if ((pass & FR_CALLNOW) && fr->fr_func)
473                         pass = (*fr->fr_func)(pass, ip, fin);
474 #ifdef  IPFILTER_LOG
475                 if ((pass & FR_LOGMASK) == FR_LOG) {
476                         if (!IPLLOG(fr->fr_flags, ip, fin, m))
477                                 frstats[fin->fin_out].fr_skip++;
478                         frstats[fin->fin_out].fr_pkl++;
479                 }
480 #endif /* IPFILTER_LOG */
481                 FR_DEBUG(("pass %#x\n", pass));
482                 fr->fr_hits++;
483                 if (pass & FR_ACCOUNT)
484                         fr->fr_bytes += (U_QUAD_T)ip->ip_len;
485                 else
486                         fin->fin_icode = fr->fr_icode;
487                 fin->fin_rule = rulen;
488                 fin->fin_fr = fr;
489                 if (pass & FR_QUICK)
490                         break;
491         }
492         return pass;
493 }
494
495
496 /*
497  * frcheck - filter check
498  * check using source and destination addresses/pors in a packet whether
499  * or not to pass it on or not.
500  */
501 int fr_check(ip, hlen, ifp, out
502 #ifdef _KERNEL
503 # if SOLARIS
504 , qif, q, mp)
505 qif_t *qif;
506 queue_t *q;
507 mblk_t **mp;
508 # else
509 , mp)
510 struct mbuf **mp;
511 # endif
512 #else
513 , mp)
514 char *mp;
515 #endif
516 ip_t *ip;
517 int hlen;
518 struct ifnet *ifp;
519 int out;
520 {
521         /*
522          * The above really sucks, but short of writing a diff
523          */
524         fr_info_t frinfo, *fc;
525         register fr_info_t *fin = &frinfo;
526         frentry_t *fr = NULL;
527         int pass, changed;
528 #ifndef _KERNEL
529         char    *mc = mp, *m = mp;
530 #endif
531
532 #ifdef  _KERNEL
533 # if !defined(__SVR4) && !defined(__svr4__)
534         register struct mbuf *m = *mp;
535         struct mbuf *mc = NULL;
536
537         if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
538              ip->ip_p == IPPROTO_ICMP)) {
539                 register int up = MIN(hlen + 8, ip->ip_len);
540
541                 if (up > m->m_len) {
542                         if ((*mp = m_pullup(m, up)) == 0) {
543                                 frstats[out].fr_pull[1]++;
544                                 return -1;
545                         } else {
546                                 frstats[out].fr_pull[0]++;
547                                 m = *mp;
548                                 ip = mtod(m, struct ip *);
549                         }
550                 }
551         }
552 # endif
553 # if SOLARIS
554         mblk_t *mc = NULL, *m = qif->qf_m;
555 # endif
556 #endif
557         fr_makefrip(hlen, ip, fin);
558         fin->fin_ifp = ifp;
559         fin->fin_out = out;
560
561         MUTEX_ENTER(&ipf_mutex);
562         if (!out) {
563                 changed = ip_natin(ip, hlen, fin);
564                 if ((fin->fin_fr = ipacct[0][fr_active]) &&
565                     (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
566                         frstats[0].fr_acct++;
567         }
568
569         if ((pass = ipfr_knownfrag(ip, fin))) {
570                 if ((pass & FR_KEEPSTATE)) {
571                         if (fr_addstate(ip, fin, pass) == -1)
572                                 frstats[out].fr_bads++;
573                         else
574                                 frstats[out].fr_ads++;
575                 }
576         } else if ((pass = fr_checkstate(ip, fin))) {
577                 if ((pass & FR_KEEPFRAG)) {
578                         if (fin->fin_fi.fi_fl & FI_FRAG) {
579                                 if (ipfr_newfrag(ip, fin, pass) == -1)
580                                         frstats[out].fr_bnfr++;
581                                 else
582                                         frstats[out].fr_nfr++;
583                         } else
584                                 frstats[out].fr_cfr++;
585                 }
586         } else {
587                 fc = frcache + out;
588                 if (fc->fin_fr && !bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
589                         /*
590                          * copy cached data so we can unlock the mutex
591                          * earlier.
592                          */
593                         bcopy((char *)fc, (char *)fin, sizeof(*fin));
594                         frstats[out].fr_chit++;
595                         pass = fin->fin_fr->fr_flags;
596                 } else {
597                         pass = IPF_NOMATCH;
598                         if ((fin->fin_fr = ipfilter[out][fr_active]))
599                                 pass = FR_SCANLIST(IPF_NOMATCH, ip, fin, m);
600                         bcopy((char *)fin, (char *)fc, FI_CSIZE);
601                         if (pass & FR_NOMATCH)
602                                 frstats[out].fr_nom++;
603                 }
604                 fr = fin->fin_fr;
605
606                 if ((pass & FR_KEEPFRAG)) {
607                         if (fin->fin_fi.fi_fl & FI_FRAG) {
608                                 if (ipfr_newfrag(ip, fin, pass) == -1)
609                                         frstats[out].fr_bnfr++;
610                                 else
611                                         frstats[out].fr_nfr++;
612                         } else
613                                 frstats[out].fr_cfr++;
614                 }
615                 if (pass & FR_KEEPSTATE) {
616                         if (fr_addstate(ip, fin, pass) == -1)
617                                 frstats[out].fr_bads++;
618                         else
619                                 frstats[out].fr_ads++;
620                 }
621         }
622
623         if (fr && fr->fr_func && !(pass & FR_CALLNOW))
624                 pass = (*fr->fr_func)(pass, ip, fin);
625
626         if (out) {
627                 if ((fin->fin_fr = ipacct[1][fr_active]) &&
628                     (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
629                         frstats[1].fr_acct++;
630                 fin->fin_fr = NULL;
631                 changed = ip_natout(ip, hlen, fin);
632         }
633         fin->fin_fr = fr;
634         MUTEX_EXIT(&ipf_mutex);
635
636 #ifdef  IPFILTER_LOG
637         if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
638                 if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
639                         pass |= FF_LOGNOMATCH;
640                         frstats[out].fr_npkl++;
641                         goto logit;
642                 } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
643                     ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
644                         if ((pass & FR_LOGMASK) != FR_LOGP)
645                                 pass |= FF_LOGPASS;
646                         frstats[out].fr_ppkl++;
647                         goto logit;
648                 } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
649                            ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
650                         if ((pass & FR_LOGMASK) != FR_LOGB)
651                                 pass |= FF_LOGBLOCK;
652                         frstats[out].fr_bpkl++;
653 logit:
654                         if (!IPLLOG(pass, ip, fin, m)) {
655                                 frstats[out].fr_skip++;
656                                 if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
657                                     (FR_PASS|FR_LOGORBLOCK))
658                                         pass ^= FR_PASS|FR_BLOCK;
659                         }
660                 }
661         }
662 #endif /* IPFILTER_LOG */
663
664         if (pass & FR_PASS)
665                 frstats[out].fr_pass++;
666         else if (pass & FR_BLOCK) {
667                 frstats[out].fr_block++;
668                 /*
669                  * Should we return an ICMP packet to indicate error
670                  * status passing through the packet filter ?
671                  * WARNING: ICMP error packets AND TCP RST packets should
672                  * ONLY be sent in repsonse to incoming packets.  Sending them
673                  * in response to outbound packets can result in a panic on
674                  * some operating systems.
675                  */
676                 if (!out) {
677 #ifdef  _KERNEL
678                         if (pass & FR_RETICMP) {
679 # if SOLARIS
680                                 ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode,
681                                            qif, ip->ip_src);
682 # else
683                                 ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode,
684                                            ifp, ip->ip_src);
685                                 m = *mp = NULL; /* freed by icmp_error() */
686 # endif
687
688                                 frstats[0].fr_ret++;
689                         } else if ((pass & FR_RETRST) &&
690                                    !(fin->fin_fi.fi_fl & FI_SHORT)) {
691                                 if (SEND_RESET(ip, qif, q, ifp) == 0)
692                                         frstats[1].fr_ret++;
693                         }
694 #else
695                         if (pass & FR_RETICMP) {
696                                 verbose("- ICMP unreachable sent\n");
697                                 frstats[0].fr_ret++;
698                         } else if ((pass & FR_RETRST) &&
699                                    !(fin->fin_fi.fi_fl & FI_SHORT)) {
700                                 verbose("- TCP RST sent\n");
701                                 frstats[1].fr_ret++;
702                         }
703 #endif
704                 }
705         }
706 #ifdef  _KERNEL
707 # if    !SOLARIS
708         if (pass & FR_DUP)
709                 mc = m_copy(m, 0, M_COPYALL);
710         if (fr) {
711                 frdest_t *fdp = &fr->fr_tif;
712
713                 if ((pass & FR_FASTROUTE) ||
714                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
715                         ipfr_fastroute(m, fin, fdp);
716                         m = *mp = NULL;
717                 }
718                 if (mc)
719                         ipfr_fastroute(mc, fin, &fr->fr_dif);
720         }
721         if (!(pass & FR_PASS) && m)
722                 m_freem(m);
723         return (pass & FR_PASS) ? 0 : -1;
724 # else
725         if (pass & FR_DUP)
726                 mc = dupmsg(m);
727         if (fr) {
728                 frdest_t *fdp = &fr->fr_tif;
729
730                 if ((pass & FR_FASTROUTE) ||
731                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
732                         ipfr_fastroute(qif, ip, m, mp, fin, fdp);
733                         m = *mp = NULL;
734                 }
735                 if (mc)
736                         ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif);
737         }
738         return (pass & FR_PASS) ? changed : -1;
739 # endif
740 #else
741         if (pass & FR_NOMATCH)
742                 return 1;
743         if (pass & FR_PASS)
744                 return 0;
745         return -1;
746 #endif
747 }
748
749
750 #ifdef  IPFILTER_LOG
751 int fr_copytolog(dev, buf, len)
752 int dev;
753 char *buf;
754 int len;
755 {
756         register char   *bufp = iplbuf[dev], *tp = iplt[dev], *hp = iplh[dev];
757         register int    clen, tail;
758
759         tail = (hp >= tp) ? (bufp + IPLLOGSIZE - hp) : (tp - hp);
760         clen = MIN(tail, len);
761         bcopy(buf, hp, clen);
762         len -= clen;
763         tail -= clen;
764         hp += clen;
765         buf += clen;
766         if (hp == bufp + IPLLOGSIZE) {
767                 hp = bufp;
768                 tail = tp - hp;
769         }
770         if (len && tail) {
771                 clen = MIN(tail, len);
772                 bcopy(buf, hp, clen);
773                 len -= clen;
774                 hp += clen;
775         }
776         iplh[dev] = hp;
777         return len;
778 }
779 #endif