📄 gencode.c
字号:
/* * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic const char rcsid[] = "@(#) $Header: gencode.c,v 1.94 98/07/12 13:06:49 leres Exp $ (LBL)";#endif#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#if __STDC__struct mbuf;struct rtentry;#endif#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <stdlib.h>#include <memory.h>#include <setjmp.h>#if __STDC__#include <stdarg.h>#else#include <varargs.h>#endif#include "pcap-int.h"#include "ethertype.h"#include "gencode.h"#include "ppp.h"#include <pcap-namedb.h>#include "gnuc.h"#ifdef HAVE_OS_PROTO_H#include "os-proto.h"#endif#ifdef ZFLAG#include "if_nprobe.h"#endif#define JMP(c) ((c)|BPF_JMP|BPF_K)/* Locals */static jmp_buf top_ctx;static pcap_t *bpf_pcap;/* XXX */#ifdef PCAP_FDDIPADint pcap_fddipad = PCAP_FDDIPAD;#elseint pcap_fddipad;#endif/* VARARGS */__dead void#if __STDC__bpf_error(const char *fmt, ...)#elsebpf_error(fmt, va_alist) const char *fmt; va_dcl#endif{ va_list ap;#if __STDC__ va_start(ap, fmt);#else va_start(ap);#endif if (bpf_pcap != NULL) (void)vsprintf(pcap_geterr(bpf_pcap), fmt, ap); va_end(ap); longjmp(top_ctx, 1); /* NOTREACHED */}static void init_linktype(int);static int alloc_reg(void);static void free_reg(int);static struct block *root;/* * We divy out chunks of memory rather than call malloc each time so * we don't have to worry about leaking memory. It's probably * not a big deal if all this memory was wasted but it this ever * goes into a library that would probably not be a good idea. */#define NCHUNKS 16#define CHUNK0SIZE 1024struct chunk { u_int n_left; void *m;};static struct chunk chunks[NCHUNKS];static int cur_chunk;static void *newchunk(u_int);static void freechunks(void);static inline struct block *new_block(int);static inline struct slist *new_stmt(int);static struct block *gen_retblk(int);static inline void syntax(void);static void backpatch(struct block *, struct block *);static void merge(struct block *, struct block *);static struct block *gen_cmp(u_int, u_int, bpf_int32);static struct block *gen_mcmp(u_int, u_int, bpf_int32, bpf_u_int32);static struct block *gen_bcmp(u_int, u_int, const u_char *);static struct block *gen_uncond(int);static inline struct block *gen_true(void);static inline struct block *gen_false(void);static struct block *gen_linktype(int);static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);static struct block *gen_ehostop(const u_char *, int);static struct block *gen_fhostop(const u_char *, int);static struct block *gen_dnhostop(bpf_u_int32, int, u_int);static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int);static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int);static struct block *gen_ipfrag(void);static struct block *gen_portatom(int, bpf_int32);struct block *gen_portop(int, int, int);static struct block *gen_port(int, int, int);static int lookup_proto(const char *, int);static struct block *gen_proto(int, int, int);static struct slist *xfer_to_x(struct arth *);static struct slist *xfer_to_a(struct arth *);static struct block *gen_len(int, int);static void *newchunk(n) u_int n;{ struct chunk *cp; int k, size; /* XXX Round up to nearest long. */ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); cp = &chunks[cur_chunk]; if (n > cp->n_left) { ++cp, k = ++cur_chunk; if (k >= NCHUNKS) bpf_error("out of memory"); size = CHUNK0SIZE << k; cp->m = (void *)malloc(size); memset((char *)cp->m, 0, size); cp->n_left = size; if (n > size) bpf_error("out of memory"); } cp->n_left -= n; return (void *)((char *)cp->m + cp->n_left);}static voidfreechunks(){ int i; cur_chunk = 0; for (i = 0; i < NCHUNKS; ++i) if (chunks[i].m != NULL) { free(chunks[i].m); chunks[i].m = NULL; }}/* * A strdup whose allocations are freed after code generation is over. */char *sdup(s) register const char *s;{ int n = strlen(s) + 1; char *cp = newchunk(n); strcpy(cp, s); return (cp);}static inline struct block *new_block(code) int code;{ struct block *p; p = (struct block *)newchunk(sizeof(*p)); p->s.code = code; p->head = p; return p;}static inline struct slist *new_stmt(code) int code;{ struct slist *p; p = (struct slist *)newchunk(sizeof(*p)); p->s.code = code; return p;}static struct block *gen_retblk(v) int v;{ struct block *b = new_block(BPF_RET|BPF_K); b->s.k = v; return b;}static inline voidsyntax(){ bpf_error("syntax error in filter expression");}static bpf_u_int32 netmask;static int snaplen;intpcap_compile(pcap_t *p, struct bpf_program *program, char *buf, int optimize, bpf_u_int32 mask){ extern int n_errors; int len; n_errors = 0; root = NULL; bpf_pcap = p; if (setjmp(top_ctx)) { freechunks(); return (-1); } netmask = mask; snaplen = pcap_snapshot(p); lex_init(buf ? buf : ""); init_linktype(pcap_datalink(p)); (void)pcap_parse(); if (n_errors) syntax(); if (root == NULL) root = gen_retblk(snaplen); if (optimize) { bpf_optimize(&root); if (root == NULL || (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) bpf_error("expression rejects all packets"); } program->bf_insns = icode_to_fcode(root, &len); program->bf_len = len; freechunks(); return (0);}/* * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates * which of the jt and jf fields has been resolved and which is a pointer * back to another unresolved block (or nil). At least one of the fields * in each block is already resolved. */static voidbackpatch(list, target) struct block *list, *target;{ struct block *next; while (list) { if (!list->sense) { next = JT(list); JT(list) = target; } else { next = JF(list); JF(list) = target; } list = next; }}/* * Merge the lists in b0 and b1, using the 'sense' field to indicate * which of jt and jf is the link. */static voidmerge(b0, b1) struct block *b0, *b1;{ register struct block **p = &b0; /* Find end of list. */ while (*p) p = !((*p)->sense) ? &JT(*p) : &JF(*p); /* Concatenate the lists. */ *p = b1;}voidfinish_parse(p) struct block *p;{ backpatch(p, gen_retblk(snaplen)); p->sense = !p->sense; backpatch(p, gen_retblk(0)); root = p->head;}voidgen_and(b0, b1) struct block *b0, *b1;{ backpatch(b0, b1->head); b0->sense = !b0->sense; b1->sense = !b1->sense; merge(b1, b0); b1->sense = !b1->sense; b1->head = b0->head;}voidgen_or(b0, b1) struct block *b0, *b1;{ b0->sense = !b0->sense; backpatch(b0, b1->head); b0->sense = !b0->sense; merge(b1, b0); b1->head = b0->head;}voidgen_not(b) struct block *b;{ b->sense = !b->sense;}static struct block *gen_cmp(offset, size, v) u_int offset, size; bpf_int32 v;{ struct slist *s; struct block *b; s = new_stmt(BPF_LD|BPF_ABS|size); s->s.k = offset; b = new_block(JMP(BPF_JEQ)); b->stmts = s; b->s.k = v; return b;}static struct block *gen_mcmp(offset, size, v, mask) u_int offset, size; bpf_int32 v; bpf_u_int32 mask;{ struct block *b = gen_cmp(offset, size, v); struct slist *s; if (mask != 0xffffffff) { s = new_stmt(BPF_ALU|BPF_AND|BPF_K); s->s.k = mask; b->stmts->next = s; } return b;}static struct block *gen_bcmp(offset, size, v) register u_int offset, size; register const u_char *v;{ register struct block *b, *tmp; b = NULL; while (size >= 4) { register const u_char *p = &v[size - 4]; bpf_int32 w = ((bpf_int32)p[0] << 24) | ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; tmp = gen_cmp(offset + size - 4, BPF_W, w); if (b != NULL) gen_and(b, tmp); b = tmp; size -= 4; } while (size >= 2) { register const u_char *p = &v[size - 2]; bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; tmp = gen_cmp(offset + size - 2, BPF_H, w); if (b != NULL) gen_and(b, tmp); b = tmp; size -= 2; } if (size > 0) { tmp = gen_cmp(offset, BPF_B, (bpf_int32)v[0]); if (b != NULL) gen_and(b, tmp); b = tmp; } return b;}/* * Various code constructs need to know the layout of the data link * layer. These variables give the necessary offsets. off_linktype * is set to -1 for no encapsulation, in which case, IP is assumed. */static u_int off_linktype;static u_int off_nl;static int linktype;static voidinit_linktype(type) int type;{ linktype = type; switch (type) {#ifdef ZFLAG case DLT_NPROBE:#endif case DLT_EN10MB: off_linktype = 12; off_nl = 14; return; case DLT_SLIP: /* * SLIP doesn't have a link level type. The 16 byte * header is hacked into our SLIP driver. */ off_linktype = -1; off_nl = 16; return; case DLT_SLIP_BSDOS: /* XXX this may be the same as the DLT_PPP_BSDOS case */ off_linktype = -1; /* XXX end */ off_nl = 24; return; case DLT_NULL: off_linktype = 0; off_nl = 4; return; case DLT_PPP: off_linktype = 2; off_nl = 4; return; case DLT_PPP_BSDOS: off_linktype = 5; off_nl = 24; return; case DLT_FDDI: /* * FDDI doesn't really have a link-level type field. * We assume that SSAP = SNAP is being used and pick * out the encapsulated Ethernet type. */ off_linktype = 19;#ifdef PCAP_FDDIPAD off_linktype += pcap_fddipad;#endif off_nl = 21;#ifdef PCAP_FDDIPAD off_nl += pcap_fddipad;#endif return; case DLT_IEEE802: off_linktype = 20; off_nl = 22; return; case DLT_ATM_RFC1483: /* * assume routed, non-ISO PDUs * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) */ off_linktype = 6; off_nl = 8; return; case DLT_RAW: case DLT_RAW_HIGH: off_linktype = -1; off_nl = 0; return; case DLT_ATM_CLIP: off_linktype = 6; off_nl = 8; return; } bpf_error("unknown data link type %d", linktype); /* NOTREACHED */}static struct block *gen_uncond(rsense) int rsense;{ struct block *b; struct slist *s; s = new_stmt(BPF_LD|BPF_IMM); s->s.k = !rsense; b = new_block(JMP(BPF_JEQ)); b->stmts = s; return b;}static inline struct block *gen_true(){ return gen_uncond(1);}static inline struct block *gen_false(){ return gen_uncond(0);}static struct block *gen_linktype(proto) register int proto;{ struct block *b0, *b1; /* If we're not using encapsulation and checking for IP, we're done */ if (off_linktype == -1 && proto == ETHERTYPE_IP) return gen_true(); switch (linktype) { case DLT_SLIP: return gen_false(); case DLT_PPP: if (proto == ETHERTYPE_IP) proto = PPP_IP; /* XXX was 0x21 */ break; case DLT_PPP_BSDOS: switch (proto) { case ETHERTYPE_IP: b0 = gen_cmp(off_linktype, BPF_H, PPP_IP); b1 = gen_cmp(off_linktype, BPF_H, PPP_VJC); gen_or(b0, b1); b0 = gen_cmp(off_linktype, BPF_H, PPP_VJNC); gen_or(b1, b0); return b0; case ETHERTYPE_DN: proto = PPP_DECNET; break; case ETHERTYPE_ATALK: proto = PPP_APPLE; break; case ETHERTYPE_NS: proto = PPP_NS; break; } break; case DLT_NULL: /* XXX */ if (proto == ETHERTYPE_IP) return (gen_cmp(0, BPF_W, (bpf_int32)htonl(AF_INET))); else return gen_false(); } return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto);}static struct block *gen_hostop(addr, mask, dir, proto, src_off, dst_off) bpf_u_int32 addr; bpf_u_int32 mask; int dir, proto; u_int src_off, dst_off;{ struct block *b0, *b1; u_int offset; switch (dir) { case Q_SRC: offset = src_off; break; case Q_DST: offset = dst_off; break; case Q_AND:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -