]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/fil.c
This commit was generated by cvs2svn to compensate for changes in r57422,
[FreeBSD/FreeBSD.git] / sys / netinet / fil.c
1 /*
2  * Copyright (C) 1993-1998 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)
9 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
10 static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 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 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
19     defined(_KERNEL)
20 # include "opt_ipfilter_log.h"
21 #endif
22 #if defined(_KERNEL) && defined(__FreeBSD_version) && \
23     (__FreeBSD_version >= 220000)
24 # include <sys/filio.h>
25 # include <sys/fcntl.h>
26 #else
27 # include <sys/ioctl.h>
28 #endif
29 #if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
30 # include <sys/systm.h>
31 #else
32 # include <stdio.h>
33 # include <string.h>
34 # include <stdlib.h>
35 #endif
36 #include <sys/uio.h>
37 #if !defined(__SVR4) && !defined(__svr4__)
38 # ifndef linux
39 #  include <sys/mbuf.h>
40 # endif
41 #else
42 # include <sys/byteorder.h>
43 # if SOLARIS2 < 5
44 #  include <sys/dditypes.h>
45 # endif
46 #  include <sys/stream.h>
47 #endif
48 #ifndef linux
49 # include <sys/protosw.h>
50 # include <sys/socket.h>
51 #endif
52 #include <net/if.h>
53 #ifdef sun
54 # include <net/af.h>
55 #endif
56 #include <net/route.h>
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/ip.h>
60 #ifndef linux
61 # include <netinet/ip_var.h>
62 #endif
63 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
64 # include <sys/hashing.h>
65 # include <netinet/in_var.h>
66 #endif
67 #include <netinet/tcp.h>
68 #include <netinet/udp.h>
69 #include <netinet/ip_icmp.h>
70 #include "netinet/ip_compat.h"
71 #include <netinet/tcpip.h>
72 #include "netinet/ip_fil.h"
73 #include "netinet/ip_proxy.h"
74 #include "netinet/ip_nat.h"
75 #include "netinet/ip_frag.h"
76 #include "netinet/ip_state.h"
77 #include "netinet/ip_auth.h"
78 # if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
79 #  include <sys/malloc.h>
80 #  if defined(_KERNEL) && !defined(IPFILTER_LKM)
81 #   include "opt_ipfilter.h"
82 #  endif
83 # endif
84 #ifndef MIN
85 # define        MIN(a,b)        (((a)<(b))?(a):(b))
86 #endif
87 #include "netinet/ipl.h"
88
89 #ifndef _KERNEL
90 # include "ipf.h"
91 # include "ipt.h"
92 extern  int     opts;
93
94 # define        FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; \
95                                                           second; }
96 # define        FR_IFDEBUG(ex,second,verb_pr)   if (ex) { debug verb_pr; \
97                                                           second; }
98 # define        FR_VERBOSE(verb_pr)                     verbose verb_pr
99 # define        FR_DEBUG(verb_pr)                       debug verb_pr
100 # define        SEND_RESET(ip, qif, if, m, fin)         send_reset(ip, if)
101 # define        IPLLOG(a, c, d, e)              ipllog()
102 # define        FR_NEWAUTH(m, fi, ip, qif)      fr_newauth((mb_t *)m, fi, ip)
103 #else /* #ifndef _KERNEL */
104 # define        FR_IFVERBOSE(ex,second,verb_pr) ;
105 # define        FR_IFDEBUG(ex,second,verb_pr)   ;
106 # define        FR_VERBOSE(verb_pr)
107 # define        FR_DEBUG(verb_pr)
108 # define        IPLLOG(a, c, d, e)              ipflog(a, c, d, e)
109 # if SOLARIS || defined(__sgi)
110 extern  KRWLOCK_T       ipf_mutex, ipf_auth, ipf_nat;
111 extern  kmutex_t        ipf_rw;
112 # endif
113 # if SOLARIS
114 #  define       FR_NEWAUTH(m, fi, ip, qif)      fr_newauth((mb_t *)m, fi, \
115                                                            ip, qif)
116 #  define       SEND_RESET(ip, qif, if, fin)    send_reset(fin, ip, qif)
117 #  define       ICMP_ERROR(b, ip, t, c, if, dst) \
118                         icmp_error(ip, t, c, if, dst)
119 # else /* SOLARIS */
120 #  define       FR_NEWAUTH(m, fi, ip, qif)      fr_newauth((mb_t *)m, fi, ip)
121 #  ifdef linux
122 #   define      SEND_RESET(ip, qif, if, fin)    send_reset(ip, ifp)
123 #   define      ICMP_ERROR(b, ip, t, c, if, dst)        icmp_send(b,t,c,0,if)
124 #  else
125 #   define      SEND_RESET(ip, qif, if, fin)    send_reset(fin, ip)
126 #   define      ICMP_ERROR(b, ip, t, c, if, dst) \
127                 send_icmp_err(ip, t, c, if, dst)
128 #  endif /* linux */
129 # endif /* SOLARIS || __sgi */
130 #endif /* _KERNEL */
131
132
133 struct  filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
134 struct  frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
135                 *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
136 struct  frgroup *ipfgroups[3][2];
137 int     fr_flags = IPF_LOGGING, fr_active = 0;
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     fr_tcpudpchk __P((frentry_t *, fr_info_t *));
148 static  int     frflushlist __P((int, minor_t, int *, frentry_t **));
149 #ifdef  _KERNEL
150 static  void    frsynclist __P((frentry_t *));
151 #endif
152
153
154 /*
155  * bit values for identifying presence of individual IP options
156  */
157 struct  optlist ipopts[20] = {
158         { IPOPT_NOP,    0x000001 },
159         { IPOPT_RR,     0x000002 },
160         { IPOPT_ZSU,    0x000004 },
161         { IPOPT_MTUP,   0x000008 },
162         { IPOPT_MTUR,   0x000010 },
163         { IPOPT_ENCODE, 0x000020 },
164         { IPOPT_TS,     0x000040 },
165         { IPOPT_TR,     0x000080 },
166         { IPOPT_SECURITY, 0x000100 },
167         { IPOPT_LSRR,   0x000200 },
168         { IPOPT_E_SEC,  0x000400 },
169         { IPOPT_CIPSO,  0x000800 },
170         { IPOPT_SATID,  0x001000 },
171         { IPOPT_SSRR,   0x002000 },
172         { IPOPT_ADDEXT, 0x004000 },
173         { IPOPT_VISA,   0x008000 },
174         { IPOPT_IMITD,  0x010000 },
175         { IPOPT_EIP,    0x020000 },
176         { IPOPT_FINN,   0x040000 },
177         { 0,            0x000000 }
178 };
179
180 /*
181  * bit values for identifying presence of individual IP security options
182  */
183 struct  optlist secopt[8] = {
184         { IPSO_CLASS_RES4,      0x01 },
185         { IPSO_CLASS_TOPS,      0x02 },
186         { IPSO_CLASS_SECR,      0x04 },
187         { IPSO_CLASS_RES3,      0x08 },
188         { IPSO_CLASS_CONF,      0x10 },
189         { IPSO_CLASS_UNCL,      0x20 },
190         { IPSO_CLASS_RES2,      0x40 },
191         { IPSO_CLASS_RES1,      0x80 }
192 };
193
194
195 /*
196  * compact the IP header into a structure which contains just the info.
197  * which is useful for comparing IP headers with.
198  */
199 void    fr_makefrip(hlen, ip, fin)
200 int hlen;
201 ip_t *ip;
202 fr_info_t *fin;
203 {
204         struct optlist *op;
205         tcphdr_t *tcp;
206         fr_ip_t *fi = &fin->fin_fi;
207         u_short optmsk = 0, secmsk = 0, auth = 0;
208         int i, mv, ol, off;
209         u_char *s, opt;
210
211         fin->fin_rev = 0;
212         fin->fin_fr = NULL;
213         fin->fin_tcpf = 0;
214         fin->fin_data[0] = 0;
215         fin->fin_data[1] = 0;
216         fin->fin_rule = -1;
217         fin->fin_group = -1;
218         fin->fin_id = ip->ip_id;
219 #ifdef  _KERNEL
220         fin->fin_icode = ipl_unreach;
221 #endif
222         fi->fi_v = ip->ip_v;
223         fi->fi_tos = ip->ip_tos;
224         fin->fin_hlen = hlen;
225         fin->fin_dlen = ip->ip_len - hlen;
226         tcp = (tcphdr_t *)((char *)ip + hlen);
227         fin->fin_dp = (void *)tcp;
228         (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
229         fi->fi_src.s_addr = ip->ip_src.s_addr;
230         fi->fi_dst.s_addr = ip->ip_dst.s_addr;
231
232         fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0;
233         off = (ip->ip_off & IP_OFFMASK) << 3;
234         if (ip->ip_off & 0x3fff)
235                 fi->fi_fl |= FI_FRAG;
236         switch (ip->ip_p)
237         {
238         case IPPROTO_ICMP :
239         {
240                 int minicmpsz = sizeof(struct icmp);
241                 icmphdr_t *icmp;
242
243                 icmp = (icmphdr_t *)tcp;
244
245                 if (!off && (icmp->icmp_type == ICMP_ECHOREPLY ||
246                      icmp->icmp_type == ICMP_ECHO))
247                         minicmpsz = ICMP_MINLEN;
248                 if (!off && (icmp->icmp_type == ICMP_TSTAMP ||
249                      icmp->icmp_type == ICMP_TSTAMPREPLY))
250                         minicmpsz = 20; /* type(1) + code(1) + cksum(2) + id(2) + seq(2) + 3*timestamp(3*4) */
251                 if (!off && (icmp->icmp_type == ICMP_MASKREQ ||
252                      icmp->icmp_type == ICMP_MASKREPLY))
253                         minicmpsz = 12; /* type(1) + code(1) + cksum(2) + id(2) + seq(2) + mask(4) */
254                 if ((!(ip->ip_len >= hlen + minicmpsz) && !off) ||
255                     (off && off < sizeof(struct icmp)))
256                         fi->fi_fl |= FI_SHORT;
257                 if (fin->fin_dlen > 1)
258                         fin->fin_data[0] = *(u_short *)tcp;
259                 break;
260         }
261         case IPPROTO_TCP :
262                 fi->fi_fl |= FI_TCPUDP;
263                 if ((!IPMINLEN(ip, tcphdr) && !off) ||
264                     (off && off < sizeof(struct tcphdr)))
265                         fi->fi_fl |= FI_SHORT;
266                 if (!(fi->fi_fl & FI_SHORT) && !off)
267                         fin->fin_tcpf = tcp->th_flags;
268                 goto getports;
269         case IPPROTO_UDP :
270                 fi->fi_fl |= FI_TCPUDP;
271                 if ((!IPMINLEN(ip, udphdr) && !off) ||
272                     (off && off < sizeof(struct udphdr)))
273                         fi->fi_fl |= FI_SHORT;
274 getports:
275                 if (!off && (fin->fin_dlen > 3)) {
276                         fin->fin_data[0] = ntohs(tcp->th_sport);
277                         fin->fin_data[1] = ntohs(tcp->th_dport);
278                 }
279                 break;
280         default :
281                 break;
282         }
283
284
285         for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen; ) {
286                 opt = *s;
287                 if (opt == '\0')
288                         break;
289                 ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1);
290                 if (opt > 1 && (ol < 2 || ol > hlen))
291                         break;
292                 for (i = 9, mv = 4; mv >= 0; ) {
293                         op = ipopts + i;
294                         if (opt == (u_char)op->ol_val) {
295                                 optmsk |= op->ol_bit;
296                                 if (opt == IPOPT_SECURITY) {
297                                         struct optlist *sp;
298                                         u_char  sec;
299                                         int j, m;
300
301                                         sec = *(s + 2); /* classification */
302                                         for (j = 3, m = 2; m >= 0; ) {
303                                                 sp = secopt + j;
304                                                 if (sec == sp->ol_val) {
305                                                         secmsk |= sp->ol_bit;
306                                                         auth = *(s + 3);
307                                                         auth *= 256;
308                                                         auth += *(s + 4);
309                                                         break;
310                                                 }
311                                                 if (sec < sp->ol_val)
312                                                         j -= m--;
313                                                 else
314                                                         j += m--;
315                                         }
316                                 }
317                                 break;
318                         }
319                         if (opt < op->ol_val)
320                                 i -= mv--;
321                         else
322                                 i += mv--;
323                 }
324                 hlen -= ol;
325                 s += ol;
326         }
327         if (auth && !(auth & 0x0100))
328                 auth &= 0xff00;
329         fi->fi_optmsk = optmsk;
330         fi->fi_secmsk = secmsk;
331         fi->fi_auth = auth;
332 }
333
334
335 /*
336  * check an IP packet for TCP/UDP characteristics such as ports and flags.
337  */
338 static int fr_tcpudpchk(fr, fin)
339 frentry_t *fr;
340 fr_info_t *fin;
341 {
342         register u_short po, tup;
343         register char i;
344         register int err = 1;
345
346         /*
347          * Both ports should *always* be in the first fragment.
348          * So far, I cannot find any cases where they can not be.
349          *
350          * compare destination ports
351          */
352         if ((i = (int)fr->fr_dcmp)) {
353                 po = fr->fr_dport;
354                 tup = fin->fin_data[1];
355                 /*
356                  * Do opposite test to that required and
357                  * continue if that succeeds.
358                  */
359                 if (!--i && tup != po) /* EQUAL */
360                         err = 0;
361                 else if (!--i && tup == po) /* NOTEQUAL */
362                         err = 0;
363                 else if (!--i && tup >= po) /* LESSTHAN */
364                         err = 0;
365                 else if (!--i && tup <= po) /* GREATERTHAN */
366                         err = 0;
367                 else if (!--i && tup > po) /* LT or EQ */
368                         err = 0;
369                 else if (!--i && tup < po) /* GT or EQ */
370                         err = 0;
371                 else if (!--i &&           /* Out of range */
372                          (tup >= po && tup <= fr->fr_dtop))
373                         err = 0;
374                 else if (!--i &&           /* In range */
375                          (tup <= po || tup >= fr->fr_dtop))
376                         err = 0;
377         }
378         /*
379          * compare source ports
380          */
381         if (err && (i = (int)fr->fr_scmp)) {
382                 po = fr->fr_sport;
383                 tup = fin->fin_data[0];
384                 if (!--i && tup != po)
385                         err = 0;
386                 else if (!--i && tup == po)
387                         err = 0;
388                 else if (!--i && tup >= po)
389                         err = 0;
390                 else if (!--i && tup <= po)
391                         err = 0;
392                 else if (!--i && tup > po)
393                         err = 0;
394                 else if (!--i && tup < po)
395                         err = 0;
396                 else if (!--i &&           /* Out of range */
397                          (tup >= po && tup <= fr->fr_stop))
398                         err = 0;
399                 else if (!--i &&           /* In range */
400                          (tup <= po || tup >= fr->fr_stop))
401                         err = 0;
402         }
403
404         /*
405          * If we don't have all the TCP/UDP header, then how can we
406          * expect to do any sort of match on it ?  If we were looking for
407          * TCP flags, then NO match.  If not, then match (which should
408          * satisfy the "short" class too).
409          */
410         if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) {
411                 if (fin->fin_fi.fi_fl & FI_SHORT)
412                         return !(fr->fr_tcpf | fr->fr_tcpfm);
413                 /*
414                  * Match the flags ?  If not, abort this match.
415                  */
416                 if (fr->fr_tcpfm &&
417                     fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) {
418                         FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
419                                  fr->fr_tcpfm, fr->fr_tcpf));
420                         err = 0;
421                 }
422         }
423         return err;
424 }
425
426 /*
427  * Check the input/output list of rules for a match and result.
428  * Could be per interface, but this gets real nasty when you don't have
429  * kernel sauce.
430  */
431 int fr_scanlist(pass, ip, fin, m)
432 u_32_t pass;
433 ip_t *ip;
434 register fr_info_t *fin;
435 void *m;
436 {
437         register struct frentry *fr;
438         register fr_ip_t *fi = &fin->fin_fi;
439         int rulen, portcmp = 0, off, skip = 0, logged = 0;
440         u_32_t passt;
441
442         fr = fin->fin_fr;
443         fin->fin_fr = NULL;
444         fin->fin_rule = 0;
445         fin->fin_group = 0;
446         off = ip->ip_off & IP_OFFMASK;
447         pass |= (fi->fi_fl << 24);
448
449         if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
450                 portcmp = 1;
451
452         for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
453                 if (skip) {
454                         skip--;
455                         continue;
456                 }
457                 /*
458                  * In all checks below, a null (zero) value in the
459                  * filter struture is taken to mean a wildcard.
460                  *
461                  * check that we are working for the right interface
462                  */
463 #ifdef  _KERNEL
464 # if BSD >= 199306
465                 if (fin->fin_out != 0) {
466                         if ((fr->fr_oifa &&
467                              fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif) ||
468                             (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp))
469                                 continue;
470                 } else
471 # endif
472                         if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
473                                 continue;
474 #else
475                 if (opts & (OPT_VERBOSE|OPT_DEBUG))
476                         printf("\n");
477                 FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 
478                                   (pass & FR_AUTH) ? 'a' : 'b'));
479                 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
480                         continue;
481                 FR_VERBOSE((":i"));
482 #endif
483                 {
484                         register u_32_t *ld, *lm, *lip;
485                         register int i;
486
487                         lip = (u_32_t *)fi;
488                         lm = (u_32_t *)&fr->fr_mip;
489                         ld = (u_32_t *)&fr->fr_ip;
490                         i = ((lip[0] & lm[0]) != ld[0]);
491                         FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n",
492                                    lip[0], lm[0], ld[0]));
493                         i |= ((lip[1] & lm[1]) != ld[1]) << 19;
494                         i ^= (fr->fr_flags & FR_NOTSRCIP);
495                         FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
496                                    lip[1], lm[1], ld[1]));
497                         i |= ((lip[2] & lm[2]) != ld[2]) << 20;
498                         i ^= (fr->fr_flags & FR_NOTDSTIP);
499                         FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
500                                    lip[2], lm[2], ld[2]));
501                         i |= ((lip[3] & lm[3]) != ld[3]);
502                         FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n",
503                                    lip[3], lm[3], ld[3]));
504                         i |= ((lip[4] & lm[4]) != ld[4]);
505                         FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
506                                    lip[4], lm[4], ld[4]));
507                         if (i)
508                                 continue;
509                 }
510
511                 /*
512                  * If a fragment, then only the first has what we're looking
513                  * for here...
514                  */
515                 if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
516                                  fr->fr_tcpfm))
517                         continue;
518                 if (fi->fi_fl & FI_TCPUDP) {
519                         if (!fr_tcpudpchk(fr, fin))
520                                 continue;
521                 } else if (fr->fr_icmpm || fr->fr_icmp) {
522                         if ((fi->fi_p != IPPROTO_ICMP) || off ||
523                             (fin->fin_dlen < 2))
524                                 continue;
525                         if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) {
526                                 FR_DEBUG(("i. %#x & %#x != %#x\n",
527                                          fin->fin_data[0], fr->fr_icmpm,
528                                          fr->fr_icmp));
529                                 continue;
530                         }
531                 }
532                 FR_VERBOSE(("*"));
533                 /*
534                  * Just log this packet...
535                  */
536                 passt = fr->fr_flags;
537                 if ((passt & FR_CALLNOW) && fr->fr_func)
538                         passt = (*fr->fr_func)(passt, ip, fin);
539                 fin->fin_fr = fr;
540 #ifdef  IPFILTER_LOG
541                 if ((passt & FR_LOGMASK) == FR_LOG) {
542                         if (!IPLLOG(passt, ip, fin, m)) {
543                                 ATOMIC_INC(frstats[fin->fin_out].fr_skip);
544                         }
545                         ATOMIC_INC(frstats[fin->fin_out].fr_pkl);
546                         logged = 1;
547                 }
548 #endif /* IPFILTER_LOG */
549                 if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG)
550                         pass = passt;
551                 FR_DEBUG(("pass %#x\n", pass));
552                 ATOMIC_INC(fr->fr_hits);
553                 if (pass & FR_ACCOUNT)
554                         fr->fr_bytes += (U_QUAD_T)ip->ip_len;
555                 else
556                         fin->fin_icode = fr->fr_icode;
557                 fin->fin_rule = rulen;
558                 fin->fin_group = fr->fr_group;
559                 if (fr->fr_grp) {
560                         fin->fin_fr = fr->fr_grp;
561                         pass = fr_scanlist(pass, ip, fin, m);
562                         if (fin->fin_fr == NULL) {
563                                 fin->fin_rule = rulen;
564                                 fin->fin_group = fr->fr_group;
565                                 fin->fin_fr = fr;
566                         }
567                         if (pass & FR_DONTCACHE)
568                                 logged = 1;
569                 }
570                 if (pass & FR_QUICK)
571                         break;
572         }
573         if (logged)
574                 pass |= FR_DONTCACHE;
575         return pass;
576 }
577
578
579 /*
580  * frcheck - filter check
581  * check using source and destination addresses/ports in a packet whether
582  * or not to pass it on or not.
583  */
584 int fr_check(ip, hlen, ifp, out
585 #if defined(_KERNEL) && SOLARIS
586 , qif, mp)
587 qif_t *qif;
588 #else
589 , mp)
590 #endif
591 mb_t **mp;
592 ip_t *ip;
593 int hlen;
594 void *ifp;
595 int out;
596 {
597         /*
598          * The above really sucks, but short of writing a diff
599          */
600         fr_info_t frinfo, *fc;
601         register fr_info_t *fin = &frinfo;
602         frentry_t *fr = NULL;
603         int changed, error = EHOSTUNREACH;
604         u_32_t pass, apass;
605 #if !SOLARIS || !defined(_KERNEL)
606         register mb_t *m = *mp;
607 #endif
608
609 #ifdef  _KERNEL
610         mb_t *mc = NULL;
611 # if !defined(__SVR4) && !defined(__svr4__)
612 #  ifdef __sgi
613         char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8];
614 #  endif
615         int up;
616
617 #  ifdef M_CANFASTFWD
618         /*
619          * XXX For now, IP Filter and fast-forwarding of cached flows
620          * XXX are mutually exclusive.  Eventually, IP Filter should
621          * XXX get a "can-fast-forward" filter rule.
622          */
623         m->m_flags &= ~M_CANFASTFWD;
624 #  endif /* M_CANFASTFWD */
625
626         if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
627              ip->ip_p == IPPROTO_ICMP)) {
628                 int plen = 0;
629
630                 if ((ip->ip_off & IP_OFFMASK) == 0)
631                         switch(ip->ip_p)
632                         {
633                         case IPPROTO_TCP:
634                                 plen = sizeof(tcphdr_t);
635                                 break;
636                         case IPPROTO_UDP:
637                                 plen = sizeof(udphdr_t);
638                                 break;
639                         /* 96 - enough for complete ICMP error IP header */
640                         case IPPROTO_ICMP:
641                                 plen = ICMPERR_MAXPKTLEN - sizeof(ip_t);
642                                 break;
643                         }
644                 up = MIN(hlen + plen, ip->ip_len);
645
646                 if (up > m->m_len) {
647 #  ifdef __sgi
648         /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */
649                         if ((up > sizeof(hbuf)) || (m_length(m) < up)) {
650                                 ATOMIC_INC(frstats[out].fr_pull[1]);
651                                 return -1;
652                         }
653                         m_copydata(m, 0, up, hbuf);
654                         ATOMIC_INC(frstats[out].fr_pull[0]);
655                         ip = (ip_t *)hbuf;
656 #  else /* __ sgi */
657 #   ifndef linux
658                         if ((*mp = m_pullup(m, up)) == 0) {
659                                 ATOMIC_INC(frstats[out].fr_pull[1]);
660                                 return -1;
661                         } else {
662                                 ATOMIC_INC(frstats[out].fr_pull[0]);
663                                 m = *mp;
664                                 ip = mtod(m, ip_t *);
665                         }
666 #   endif /* !linux */
667 #  endif /* __sgi */
668                 } else
669                         up = 0;
670         } else
671                 up = 0;
672 # endif /* !defined(__SVR4) && !defined(__svr4__) */
673 # if SOLARIS
674         mb_t *m = qif->qf_m;
675
676         if ((u_int)ip & 0x3)
677                 return 2;
678         fin->fin_qfm = m;
679         fin->fin_qif = qif;
680 # endif
681 #endif /* _KERNEL */
682
683         /*
684          * Be careful here: ip_id is in network byte order when called
685          * from ip_output()
686          */
687         if (out)
688                 ip->ip_id = ntohs(ip->ip_id);
689         fr_makefrip(hlen, ip, fin);
690         fin->fin_ifp = ifp;
691         fin->fin_out = out;
692         fin->fin_mp = mp;
693         pass = fr_pass;
694
695         READ_ENTER(&ipf_mutex);
696
697         if (fin->fin_fi.fi_fl & FI_SHORT)
698                 ATOMIC_INC(frstats[out].fr_short);
699         
700         /*
701          * Check auth now.  This, combined with the check below to see if apass
702          * is 0 is to ensure that we don't count the packet twice, which can
703          * otherwise occur when we reprocess it.  As it is, we only count it
704          * after it has no auth. table matchup.  This also stops NAT from
705          * occuring until after the packet has been auth'd.
706          */
707         apass = fr_checkauth(ip, fin);
708
709         if (!out) {
710                 changed = ip_natin(ip, fin);
711                 if (!apass && (fin->fin_fr = ipacct[0][fr_active]) &&
712                     (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
713                         ATOMIC_INC(frstats[0].fr_acct);
714                 }
715         }
716
717         if (apass || (!(fr = ipfr_knownfrag(ip, fin)) &&
718             !(fr = fr_checkstate(ip, fin)))) {
719                 /*
720                  * If a packet is found in the auth table, then skip checking
721                  * the access lists for permission but we do need to consider
722                  * the result as if it were from the ACL's.
723                  */
724                 if (!apass) {
725                         fc = frcache + out;
726                         if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
727                                 /*
728                                  * copy cached data so we can unlock the mutex
729                                  * earlier.
730                                  */
731                                 bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
732                                 ATOMIC_INC(frstats[out].fr_chit);
733                                 if ((fr = fin->fin_fr)) {
734                                         ATOMIC_INC(fr->fr_hits);
735                                         pass = fr->fr_flags;
736                                 }
737                         } else {
738                                 if ((fin->fin_fr = ipfilter[out][fr_active]))
739                                         pass = fr_scanlist(fr_pass, ip, fin, m);
740                                 if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE)))
741                                         bcopy((char *)fin, (char *)fc,
742                                               FI_COPYSIZE);
743                                 if (pass & FR_NOMATCH) {
744                                         ATOMIC_INC(frstats[out].fr_nom);
745                                 }
746                         }
747                         fr = fin->fin_fr;
748                 } else
749                         pass = apass;
750
751                 /*
752                  * If we fail to add a packet to the authorization queue,
753                  * then we drop the packet later.  However, if it was added
754                  * then pretend we've dropped it already.
755                  */
756                 if ((pass & FR_AUTH))
757                         if (FR_NEWAUTH(m, fin, ip, qif) != 0)
758 #ifdef  _KERNEL
759                                 m = *mp = NULL;
760 #else
761                                 ;
762 #endif
763
764                 if (pass & FR_PREAUTH) {
765                         READ_ENTER(&ipf_auth);
766                         if ((fin->fin_fr = ipauth) &&
767                             (pass = fr_scanlist(0, ip, fin, m))) {
768                                 ATOMIC_INC(fr_authstats.fas_hits);
769                         } else {
770                                 ATOMIC_INC(fr_authstats.fas_miss);
771                         }
772                         RWLOCK_EXIT(&ipf_auth);
773                 }
774
775                 fin->fin_fr = fr;
776                 if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
777                         if (fin->fin_fi.fi_fl & FI_FRAG) {
778                                 if (ipfr_newfrag(ip, fin, pass) == -1) {
779                                         ATOMIC_INC(frstats[out].fr_bnfr);
780                                 } else {
781                                         ATOMIC_INC(frstats[out].fr_nfr);
782                                 }
783                         } else {
784                                 ATOMIC_INC(frstats[out].fr_cfr);
785                         }
786                 }
787                 if (pass & FR_KEEPSTATE) {
788                         if (fr_addstate(ip, fin, 0) == NULL) {
789                                 ATOMIC_INC(frstats[out].fr_bads);
790                         } else {
791                                 ATOMIC_INC(frstats[out].fr_ads);
792                         }
793                 }
794         } else if (fr != NULL) {
795                 pass = fr->fr_flags;
796                 if (pass & FR_LOGFIRST)
797                         pass &= ~(FR_LOGFIRST|FR_LOG);
798         }
799
800         if (fr && fr->fr_func && !(pass & FR_CALLNOW))
801                 pass = (*fr->fr_func)(pass, ip, fin);
802
803         /*
804          * Only count/translate packets which will be passed on, out the
805          * interface.
806          */
807         if (out && (pass & FR_PASS)) {
808                 if ((fin->fin_fr = ipacct[1][fr_active]) &&
809                     (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) {
810                         ATOMIC_INC(frstats[1].fr_acct);
811                 }
812                 fin->fin_fr = fr;
813                 changed = ip_natout(ip, fin);
814         } else
815                 fin->fin_fr = fr;
816         RWLOCK_EXIT(&ipf_mutex);
817
818 #ifdef  IPFILTER_LOG
819         if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
820                 if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
821                         pass |= FF_LOGNOMATCH;
822                         ATOMIC_INC(frstats[out].fr_npkl);
823                         goto logit;
824                 } else if (((pass & FR_LOGMASK) == FR_LOGP) ||
825                     ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
826                         if ((pass & FR_LOGMASK) != FR_LOGP)
827                                 pass |= FF_LOGPASS;
828                         ATOMIC_INC(frstats[out].fr_ppkl);
829                         goto logit;
830                 } else if (((pass & FR_LOGMASK) == FR_LOGB) ||
831                            ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
832                         if ((pass & FR_LOGMASK) != FR_LOGB)
833                                 pass |= FF_LOGBLOCK;
834                         ATOMIC_INC(frstats[out].fr_bpkl);
835 logit:
836                         if (!IPLLOG(pass, ip, fin, m)) {
837                                 ATOMIC_INC(frstats[out].fr_skip);
838                                 if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
839                                     (FR_PASS|FR_LOGORBLOCK))
840                                         pass ^= FR_PASS|FR_BLOCK;
841                         }
842                 }
843         }
844 #endif /* IPFILTER_LOG */
845
846         if (out)
847                 ip->ip_id = htons(ip->ip_id);
848
849 #ifdef  _KERNEL
850         /*
851          * Only allow FR_DUP to work if a rule matched - it makes no sense to
852          * set FR_DUP as a "default" as there are no instructions about where
853          * to send the packet.
854          */
855         if (fr && (pass & FR_DUP))
856 # if    SOLARIS
857                 mc = dupmsg(m);
858 # else
859 #  ifndef linux
860                 mc = m_copy(m, 0, M_COPYALL);
861 #  else
862                 ;
863 #  endif
864 # endif
865 #endif
866         if (pass & FR_PASS) {
867                 ATOMIC_INC(frstats[out].fr_pass);
868         } else if (pass & FR_BLOCK) {
869                 ATOMIC_INC(frstats[out].fr_block);
870                 /*
871                  * Should we return an ICMP packet to indicate error
872                  * status passing through the packet filter ?
873                  * WARNING: ICMP error packets AND TCP RST packets should
874                  * ONLY be sent in repsonse to incoming packets.  Sending them
875                  * in response to outbound packets can result in a panic on
876                  * some operating systems.
877                  */
878                 if (!out) {
879 #ifdef  _KERNEL
880                         if (pass & FR_RETICMP) {
881                                 struct in_addr dst;
882
883                                 if ((pass & FR_RETMASK) == FR_FAKEICMP)
884                                         dst = ip->ip_dst;
885                                 else
886                                         dst.s_addr = 0;
887 # if SOLARIS
888                                 ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode,
889                                            qif, dst);
890 # else
891                                 ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode,
892                                            ifp, dst);
893 # endif
894                                 ATOMIC_INC(frstats[0].fr_ret);
895                         } else if (((pass & FR_RETMASK) == FR_RETRST) &&
896                                    !(fin->fin_fi.fi_fl & FI_SHORT)) {
897                                 if (SEND_RESET(ip, qif, ifp, fin) == 0) {
898                                         ATOMIC_INC(frstats[1].fr_ret);
899                                 }
900                         }
901 #else
902                         if ((pass & FR_RETMASK) == FR_RETICMP) {
903                                 verbose("- ICMP unreachable sent\n");
904                                 ATOMIC_INC(frstats[0].fr_ret);
905                         } else if ((pass & FR_RETMASK) == FR_FAKEICMP) {
906                                 verbose("- forged ICMP unreachable sent\n");
907                                 ATOMIC_INC(frstats[0].fr_ret);
908                         } else if (((pass & FR_RETMASK) == FR_RETRST) &&
909                                    !(fin->fin_fi.fi_fl & FI_SHORT)) {
910                                 verbose("- TCP RST sent\n");
911                                 ATOMIC_INC(frstats[1].fr_ret);
912                         }
913 #endif
914                 } else {
915                         if (pass & FR_RETRST)
916                                 error = ECONNRESET;
917                 }
918         }
919
920         /*
921          * If we didn't drop off the bottom of the list of rules (and thus
922          * the 'current' rule fr is not NULL), then we may have some extra
923          * instructions about what to do with a packet.
924          * Once we're finished return to our caller, freeing the packet if
925          * we are dropping it (* BSD ONLY *).
926          */
927 #if defined(_KERNEL)
928 # if !SOLARIS
929 #  if !defined(linux)
930         if (fr) {
931                 frdest_t *fdp = &fr->fr_tif;
932
933                 if (((pass & FR_FASTROUTE) && !out) ||
934                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
935                         if (ipfr_fastroute(m, fin, fdp) == 0)
936                                 m = *mp = NULL;
937                 }
938                 if (mc)
939                         ipfr_fastroute(mc, fin, &fr->fr_dif);
940         }
941         if (!(pass & FR_PASS) && m)
942                 m_freem(m);
943 #   ifdef __sgi
944         else if (changed && up && m)
945                 m_copyback(m, 0, up, hbuf);
946 #   endif
947 #  endif /* !linux */
948 # else /* !SOLARIS */
949         if (fr) {
950                 frdest_t *fdp = &fr->fr_tif;
951
952                 if (((pass & FR_FASTROUTE) && !out) ||
953                     (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
954                         if (ipfr_fastroute(qif, ip, m, mp, fin, fdp) == 0)
955                                 m = *mp = NULL;
956                 }
957                 if (mc)
958                         ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif);
959         }
960 # endif /* !SOLARIS */
961         return (pass & FR_PASS) ? 0 : error;
962 #else /* _KERNEL */
963         if (pass & FR_NOMATCH)
964                 return 1;
965         if (pass & FR_PASS)
966                 return 0;
967         if (pass & FR_AUTH)
968                 return -2;
969         return -1;
970 #endif /* _KERNEL */
971 }
972
973
974 /*
975  * ipf_cksum
976  * addr should be 16bit aligned and len is in bytes.
977  * length is in bytes
978  */
979 u_short ipf_cksum(addr, len)
980 register u_short *addr;
981 register int len;
982 {
983         register u_32_t sum = 0;
984
985         for (sum = 0; len > 1; len -= 2)
986                 sum += *addr++;
987
988         /* mop up an odd byte, if necessary */
989         if (len == 1)
990                 sum += *(u_char *)addr;
991
992         /*
993          * add back carry outs from top 16 bits to low 16 bits
994          */
995         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
996         sum += (sum >> 16);                     /* add carry */
997         return (u_short)(~sum);
998 }
999
1000
1001 /*
1002  * NB: This function assumes we've pullup'd enough for all of the IP header
1003  * and the TCP header.  We also assume that data blocks aren't allocated in
1004  * odd sizes.
1005  */
1006 u_short fr_tcpsum(m, ip, tcp)
1007 mb_t *m;
1008 ip_t *ip;
1009 tcphdr_t *tcp;
1010 {
1011         u_short *sp, slen, ts;
1012         u_int sum, sum2;
1013         int hlen;
1014
1015         /*
1016          * Add up IP Header portion
1017          */
1018         hlen = ip->ip_hl << 2;
1019         slen = ip->ip_len - hlen;
1020         sum = htons((u_short)ip->ip_p);
1021         sum += htons(slen);
1022         sp = (u_short *)&ip->ip_src;
1023         sum += *sp++;   /* ip_src */
1024         sum += *sp++;
1025         sum += *sp++;   /* ip_dst */
1026         sum += *sp++;
1027         ts = tcp->th_sum;
1028         tcp->th_sum = 0;
1029 #ifdef  KERNEL
1030 # if SOLARIS
1031         sum2 = ip_cksum(m, hlen, sum);  /* hlen == offset */
1032         sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1033         sum2 = ~sum2 & 0xffff;
1034 # else /* SOLARIS */
1035 #  if defined(BSD) || defined(sun)
1036 #   if BSD >= 199306
1037         m->m_data += hlen;
1038 #   else
1039         m->m_off += hlen;
1040 #   endif
1041         m->m_len -= hlen;
1042         sum2 = in_cksum(m, slen);
1043         m->m_len += hlen;
1044 #   if BSD >= 199306
1045         m->m_data -= hlen;
1046 #   else
1047         m->m_off -= hlen;
1048 #   endif
1049         /*
1050          * Both sum and sum2 are partial sums, so combine them together.
1051          */
1052         sum = (sum & 0xffff) + (sum >> 16);
1053         sum = ~sum & 0xffff;
1054         sum2 += sum;
1055         sum2 = (sum2 & 0xffff) + (sum2 >> 16);
1056 #  else /* defined(BSD) || defined(sun) */
1057 {
1058         union {
1059                 u_char  c[2];
1060                 u_short s;
1061         } bytes;
1062         u_short len = ip->ip_len;
1063 # if defined(__sgi)
1064         int add;
1065 # endif
1066
1067         /*
1068          * Add up IP Header portion
1069          */
1070         sp = (u_short *)&ip->ip_src;
1071         len -= (ip->ip_hl << 2);
1072         sum = ntohs(IPPROTO_TCP);
1073         sum += htons(len);
1074         sum += *sp++;   /* ip_src */
1075         sum += *sp++;
1076         sum += *sp++;   /* ip_dst */
1077         sum += *sp++;
1078         if (sp != (u_short *)tcp)
1079                 sp = (u_short *)tcp;
1080         sum += *sp++;   /* sport */
1081         sum += *sp++;   /* dport */
1082         sum += *sp++;   /* seq */
1083         sum += *sp++;
1084         sum += *sp++;   /* ack */
1085         sum += *sp++;
1086         sum += *sp++;   /* off */
1087         sum += *sp++;   /* win */
1088         sum += *sp++;   /* Skip over checksum */
1089         sum += *sp++;   /* urp */
1090
1091 # ifdef __sgi
1092         /*
1093          * In case we had to copy the IP & TCP header out of mbufs,
1094          * skip over the mbuf bits which are the header
1095          */
1096         if ((caddr_t)ip != mtod(m, caddr_t)) {
1097                 hlen = (caddr_t)sp - (caddr_t)ip;
1098                 while (hlen) {
1099                         add = MIN(hlen, m->m_len);
1100                         sp = (u_short *)(mtod(m, caddr_t) + add);
1101                         hlen -= add;
1102                         if (add == m->m_len) {
1103                                 m = m->m_next;
1104                                 if (!hlen) {
1105                                         if (!m)
1106                                                 break;
1107                                         sp = mtod(m, u_short *);
1108                                 }
1109                                 PANIC((!m),("fr_tcpsum(1): not enough data"));
1110                         }
1111                 }
1112         }
1113 # endif
1114
1115         if (!(len -= sizeof(*tcp)))
1116                 goto nodata;
1117         while (len > 1) {
1118                 if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) {
1119                         m = m->m_next;
1120                         PANIC((!m),("fr_tcpsum(2): not enough data"));
1121                         sp = mtod(m, u_short *);
1122                 }
1123                 if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) {
1124                         bytes.c[0] = *(u_char *)sp;
1125                         m = m->m_next;
1126                         PANIC((!m),("fr_tcpsum(3): not enough data"));
1127                         sp = mtod(m, u_short *);
1128                         bytes.c[1] = *(u_char *)sp;
1129                         sum += bytes.s;
1130                         sp = (u_short *)((u_char *)sp + 1);
1131                 }
1132                 if ((u_long)sp & 1) {
1133                         bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
1134                         sum += bytes.s;
1135                 } else
1136                         sum += *sp++;
1137                 len -= 2;
1138         }
1139         if (len)
1140                 sum += ntohs(*(u_char *)sp << 8);
1141 nodata:
1142         while (sum > 0xffff)
1143                 sum = (sum & 0xffff) + (sum >> 16);
1144         sum2 = (u_short)(~sum & 0xffff);
1145 }
1146 #  endif /*  defined(BSD) || defined(sun) */
1147 # endif /* SOLARIS */
1148 #else /* KERNEL */
1149         sum2 = 0;
1150 #endif /* KERNEL */
1151         tcp->th_sum = ts;
1152         return sum2;
1153 }
1154
1155
1156 #if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) )
1157 /*
1158  * Copyright (c) 1982, 1986, 1988, 1991, 1993
1159  *      The Regents of the University of California.  All rights reserved.
1160  *
1161  * Redistribution and use in source and binary forms, with or without
1162  * modification, are permitted provided that the following conditions
1163  * are met:
1164  * 1. Redistributions of source code must retain the above copyright
1165  *    notice, this list of conditions and the following disclaimer.
1166  * 2. Redistributions in binary form must reproduce the above copyright
1167  *    notice, this list of conditions and the following disclaimer in the
1168  *    documentation and/or other materials provided with the distribution.
1169  * 3. All advertising materials mentioning features or use of this software
1170  *    must display the following acknowledgement:
1171  *      This product includes software developed by the University of
1172  *      California, Berkeley and its contributors.
1173  * 4. Neither the name of the University nor the names of its contributors
1174  *    may be used to endorse or promote products derived from this software
1175  *    without specific prior written permission.
1176  *
1177  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1178  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1179  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1180  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1181  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1182  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1183  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1184  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1185  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1186  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1187  * SUCH DAMAGE.
1188  *
1189  *      @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
1190  * $Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darrenr Exp $
1191  */
1192 /*
1193  * Copy data from an mbuf chain starting "off" bytes from the beginning,
1194  * continuing for "len" bytes, into the indicated buffer.
1195  */
1196 void
1197 m_copydata(m, off, len, cp)
1198         register mb_t *m;
1199         register int off;
1200         register int len;
1201         caddr_t cp;
1202 {
1203         register unsigned count;
1204
1205         if (off < 0 || len < 0)
1206                 panic("m_copydata");
1207         while (off > 0) {
1208                 if (m == 0)
1209                         panic("m_copydata");
1210                 if (off < m->m_len)
1211                         break;
1212                 off -= m->m_len;
1213                 m = m->m_next;
1214         }
1215         while (len > 0) {
1216                 if (m == 0)
1217                         panic("m_copydata");
1218                 count = MIN(m->m_len - off, len);
1219                 bcopy(mtod(m, caddr_t) + off, cp, count);
1220                 len -= count;
1221                 cp += count;
1222                 off = 0;
1223                 m = m->m_next;
1224         }
1225 }
1226
1227
1228 # ifndef linux
1229 /*
1230  * Copy data from a buffer back into the indicated mbuf chain,
1231  * starting "off" bytes from the beginning, extending the mbuf
1232  * chain if necessary.
1233  */
1234 void
1235 m_copyback(m0, off, len, cp)
1236         struct  mbuf *m0;
1237         register int off;
1238         register int len;
1239         caddr_t cp;
1240 {
1241         register int mlen;
1242         register struct mbuf *m = m0, *n;
1243         int totlen = 0;
1244
1245         if (m0 == 0)
1246                 return;
1247         while (off > (mlen = m->m_len)) {
1248                 off -= mlen;
1249                 totlen += mlen;
1250                 if (m->m_next == 0) {
1251                         n = m_getclr(M_DONTWAIT, m->m_type);
1252                         if (n == 0)
1253                                 goto out;
1254                         n->m_len = min(MLEN, len + off);
1255                         m->m_next = n;
1256                 }
1257                 m = m->m_next;
1258         }
1259         while (len > 0) {
1260                 mlen = min (m->m_len - off, len);
1261                 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
1262                 cp += mlen;
1263                 len -= mlen;
1264                 mlen += off;
1265                 off = 0;
1266                 totlen += mlen;
1267                 if (len == 0)
1268                         break;
1269                 if (m->m_next == 0) {
1270                         n = m_get(M_DONTWAIT, m->m_type);
1271                         if (n == 0)
1272                                 break;
1273                         n->m_len = min(MLEN, len);
1274                         m->m_next = n;
1275                 }
1276                 m = m->m_next;
1277         }
1278 out:
1279 #if 0
1280         if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
1281                 m->m_pkthdr.len = totlen;
1282 #endif
1283         return;
1284 }
1285 # endif /* linux */
1286 #endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */
1287
1288
1289 frgroup_t *fr_findgroup(num, flags, which, set, fgpp)
1290 u_int num;
1291 u_32_t flags;
1292 minor_t which;
1293 int set;
1294 frgroup_t ***fgpp;
1295 {
1296         frgroup_t *fg, **fgp;
1297
1298         if (which == IPL_LOGAUTH)
1299                 fgp = &ipfgroups[2][set];
1300         else if (flags & FR_ACCOUNT)
1301                 fgp = &ipfgroups[1][set];
1302         else if (flags & (FR_OUTQUE|FR_INQUE))
1303                 fgp = &ipfgroups[0][set];
1304         else
1305                 return NULL;
1306         num &= 0xffff;
1307
1308         while ((fg = *fgp))
1309                 if (fg->fg_num == num)
1310                         break;
1311                 else
1312                         fgp = &fg->fg_next;
1313         if (fgpp)
1314                 *fgpp = fgp;
1315         return fg;
1316 }
1317
1318
1319 frgroup_t *fr_addgroup(num, fp, which, set)
1320 u_int num;
1321 frentry_t *fp;
1322 minor_t which;
1323 int set;
1324 {
1325         frgroup_t *fg, **fgp;
1326
1327         if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp)))
1328                 return fg;
1329
1330         KMALLOC(fg, frgroup_t *);
1331         if (fg) {
1332                 fg->fg_num = num & 0xffff;
1333                 fg->fg_next = *fgp;
1334                 fg->fg_head = fp;
1335                 fg->fg_start = &fp->fr_grp;
1336                 *fgp = fg;
1337         }
1338         return fg;
1339 }
1340
1341
1342 void fr_delgroup(num, flags, which, set)
1343 u_int num;
1344 u_32_t flags;
1345 minor_t which;
1346 int set;
1347 {
1348         frgroup_t *fg, **fgp;
1349  
1350         if (!(fg = fr_findgroup(num, flags, which, set, &fgp)))
1351                 return;
1352  
1353         *fgp = fg->fg_next;
1354         KFREE(fg);
1355 }
1356
1357
1358
1359 /*
1360  * recursively flush rules from the list, descending groups as they are
1361  * encountered.  if a rule is the head of a group and it has lost all its
1362  * group members, then also delete the group reference.
1363  */
1364 static int frflushlist(set, unit, nfreedp, listp)
1365 int set;
1366 minor_t unit;
1367 int *nfreedp;
1368 frentry_t **listp;
1369 {
1370         register int freed = 0, i;
1371         register frentry_t *fp;
1372
1373         while ((fp = *listp)) {
1374                 *listp = fp->fr_next;
1375                 if (fp->fr_grp) {
1376                         i = frflushlist(set, unit, nfreedp, &fp->fr_grp);
1377                         MUTEX_ENTER(&ipf_rw);
1378                         fp->fr_ref -= i;
1379                         MUTEX_EXIT(&ipf_rw);
1380                 }
1381
1382                 ATOMIC_DEC(fp->fr_ref);
1383                 if (fp->fr_grhead) {
1384                         fr_delgroup((u_int)fp->fr_grhead, fp->fr_flags, 
1385                                     unit, set);
1386                         fp->fr_grhead = NULL;
1387                 }
1388                 if (fp->fr_ref == 0) {
1389                         KFREE(fp);
1390                         freed++;
1391                 } else
1392                         fp->fr_next = NULL;
1393         }
1394         *nfreedp += freed;
1395         return freed;
1396 }
1397
1398
1399 int frflush(unit, flags)
1400 minor_t unit;
1401 int flags;
1402 {
1403         int flushed = 0, set;
1404
1405         if (unit != IPL_LOGIPF)
1406                 return 0;
1407         WRITE_ENTER(&ipf_mutex);
1408         bzero((char *)frcache, sizeof(frcache[0]) * 2);
1409
1410         set = fr_active;
1411         if (flags & FR_INACTIVE)
1412                 set = 1 - set;
1413
1414         if (flags & FR_OUTQUE) {
1415                 (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]);
1416                 (void) frflushlist(set, unit, &flushed, &ipacct[1][set]);
1417         }
1418         if (flags & FR_INQUE) {
1419                 (void) frflushlist(set, unit, &flushed, &ipfilter[0][set]);
1420                 (void) frflushlist(set, unit, &flushed, &ipacct[0][set]);
1421         }
1422         RWLOCK_EXIT(&ipf_mutex);
1423         return flushed;
1424 }
1425
1426
1427 char *memstr(src, dst, slen, dlen)
1428 char *src, *dst;
1429 int slen, dlen;
1430 {
1431         char *s = NULL;
1432
1433         while (dlen >= slen) {
1434                 if (bcmp(src, dst, slen) == 0) {
1435                         s = dst;
1436                         break;
1437                 }
1438                 dst++;
1439                 dlen--;
1440         }
1441         return s;
1442 }
1443
1444
1445 void fixskip(listp, rp, addremove)
1446 frentry_t **listp, *rp;
1447 int addremove;
1448 {
1449         frentry_t *fp;
1450         int rules = 0, rn = 0;
1451
1452         for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++)
1453                 ;
1454
1455         if (!fp)
1456                 return;
1457
1458         for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++)
1459                 if (fp->fr_skip && (rn + fp->fr_skip >= rules))
1460                         fp->fr_skip += addremove;
1461 }
1462
1463
1464 #ifdef  _KERNEL
1465 /*
1466  * count consecutive 1's in bit mask.  If the mask generated by counting
1467  * consecutive 1's is different to that passed, return -1, else return #
1468  * of bits.
1469  */
1470 int     countbits(ip)
1471 u_32_t  ip;
1472 {
1473         u_32_t  ipn;
1474         int     cnt = 0, i, j;
1475
1476         ip = ipn = ntohl(ip);
1477         for (i = 32; i; i--, ipn *= 2)
1478                 if (ipn & 0x80000000)
1479                         cnt++;
1480                 else
1481                         break;
1482         ipn = 0;
1483         for (i = 32, j = cnt; i; i--, j--) {
1484                 ipn *= 2;
1485                 if (j > 0)
1486                         ipn++;
1487         }
1488         if (ipn == ip)
1489                 return cnt;
1490         return -1;
1491 }
1492
1493
1494 /*
1495  * return the first IP Address associated with an interface
1496  */
1497 int fr_ifpaddr(ifptr, inp)
1498 void *ifptr;
1499 struct in_addr *inp;
1500 {
1501 # if SOLARIS
1502         ill_t *ill = ifptr;
1503 # else
1504         struct ifnet *ifp = ifptr;
1505 # endif
1506         struct in_addr in;
1507
1508 # if SOLARIS
1509         in.s_addr = ill->ill_ipif->ipif_local_addr;
1510 # else /* SOLARIS */
1511 #  if linux
1512         ;
1513 #  else /* linux */
1514         struct ifaddr *ifa;
1515         struct sockaddr_in *sin;
1516
1517 #   if  (__FreeBSD_version >= 300000)
1518         ifa = TAILQ_FIRST(&ifp->if_addrhead);
1519 #   else
1520 #    if defined(__NetBSD__) || defined(__OpenBSD__)
1521         ifa = ifp->if_addrlist.tqh_first;
1522 #    else
1523 #     if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
1524         ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa;
1525 #     else
1526         ifa = ifp->if_addrlist;
1527 #     endif
1528 #    endif /* __NetBSD__ || __OpenBSD__ */
1529 #   endif /* __FreeBSD_version >= 300000 */
1530 #   if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK))
1531         sin = (struct sockaddr_in *)&ifa->ifa_addr;
1532 #   else
1533         sin = (struct sockaddr_in *)ifa->ifa_addr;
1534         while (sin && ifa &&
1535                sin->sin_family != AF_INET) {
1536 #    if (__FreeBSD_version >= 300000)
1537                 ifa = TAILQ_NEXT(ifa, ifa_link);
1538 #    else
1539 #     if defined(__NetBSD__) || defined(__OpenBSD__)
1540                 ifa = ifa->ifa_list.tqe_next;
1541 #     else
1542                 ifa = ifa->ifa_next;
1543 #     endif
1544 #    endif /* __FreeBSD_version >= 300000 */
1545                 if (ifa)
1546                         sin = (struct sockaddr_in *)ifa->ifa_addr;
1547         }
1548         if (ifa == NULL)
1549                 sin = NULL;
1550         if (sin == NULL)
1551                 return -1;
1552 #   endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */
1553         in = sin->sin_addr;
1554 #  endif /* linux */
1555 # endif /* SOLARIS */
1556         *inp = in;
1557         return 0;
1558 }
1559
1560
1561 static void frsynclist(fr)
1562 register frentry_t *fr;
1563 {
1564         for (; fr; fr = fr->fr_next) {
1565                 if (fr->fr_ifa != NULL) {
1566                         fr->fr_ifa = GETUNIT(fr->fr_ifname);
1567                         if (fr->fr_ifa == NULL)
1568                                 fr->fr_ifa = (void *)-1;
1569                 }
1570                 if (fr->fr_grp)
1571                         frsynclist(fr->fr_grp);
1572         }
1573 }
1574
1575
1576 void frsync()
1577 {
1578         register struct ifnet *ifp;
1579
1580 # if !SOLARIS
1581 #  if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \
1582      (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000))
1583 #   if (NetBSD >= 199905) || defined(__OpenBSD__)
1584         for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
1585 #   else
1586         for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
1587 #   endif
1588 #  else
1589         for (ifp = ifnet; ifp; ifp = ifp->if_next)
1590 #  endif
1591         {
1592                 ip_natsync(ifp);
1593                 ip_statesync(ifp);
1594         }
1595 # endif
1596
1597         WRITE_ENTER(&ipf_mutex);
1598         frsynclist(ipacct[0][fr_active]);
1599         frsynclist(ipacct[1][fr_active]);
1600         frsynclist(ipfilter[0][fr_active]);
1601         frsynclist(ipfilter[1][fr_active]);
1602         RWLOCK_EXIT(&ipf_mutex);
1603 }
1604
1605 #else
1606
1607
1608 /*
1609  * return the first IP Address associated with an interface
1610  */
1611 int fr_ifpaddr(ifptr, inp)
1612 void *ifptr;
1613 struct in_addr *inp;
1614 {
1615         return 0;
1616 }
1617 #endif