151441Smccanne /*
2*63211Sbostic * Copyright (c) 1990, 1991, 1993
3*63211Sbostic * The Regents of the University of California. All rights reserved.
447585Smccanne *
549284Sbostic * This code is derived from the Stanford/CMU enet packet filter,
649284Sbostic * (net/enet.c) distributed as part of 4.3BSD, and code contributed
751441Smccanne * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
851428Smccanne * Berkeley Laboratory.
949284Sbostic *
1051441Smccanne * %sccs.include.redist.c%
1149284Sbostic *
12*63211Sbostic * @(#)bpf_filter.c 8.1 (Berkeley) 06/10/93
1349284Sbostic *
1449284Sbostic * static char rcsid[] =
1551428Smccanne * "$Header: bpf_filter.c,v 1.16 91/10/27 21:22:35 mccanne Exp $";
1647585Smccanne */
1747585Smccanne
1848931Smccanne #include <sys/param.h>
1947585Smccanne #include <sys/types.h>
2047585Smccanne #include <sys/time.h>
2147585Smccanne
2249724Smccanne #ifdef sun
2349724Smccanne #include <netinet/in.h>
2449724Smccanne #endif
2549724Smccanne
2651428Smccanne #if defined(sparc) || defined(mips) || defined(ibm032)
2753950Smccanne #define BPF_ALIGN
2847585Smccanne #endif
2947585Smccanne
3053950Smccanne #ifndef BPF_ALIGN
3153950Smccanne #define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
3247585Smccanne #define EXTRACT_LONG(p) (ntohl(*(u_long *)p))
3347585Smccanne #else
3447585Smccanne #define EXTRACT_SHORT(p)\
3547585Smccanne ((u_short)\
3653950Smccanne ((u_short)*((u_char *)p+0)<<8|\
3753950Smccanne (u_short)*((u_char *)p+1)<<0))
3847585Smccanne #define EXTRACT_LONG(p)\
3953950Smccanne ((u_long)*((u_char *)p+0)<<24|\
4053950Smccanne (u_long)*((u_char *)p+1)<<16|\
4153950Smccanne (u_long)*((u_char *)p+2)<<8|\
4253950Smccanne (u_long)*((u_char *)p+3)<<0)
4347585Smccanne #endif
4447585Smccanne
4549200Smccanne #ifdef KERNEL
4649200Smccanne #include <sys/mbuf.h>
4749200Smccanne #define MINDEX(m, k) \
4849200Smccanne { \
4949200Smccanne register int len = m->m_len; \
5049200Smccanne \
5149200Smccanne while (k >= len) { \
5249200Smccanne k -= len; \
5349200Smccanne m = m->m_next; \
5449200Smccanne if (m == 0) \
5549200Smccanne return 0; \
5649200Smccanne len = m->m_len; \
5749200Smccanne } \
5849200Smccanne }
5949724Smccanne
6049724Smccanne static int
m_xword(m,k,err)6149724Smccanne m_xword(m, k, err)
6249724Smccanne register struct mbuf *m;
6349724Smccanne register int k, *err;
6449724Smccanne {
6549724Smccanne register int len;
6649724Smccanne register u_char *cp, *np;
6749724Smccanne register struct mbuf *m0;
6849724Smccanne
6949724Smccanne len = m->m_len;
7049724Smccanne while (k >= len) {
7149724Smccanne k -= len;
7249724Smccanne m = m->m_next;
7349724Smccanne if (m == 0)
7449724Smccanne goto bad;
7549724Smccanne len = m->m_len;
7649724Smccanne }
7749724Smccanne cp = mtod(m, u_char *) + k;
7849724Smccanne if (len - k >= 4) {
7949724Smccanne *err = 0;
8049724Smccanne return EXTRACT_LONG(cp);
8149724Smccanne }
8249724Smccanne m0 = m->m_next;
8349724Smccanne if (m0 == 0 || m0->m_len + len - k < 4)
8449724Smccanne goto bad;
8549724Smccanne *err = 0;
8649724Smccanne np = mtod(m0, u_char *);
8749724Smccanne switch (len - k) {
8849724Smccanne
8949724Smccanne case 1:
9049724Smccanne return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
9149724Smccanne
9249724Smccanne case 2:
9349724Smccanne return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) |
9449724Smccanne np[1];
9549724Smccanne
9649724Smccanne default:
9749724Smccanne return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) |
9849724Smccanne np[0];
9949724Smccanne }
10049724Smccanne bad:
10149724Smccanne *err = 1;
10249724Smccanne return 0;
10349724Smccanne }
10449724Smccanne
10549724Smccanne static int
m_xhalf(m,k,err)10649724Smccanne m_xhalf(m, k, err)
10749724Smccanne register struct mbuf *m;
10849724Smccanne register int k, *err;
10949724Smccanne {
11049724Smccanne register int len;
11151428Smccanne register u_char *cp;
11249724Smccanne register struct mbuf *m0;
11349724Smccanne
11449724Smccanne len = m->m_len;
11549724Smccanne while (k >= len) {
11649724Smccanne k -= len;
11749724Smccanne m = m->m_next;
11849724Smccanne if (m == 0)
11949724Smccanne goto bad;
12049724Smccanne len = m->m_len;
12149724Smccanne }
12249724Smccanne cp = mtod(m, u_char *) + k;
12349724Smccanne if (len - k >= 2) {
12449724Smccanne *err = 0;
12549724Smccanne return EXTRACT_SHORT(cp);
12649724Smccanne }
12749724Smccanne m0 = m->m_next;
12849724Smccanne if (m0 == 0)
12949724Smccanne goto bad;
13049724Smccanne *err = 0;
13149724Smccanne return (cp[k] << 8) | mtod(m0, u_char *)[0];
13249724Smccanne bad:
13349724Smccanne *err = 1;
13449724Smccanne return 0;
13549724Smccanne }
13649200Smccanne #endif
13749200Smccanne
13861339Sbostic #include <net/bpf.h>
13947585Smccanne /*
14048969Smccanne * Execute the filter program starting at pc on the packet p
14148969Smccanne * wirelen is the length of the original packet
14248969Smccanne * buflen is the amount of data present
14347585Smccanne */
14447585Smccanne u_int
bpf_filter(pc,p,wirelen,buflen)14547585Smccanne bpf_filter(pc, p, wirelen, buflen)
14647585Smccanne register struct bpf_insn *pc;
14747585Smccanne register u_char *p;
14847585Smccanne u_int wirelen;
14948969Smccanne register u_int buflen;
15047585Smccanne {
15153950Smccanne register u_long A, X;
15248969Smccanne register int k;
15347585Smccanne long mem[BPF_MEMWORDS];
15447585Smccanne
15547585Smccanne if (pc == 0)
15647585Smccanne /*
15747585Smccanne * No filter means accept all.
15847585Smccanne */
15948969Smccanne return (u_int)-1;
16047585Smccanne #ifdef lint
16147585Smccanne A = 0;
16247585Smccanne X = 0;
16347585Smccanne #endif
16448969Smccanne --pc;
16547585Smccanne while (1) {
16648969Smccanne ++pc;
16747585Smccanne switch (pc->code) {
16847585Smccanne
16947585Smccanne default:
17047585Smccanne #ifdef KERNEL
17147585Smccanne return 0;
17247585Smccanne #else
17347585Smccanne abort();
17447585Smccanne #endif
17548969Smccanne case BPF_RET|BPF_K:
17647585Smccanne return (u_int)pc->k;
17747585Smccanne
17848969Smccanne case BPF_RET|BPF_A:
17947585Smccanne return (u_int)A;
18047585Smccanne
18148969Smccanne case BPF_LD|BPF_W|BPF_ABS:
18248969Smccanne k = pc->k;
18349200Smccanne if (k + sizeof(long) > buflen) {
18449200Smccanne #ifdef KERNEL
18549724Smccanne int merr;
18649200Smccanne
18749200Smccanne if (buflen != 0)
18849200Smccanne return 0;
18949724Smccanne A = m_xword((struct mbuf *)p, k, &merr);
19049724Smccanne if (merr != 0)
19149724Smccanne return 0;
19249724Smccanne continue;
19349200Smccanne #else
19447585Smccanne return 0;
19549200Smccanne #endif
19649200Smccanne }
19753950Smccanne #ifdef BPF_ALIGN
19848969Smccanne if (((int)(p + k) & 3) != 0)
19948969Smccanne A = EXTRACT_LONG(&p[k]);
20048969Smccanne else
20148969Smccanne #endif
20253950Smccanne A = ntohl(*(long *)(p + k));
20349724Smccanne continue;
20447585Smccanne
20548969Smccanne case BPF_LD|BPF_H|BPF_ABS:
20648969Smccanne k = pc->k;
20749200Smccanne if (k + sizeof(short) > buflen) {
20849200Smccanne #ifdef KERNEL
20949724Smccanne int merr;
21049200Smccanne
21149200Smccanne if (buflen != 0)
21249200Smccanne return 0;
21349724Smccanne A = m_xhalf((struct mbuf *)p, k, &merr);
21449724Smccanne continue;
21549200Smccanne #else
21647585Smccanne return 0;
21749200Smccanne #endif
21849200Smccanne }
21948969Smccanne A = EXTRACT_SHORT(&p[k]);
22049724Smccanne continue;
22147585Smccanne
22248969Smccanne case BPF_LD|BPF_B|BPF_ABS:
22348969Smccanne k = pc->k;
22449200Smccanne if (k >= buflen) {
22549200Smccanne #ifdef KERNEL
22649200Smccanne register struct mbuf *m;
22749200Smccanne
22849200Smccanne if (buflen != 0)
22949200Smccanne return 0;
23049200Smccanne m = (struct mbuf *)p;
23149200Smccanne MINDEX(m, k);
23249724Smccanne A = mtod(m, u_char *)[k];
23349724Smccanne continue;
23449200Smccanne #else
23547585Smccanne return 0;
23649200Smccanne #endif
23749200Smccanne }
23848969Smccanne A = p[k];
23949724Smccanne continue;
24047585Smccanne
24148969Smccanne case BPF_LD|BPF_W|BPF_LEN:
24247585Smccanne A = wirelen;
24349724Smccanne continue;
24447585Smccanne
24548969Smccanne case BPF_LDX|BPF_W|BPF_LEN:
24648969Smccanne X = wirelen;
24749724Smccanne continue;
24848969Smccanne
24948969Smccanne case BPF_LD|BPF_W|BPF_IND:
25048969Smccanne k = X + pc->k;
25149200Smccanne if (k + sizeof(long) > buflen) {
25249200Smccanne #ifdef KERNEL
25349724Smccanne int merr;
25449200Smccanne
25549200Smccanne if (buflen != 0)
25649200Smccanne return 0;
25749724Smccanne A = m_xword((struct mbuf *)p, k, &merr);
25849724Smccanne if (merr != 0)
25949724Smccanne return 0;
26049724Smccanne continue;
26149200Smccanne #else
26247585Smccanne return 0;
26349200Smccanne #endif
26449200Smccanne }
26553950Smccanne #ifdef BPF_ALIGN
26648969Smccanne if (((int)(p + k) & 3) != 0)
26748969Smccanne A = EXTRACT_LONG(&p[k]);
26848969Smccanne else
26948969Smccanne #endif
27053950Smccanne A = ntohl(*(long *)(p + k));
27149724Smccanne continue;
27247585Smccanne
27348969Smccanne case BPF_LD|BPF_H|BPF_IND:
27448969Smccanne k = X + pc->k;
27549200Smccanne if (k + sizeof(short) > buflen) {
27649200Smccanne #ifdef KERNEL
27749724Smccanne int merr;
27849200Smccanne
27949200Smccanne if (buflen != 0)
28049200Smccanne return 0;
28149724Smccanne A = m_xhalf((struct mbuf *)p, k, &merr);
28249724Smccanne if (merr != 0)
28349724Smccanne return 0;
28449724Smccanne continue;
28549200Smccanne #else
28647585Smccanne return 0;
28749200Smccanne #endif
28849200Smccanne }
28948969Smccanne A = EXTRACT_SHORT(&p[k]);
29049724Smccanne continue;
29147585Smccanne
29248969Smccanne case BPF_LD|BPF_B|BPF_IND:
29348969Smccanne k = X + pc->k;
29449200Smccanne if (k >= buflen) {
29549200Smccanne #ifdef KERNEL
29649200Smccanne register struct mbuf *m;
29749200Smccanne
29849200Smccanne if (buflen != 0)
29949200Smccanne return 0;
30049200Smccanne m = (struct mbuf *)p;
30149200Smccanne MINDEX(m, k);
30249200Smccanne A = mtod(m, char *)[k];
30349724Smccanne continue;
30449200Smccanne #else
30547585Smccanne return 0;
30649200Smccanne #endif
30749200Smccanne }
30848969Smccanne A = p[k];
30949724Smccanne continue;
31047585Smccanne
31149200Smccanne case BPF_LDX|BPF_MSH|BPF_B:
31249200Smccanne k = pc->k;
31349200Smccanne if (k >= buflen) {
31449200Smccanne #ifdef KERNEL
31549200Smccanne register struct mbuf *m;
31649200Smccanne
31749200Smccanne if (buflen != 0)
31849200Smccanne return 0;
31949200Smccanne m = (struct mbuf *)p;
32049200Smccanne MINDEX(m, k);
32149200Smccanne X = (mtod(m, char *)[k] & 0xf) << 2;
32249724Smccanne continue;
32349200Smccanne #else
32449200Smccanne return 0;
32549200Smccanne #endif
32649200Smccanne }
32749200Smccanne X = (p[pc->k] & 0xf) << 2;
32849724Smccanne continue;
32949200Smccanne
33048969Smccanne case BPF_LD|BPF_IMM:
33147585Smccanne A = pc->k;
33249724Smccanne continue;
33347585Smccanne
33448969Smccanne case BPF_LDX|BPF_IMM:
33547585Smccanne X = pc->k;
33649724Smccanne continue;
33747585Smccanne
33848969Smccanne case BPF_LD|BPF_MEM:
33948969Smccanne A = mem[pc->k];
34049724Smccanne continue;
34148969Smccanne
34248969Smccanne case BPF_LDX|BPF_MEM:
34348969Smccanne X = mem[pc->k];
34449724Smccanne continue;
34547585Smccanne
34648969Smccanne case BPF_ST:
34747585Smccanne mem[pc->k] = A;
34849724Smccanne continue;
34947585Smccanne
35048969Smccanne case BPF_STX:
35147585Smccanne mem[pc->k] = X;
35249724Smccanne continue;
35347585Smccanne
35448969Smccanne case BPF_JMP|BPF_JA:
35548969Smccanne pc += pc->k;
35649724Smccanne continue;
35747585Smccanne
35848969Smccanne case BPF_JMP|BPF_JGT|BPF_K:
35948969Smccanne pc += (A > pc->k) ? pc->jt : pc->jf;
36049724Smccanne continue;
36147585Smccanne
36248969Smccanne case BPF_JMP|BPF_JGE|BPF_K:
36348969Smccanne pc += (A >= pc->k) ? pc->jt : pc->jf;
36449724Smccanne continue;
36547585Smccanne
36648969Smccanne case BPF_JMP|BPF_JEQ|BPF_K:
36748969Smccanne pc += (A == pc->k) ? pc->jt : pc->jf;
36849724Smccanne continue;
36947585Smccanne
37048969Smccanne case BPF_JMP|BPF_JSET|BPF_K:
37148969Smccanne pc += (A & pc->k) ? pc->jt : pc->jf;
37249724Smccanne continue;
37347585Smccanne
37448969Smccanne case BPF_JMP|BPF_JGT|BPF_X:
37548969Smccanne pc += (A > X) ? pc->jt : pc->jf;
37649724Smccanne continue;
37748969Smccanne
37848969Smccanne case BPF_JMP|BPF_JGE|BPF_X:
37948969Smccanne pc += (A >= X) ? pc->jt : pc->jf;
38049724Smccanne continue;
38148969Smccanne
38248969Smccanne case BPF_JMP|BPF_JEQ|BPF_X:
38348969Smccanne pc += (A == X) ? pc->jt : pc->jf;
38449724Smccanne continue;
38548969Smccanne
38648969Smccanne case BPF_JMP|BPF_JSET|BPF_X:
38748969Smccanne pc += (A & X) ? pc->jt : pc->jf;
38849724Smccanne continue;
38948969Smccanne
39048969Smccanne case BPF_ALU|BPF_ADD|BPF_X:
39147585Smccanne A += X;
39249724Smccanne continue;
39347585Smccanne
39448969Smccanne case BPF_ALU|BPF_SUB|BPF_X:
39547585Smccanne A -= X;
39649724Smccanne continue;
39747585Smccanne
39848969Smccanne case BPF_ALU|BPF_MUL|BPF_X:
39947585Smccanne A *= X;
40049724Smccanne continue;
40147585Smccanne
40248969Smccanne case BPF_ALU|BPF_DIV|BPF_X:
40347585Smccanne if (X == 0)
40447585Smccanne return 0;
40547585Smccanne A /= X;
40649724Smccanne continue;
40747585Smccanne
40848969Smccanne case BPF_ALU|BPF_AND|BPF_X:
40947585Smccanne A &= X;
41049724Smccanne continue;
41147585Smccanne
41248969Smccanne case BPF_ALU|BPF_OR|BPF_X:
41347585Smccanne A |= X;
41449724Smccanne continue;
41547585Smccanne
41648969Smccanne case BPF_ALU|BPF_LSH|BPF_X:
41747585Smccanne A <<= X;
41849724Smccanne continue;
41947585Smccanne
42048969Smccanne case BPF_ALU|BPF_RSH|BPF_X:
42147585Smccanne A >>= X;
42249724Smccanne continue;
42347585Smccanne
42448969Smccanne case BPF_ALU|BPF_ADD|BPF_K:
42547585Smccanne A += pc->k;
42649724Smccanne continue;
42747585Smccanne
42848969Smccanne case BPF_ALU|BPF_SUB|BPF_K:
42947585Smccanne A -= pc->k;
43049724Smccanne continue;
43147585Smccanne
43248969Smccanne case BPF_ALU|BPF_MUL|BPF_K:
43347585Smccanne A *= pc->k;
43449724Smccanne continue;
43547585Smccanne
43648969Smccanne case BPF_ALU|BPF_DIV|BPF_K:
43747585Smccanne A /= pc->k;
43849724Smccanne continue;
43947585Smccanne
44048969Smccanne case BPF_ALU|BPF_AND|BPF_K:
44147585Smccanne A &= pc->k;
44249724Smccanne continue;
44347585Smccanne
44448969Smccanne case BPF_ALU|BPF_OR|BPF_K:
44547585Smccanne A |= pc->k;
44649724Smccanne continue;
44747585Smccanne
44848969Smccanne case BPF_ALU|BPF_LSH|BPF_K:
44947585Smccanne A <<= pc->k;
45049724Smccanne continue;
45147585Smccanne
45248969Smccanne case BPF_ALU|BPF_RSH|BPF_K:
45347585Smccanne A >>= pc->k;
45449724Smccanne continue;
45547585Smccanne
45648969Smccanne case BPF_ALU|BPF_NEG:
45747585Smccanne A = -A;
45849724Smccanne continue;
45948969Smccanne
46048969Smccanne case BPF_MISC|BPF_TAX:
46148969Smccanne X = A;
46249724Smccanne continue;
46348969Smccanne
46448969Smccanne case BPF_MISC|BPF_TXA:
46548969Smccanne A = X;
46649724Smccanne continue;
46747585Smccanne }
46847585Smccanne }
46947585Smccanne }
47047585Smccanne
47147585Smccanne #ifdef KERNEL
47247585Smccanne /*
47347585Smccanne * Return true if the 'fcode' is a valid filter program.
47447585Smccanne * The constraints are that each jump be forward and to a valid
47547585Smccanne * code. The code must terminate with either an accept or reject.
47647585Smccanne * 'valid' is an array for use by the routine (it must be at least
47747585Smccanne * 'len' bytes long).
47847585Smccanne *
47947585Smccanne * The kernel needs to be able to verify an application's filter code.
48047585Smccanne * Otherwise, a bogus program could easily crash the system.
48147585Smccanne */
48247585Smccanne int
bpf_validate(f,len)48348969Smccanne bpf_validate(f, len)
48448969Smccanne struct bpf_insn *f;
48547585Smccanne int len;
48647585Smccanne {
48748969Smccanne register int i;
48848969Smccanne register struct bpf_insn *p;
48947585Smccanne
49048969Smccanne for (i = 0; i < len; ++i) {
49147585Smccanne /*
49247585Smccanne * Check that that jumps are forward, and within
49347585Smccanne * the code block.
49447585Smccanne */
49548969Smccanne p = &f[i];
49648969Smccanne if (BPF_CLASS(p->code) == BPF_JMP) {
49748969Smccanne register int from = i + 1;
49848969Smccanne
49948969Smccanne if (BPF_OP(p->code) == BPF_JA) {
50048969Smccanne if (from + p->k >= len)
50148969Smccanne return 0;
50248969Smccanne }
50348969Smccanne else if (from + p->jt >= len || from + p->jf >= len)
50448969Smccanne return 0;
50548969Smccanne }
50647585Smccanne /*
50747585Smccanne * Check that memory operations use valid addresses.
50847585Smccanne */
50948969Smccanne if ((BPF_CLASS(p->code) == BPF_ST ||
51048969Smccanne (BPF_CLASS(p->code) == BPF_LD &&
51148969Smccanne (p->code & 0xe0) == BPF_MEM)) &&
51248969Smccanne (p->k >= BPF_MEMWORDS || p->k < 0))
51348969Smccanne return 0;
51448969Smccanne /*
51548969Smccanne * Check for constant division by 0.
51648969Smccanne */
51751428Smccanne if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
51851428Smccanne return 0;
51947585Smccanne }
52048969Smccanne return BPF_CLASS(f[len - 1].code) == BPF_RET;
52147585Smccanne }
52247585Smccanne #endif
523