📄 gencode.c
字号:
/*#define CHASE_CHAIN*//* * 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[] _U_ = "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.43 2006/09/13 07:36:19 guy Exp $ (LBL)";#endif#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef WIN32#include <pcap-stdinc.h>#else /* WIN32 */#include <sys/types.h>#include <sys/socket.h>#endif /* WIN32 *//* * XXX - why was this included even on UNIX? */#ifdef __MINGW32__#include "IP6_misc.h"#endif#ifndef WIN32#ifdef __NetBSD__#include <sys/param.h>#endif#include <netinet/in.h>#endif /* WIN32 */#include <stdlib.h>#include <string.h>#include <memory.h>#include <setjmp.h>#include <stdarg.h>#ifdef MSDOS#include "pcap-dos.h"#endif#include "pcap-int.h"#include "ethertype.h"#include "nlpid.h"#include "llc.h"#include "gencode.h"#include "atmuni31.h"#include "sunatmpos.h"#include "ppp.h"#include "sll.h"#include "arcnet.h"#include "pf.h"#ifndef offsetof#define offsetof(s, e) ((size_t)&((s *)0)->e)#endif#ifdef INET6#ifndef WIN32#include <netdb.h> /* for "struct addrinfo" */#endif /* WIN32 */#endif /*INET6*/#include <pcap-namedb.h>#define ETHERMTU 1500#ifndef IPPROTO_SCTP#define IPPROTO_SCTP 132#endif#ifdef HAVE_OS_PROTO_H#include "os-proto.h"#endif#define JMP(c) ((c)|BPF_JMP|BPF_K)/* Locals */static jmp_buf top_ctx;static pcap_t *bpf_pcap;/* Hack for updating VLAN, MPLS, and PPPoE offsets. */static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;/* XXX */#ifdef PCAP_FDDIPADstatic int pcap_fddipad;#endif/* VARARGS */voidbpf_error(const char *fmt, ...){ va_list ap; va_start(ap, fmt); if (bpf_pcap != NULL) (void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE, fmt, ap); va_end(ap); longjmp(top_ctx, 1); /* NOTREACHED */}static void init_linktype(pcap_t *);static int alloc_reg(void);static void free_reg(int);static struct block *root;/* * Value passed to gen_load_a() to indicate what the offset argument * is relative to. */enum e_offrel { OR_PACKET, /* relative to the beginning of the packet */ OR_LINK, /* relative to the link-layer header */ OR_NET, /* relative to the network-layer header */ OR_NET_NOSNAP, /* relative to the network-layer header, with no SNAP header at the link layer */ OR_TRAN_IPV4, /* relative to the transport-layer header, with IPv4 network layer */ OR_TRAN_IPV6 /* relative to the transport-layer header, with IPv6 network layer */};/* * 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 if this ever * goes into a library that would probably not be a good idea. * * XXX - this *is* in a library.... */#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(enum e_offrel, u_int, u_int, bpf_int32);static struct block *gen_cmp_gt(enum e_offrel, u_int, u_int, bpf_int32);static struct block *gen_cmp_ge(enum e_offrel, u_int, u_int, bpf_int32);static struct block *gen_cmp_lt(enum e_offrel, u_int, u_int, bpf_int32);static struct block *gen_cmp_le(enum e_offrel, u_int, u_int, bpf_int32);static struct block *gen_mcmp(enum e_offrel, u_int, u_int, bpf_int32, bpf_u_int32);static struct block *gen_bcmp(enum e_offrel, u_int, u_int, const u_char *);static struct block *gen_ncmp(enum e_offrel, bpf_u_int32, bpf_u_int32, bpf_u_int32, bpf_u_int32, int, bpf_int32);static struct slist *gen_load_llrel(u_int, u_int);static struct slist *gen_load_a(enum e_offrel, u_int, u_int);static struct slist *gen_loadx_iphdrlen(void);static struct block *gen_uncond(int);static inline struct block *gen_true(void);static inline struct block *gen_false(void);static struct block *gen_ether_linktype(int);static struct block *gen_linux_sll_linktype(int);static void insert_radiotap_load_llprefixlen(struct block *);static void insert_load_llprefixlen(struct block *);static struct slist *gen_llprefixlen(void);static struct block *gen_linktype(int);static struct block *gen_snap(bpf_u_int32, bpf_u_int32, u_int);static struct block *gen_llc_linktype(int);static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int);#ifdef INET6static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int);#endifstatic struct block *gen_ahostop(const u_char *, int);static struct block *gen_ehostop(const u_char *, int);static struct block *gen_fhostop(const u_char *, int);static struct block *gen_thostop(const u_char *, int);static struct block *gen_wlanhostop(const u_char *, int);static struct block *gen_ipfchostop(const u_char *, int);static struct block *gen_dnhostop(bpf_u_int32, int);static struct block *gen_mpls_linktype(int);static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int, int);#ifdef INET6static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int, int);#endif#ifndef INET6static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int);#endifstatic struct block *gen_ipfrag(void);static struct block *gen_portatom(int, bpf_int32);static struct block *gen_portrangeatom(int, bpf_int32, bpf_int32);#ifdef INET6static struct block *gen_portatom6(int, bpf_int32);static struct block *gen_portrangeatom6(int, bpf_int32, bpf_int32);#endifstruct block *gen_portop(int, int, int);static struct block *gen_port(int, int, int);struct block *gen_portrangeop(int, int, int, int);static struct block *gen_portrange(int, int, int, int);#ifdef INET6struct block *gen_portop6(int, int, int);static struct block *gen_port6(int, int, int);struct block *gen_portrangeop6(int, int, int, int);static struct block *gen_portrange6(int, int, int, int);#endifstatic int lookup_proto(const char *, int);static struct block *gen_protochain(int, int, 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_mac_multicast(int);static struct block *gen_len(int, int);static struct block *gen_msg_abbrev(int type);static void *newchunk(n) u_int n;{ struct chunk *cp; int k; size_t size;#ifndef __NetBSD__ /* XXX Round up to nearest long. */ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);#else /* XXX Round up to structure boundary. */ n = ALIGN(n);#endif 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); if (cp->m == NULL) bpf_error("out of memory"); 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); strlcpy(cp, s, n); 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;int no_optimize;intpcap_compile(pcap_t *p, struct bpf_program *program, char *buf, int optimize, bpf_u_int32 mask){ extern int n_errors; int len;#ifdef HAVE_REMOTE /* Check if: - We are on an remote capture - we do not want to capture RPCAP traffic If so, we have to save the current filter, because we have to add some piece of stuff later */ if ( (p->rmt_clientside) && (p->rmt_flags & PCAP_OPENFLAG_NOCAPTURE_RPCAP) ) { int bufferlen; if (p->currentfilter) free (p->currentfilter); if (buf) bufferlen= strlen(buf) + 1; else bufferlen= 1; p->currentfilter= (char *) malloc( sizeof(char) * bufferlen); strncpy(p->currentfilter, buf, bufferlen); p->currentfilter[bufferlen - 1]= 0; }#endif /* HAVE_REMOTE */ no_optimize = 0; n_errors = 0; root = NULL; bpf_pcap = p; if (setjmp(top_ctx)) { lex_cleanup(); freechunks(); return (-1); } netmask = mask; snaplen = pcap_snapshot(p); if (snaplen == 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snaplen of 0 rejects all packets"); return -1; } lex_init(buf ? buf : ""); init_linktype(p); (void)pcap_parse(); if (n_errors) syntax(); if (root == NULL) root = gen_retblk(snaplen); if (optimize && !no_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; lex_cleanup(); freechunks(); return (0);}/* * entry point for using the compiler with no pcap open * pass in all the stuff that is needed explicitly instead. */intpcap_compile_nopcap(int snaplen_arg, int linktype_arg, struct bpf_program *program, char *buf, int optimize, bpf_u_int32 mask){ pcap_t *p; int ret; p = pcap_open_dead(linktype_arg, snaplen_arg); if (p == NULL) return (-1); ret = pcap_compile(p, program, buf, optimize, mask); pcap_close(p); return (ret);}/* * Clean up a "struct bpf_program" by freeing all the memory allocated * in it. */voidpcap_freecode(struct bpf_program *program){ program->bf_len = 0; if (program->bf_insns != NULL) { free((char *)program->bf_insns); program->bf_insns = NULL; }}/* * 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; /* * Insert before the statements of the first (root) block any * statements needed to load the lengths of any variable-length * headers into registers. * * XXX - a fancier strategy would be to insert those before the * statements of all blocks that use those lengths and that * have no predecessors that use them, so that we only compute * the lengths if we need them. There might be even better * approaches than that. However, as we're currently only * handling variable-length radiotap headers, and as all * filtering expressions other than raw link[M:N] tests * require the length of that header, doing more for that * header length isn't really worth the effort.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -