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