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