📄 gencode.c
字号:
* (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) * * XXX - what about ISO PDUs, e.g. CLNP, ISIS, ESIS, * or PPP with the PPP NLPID (e.g., PPPoA)? The * latter would presumably be treated the way PPPoE * should be, so you can do "pppoe and udp port 2049" * or "pppoa and tcp port 80" and have it check for * PPPo{A,E} and a PPP protocol of IP and.... */ off_linktype = 0; off_nl = 8; /* 802.2+SNAP */ off_nl_nosnap = 3; /* 802.2 */ return; case DLT_SUNATM: /* * Full Frontal ATM; you get AALn PDUs with an ATM * pseudo-header. */ is_atm = 1; off_vpi = SUNATM_VPI_POS; off_vci = SUNATM_VCI_POS; off_proto = PROTO_POS; off_mac = -1; /* LLC-encapsulated, so no MAC-layer header */ off_payload = SUNATM_PKT_BEGIN_POS; off_linktype = off_payload; off_nl = off_payload+8; /* 802.2+SNAP */ off_nl_nosnap = off_payload+3; /* 802.2 */ return; case DLT_RAW: off_linktype = -1; off_nl = 0; off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_LINUX_SLL: /* fake header for Linux cooked socket */ off_linktype = 14; off_nl = 16; off_nl_nosnap = 16; /* no 802.2 LLC */ return; case DLT_LTALK: /* * LocalTalk does have a 1-byte type field in the LLAP header, * but really it just indicates whether there is a "short" or * "long" DDP packet following. */ off_linktype = -1; off_nl = 0; off_nl_nosnap = 0; /* no 802.2 LLC */ return; case DLT_IP_OVER_FC: /* * RFC 2625 IP-over-Fibre-Channel doesn't really have a * link-level type field. We set "off_linktype" to the * offset of the LLC header. * * To check for Ethernet types, we assume that SSAP = SNAP * is being used and pick out the encapsulated Ethernet type. * XXX - should we generate code to check for SNAP? RFC * 2625 says SNAP should be used. */ off_linktype = 16; off_nl = 24; /* IPFC+802.2+SNAP */ off_nl_nosnap = 19; /* IPFC+802.2 */ return; case DLT_FRELAY: /* * XXX - we should set this to handle SNAP-encapsulated * frames (NLPID of 0x80). */ off_linktype = -1; off_nl = 0; off_nl_nosnap = 0; /* no 802.2 LLC */ return; /* * the only BPF-interesting FRF.16 frames are non-control frames; * Frame Relay has a variable length link-layer * so lets start with offset 4 for now and increments later on (FIXME); */ case DLT_MFR: off_linktype = -1; off_nl = 4; off_nl_nosnap = 0; /* XXX - for now -> no 802.2 LLC */ return; case DLT_APPLE_IP_OVER_IEEE1394: off_linktype = 16; off_nl = 18; off_nl_nosnap = 18; /* no 802.2 LLC */ return; case DLT_LINUX_IRDA: /* * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; off_nl = -1; off_nl_nosnap = -1; return; case DLT_DOCSIS: /* * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; off_nl = -1; off_nl_nosnap = -1; return; case DLT_SYMANTEC_FIREWALL: off_linktype = 6; off_nl = 44; /* Ethernet II */ off_nl_nosnap = 44; /* XXX - what does it do with 802.3 packets? */ return; case DLT_PFLOG: off_linktype = 0; /* XXX read this from pf.h? */ off_nl = PFLOG_HDRLEN; off_nl_nosnap = PFLOG_HDRLEN; /* no 802.2 LLC */ return; case DLT_JUNIPER_MFR: case DLT_JUNIPER_MLFR: case DLT_JUNIPER_MLPPP: case DLT_JUNIPER_PPP: case DLT_JUNIPER_CHDLC: case DLT_JUNIPER_FRELAY: off_linktype = 4; off_nl = 4; off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_ATM1: off_linktype = 4; /* in reality variable between 4-8 */ off_nl = 4; off_nl_nosnap = 14; return; case DLT_JUNIPER_ATM2: off_linktype = 8; /* in reality variable between 8-12 */ off_nl = 8; off_nl_nosnap = 18; return; /* frames captured on a Juniper PPPoE service PIC * contain raw ethernet frames */ case DLT_JUNIPER_PPPOE: case DLT_JUNIPER_ETHER: off_linktype = 16; off_nl = 18; /* Ethernet II */ off_nl_nosnap = 21; /* 802.3+802.2 */ return; case DLT_JUNIPER_PPPOE_ATM: off_linktype = 4; off_nl = 6; off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_GGSN: off_linktype = 6; off_nl = 12; off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_ES: off_linktype = 6; off_nl = -1; /* not really a network layer but raw IP adresses */ off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_MONITOR: off_linktype = 12; off_nl = 12; /* raw IP/IP6 header */ off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_JUNIPER_SERVICES: off_linktype = 12; off_nl = -1; /* L3 proto location dep. on cookie type */ off_nl_nosnap = -1; /* no 802.2 LLC */ return; case DLT_MTP2: off_sio = 3; off_opc = 4; off_dpc = 4; off_sls = 7; off_linktype = -1; off_nl = -1; off_nl_nosnap = -1; return;#ifdef DLT_PFSYNC case DLT_PFSYNC: off_linktype = -1; off_nl = 4; off_nl_nosnap = 4; return;#endif case DLT_LINUX_LAPD: /* * Currently, only raw "link[N:M]" filtering is supported. */ off_linktype = -1; off_nl = -1; off_nl_nosnap = -1; return; } bpf_error("unknown data link type %d", linktype); /* NOTREACHED */}/* * Load a value relative to the beginning of the link-layer header. * The link-layer header doesn't necessarily begin at the beginning * of the packet data; there might be a variable-length prefix containing * radio information. */static struct slist *gen_load_llrel(offset, size) u_int offset, size;{ struct slist *s, *s2; s = gen_llprefixlen(); /* * If "s" is non-null, it has code to arrange that the X register * contains the length of the prefix preceding the link-layer * header. * * Otherwise, the length of the prefix preceding the link-layer * header is "off_ll". */ if (s != NULL) { /* * There's a variable-length prefix preceding the * link-layer header. "s" points to a list of statements * that put the length of that prefix into the X register. * do an indirect load, to use the X register as an offset. */ s2 = new_stmt(BPF_LD|BPF_IND|size); s2->s.k = offset; sappend(s, s2); } else { /* * There is no variable-length header preceding the * link-layer header; add in off_ll, which, if there's * a fixed-length header preceding the link-layer header, * is the length of that header. */ s = new_stmt(BPF_LD|BPF_ABS|size); s->s.k = offset + off_ll; } return s;}/* * Load a value relative to the beginning of the specified header. */static struct slist *gen_load_a(offrel, offset, size) enum e_offrel offrel; u_int offset, size;{ struct slist *s, *s2; switch (offrel) { case OR_PACKET: s = new_stmt(BPF_LD|BPF_ABS|size); s->s.k = offset; break; case OR_LINK: s = gen_load_llrel(offset, size); break; case OR_NET: s = gen_load_llrel(off_nl + offset, size); break; case OR_NET_NOSNAP: s = gen_load_llrel(off_nl_nosnap + offset, size); break; case OR_TRAN_IPV4: /* * Load the X register with the length of the IPv4 header * (plus the offset of the link-layer header, if it's * preceded by a variable-length header such as a radio * header), in bytes. */ s = gen_loadx_iphdrlen(); /* * Load the item at {offset of the link-layer header} + * {offset, relative to the start of the link-layer * header, of the IPv4 header} + {length of the IPv4 header} + * {specified offset}. * * (If the link-layer is variable-length, it's included * in the value in the X register, and off_ll is 0.) */ s2 = new_stmt(BPF_LD|BPF_IND|size); s2->s.k = off_ll + off_nl + offset; sappend(s, s2); break; case OR_TRAN_IPV6: s = gen_load_llrel(off_nl + 40 + offset, size); break; default: abort(); return NULL; } return s;}/* * Generate code to load into the X register the sum of the length of * the IPv4 header and any variable-length header preceding the link-layer * header. */static struct slist *gen_loadx_iphdrlen(){ struct slist *s, *s2; s = gen_llprefixlen(); if (s != NULL) { /* * There's a variable-length prefix preceding the * link-layer header. "s" points to a list of statements * that put the length of that prefix into the X register. * The 4*([k]&0xf) addressing mode can't be used, as we * don't have a constant offset, so we have to load the * value in question into the A register and add to it * the value from the X register. */ s2 = new_stmt(BPF_LD|BPF_IND|BPF_B); s2->s.k = off_nl; sappend(s, s2); s2 = new_stmt(BPF_ALU|BPF_AND|BPF_K); s2->s.k = 0xf; sappend(s, s2); s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K); s2->s.k = 2; sappend(s, s2); /* * The A register now contains the length of the * IP header. We need to add to it the length * of the prefix preceding the link-layer * header, which is still in the X register, and * move the result into the X register. */ sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); sappend(s, new_stmt(BPF_MISC|BPF_TAX)); } else { /* * There is no variable-length header preceding the * link-layer header; add in off_ll, which, if there's * a fixed-length header preceding the link-layer header, * is the length of that header. */ s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); s->s.k = off_ll + off_nl; } return s;}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);}/* * Byte-swap a 32-bit number. * ("htonl()" or "ntohl()" won't work - we want to byte-swap even on * big-endian platforms.) */#define SWAPLONG(y) \((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))/* * Generate code to match a particular packet type. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. We use that to determine whether to * match the type/length field or to check the type/length field for * a value <= ETHERMTU to see whether it's a type field and then do * the appropriate test. */static struct block *gen_ether_linktype(proto) register int proto;{ struct block *b0, *b1; switch (proto) { case LLCSAP_ISONS: case LLCSAP_IP: case LLCSAP_NETBEUI: /* * OSI protocols and NetBEUI always use 802.2 encapsulation, * so we check the DSAP and SSAP. * * LLCSAP_IP checks for IP-over-802.2, rather * than IP-over-Ethernet or IP-over-SNAP. * * XXX - should we check both the DSAP and the * SSAP, like this, or should we check just the * DSAP, as we do for other types <= ETHERMTU * (i.e., other SAP values)? */ b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU); gen_not(b0); b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32) ((proto << 8) | proto)); gen_and(b0, b1); return b1; case LLCSAP_IPX: /* * Check for; * * Ethernet_II frames, which are Ethernet * frames with a frame type of ETHERTYPE_IPX; * * Ethernet_802.3 frames, which are 802.3 * frames (i.e., the type/length field is * a length field, <= ETHERMTU, rather than * a type field) with the first two bytes * after the Ethernet/802.3 header being * 0xFFFF; * * Ethernet_802.2 frames, which are 802.3 * frames with an 802.2 LLC header and * with the IPX LSAP as the DSAP in the LLC * header; * * Ethernet_SNAP frames, which are 802.3 * frames with an LLC header and a SNAP * header and with an OUI of 0x000000 * (encapsulated Ethernet) and a protocol * ID of ETHERTYPE_IPX in the SNAP header. * * XXX - should we generate the same code both * for tests for LLCSAP_IPX and for ETHERTYPE_IPX? */ /* * This generates code to check both for the * IPX LSAP (Ethernet_802.2) and for Ethernet_802.3. */ b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B, (bpf_int32)LLCSAP_IPX); b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_H, (bpf_int32)0xFFFF); gen_or(b0, b1); /* * Now we add code to check for SNAP frames with * ETHERTYPE_IPX, i.e. Ethernet_SNAP. */ b0 = gen_snap(0x000000, ETHERTYPE_IPX, 14); gen_or(b0, b1); /* * Now we generate code to check for 802.3 * frames in general. */ b0 = gen_cmp_gt(OR_LINK, off_linktype, BPF_H, ETHERMTU); gen_not(b0); /* * Now add the check for 802.3 frames before the * check for Ethernet_802.2 and Ethernet_802.3, * as those checks should only be done on 802.3 * frames, not on Ethernet frames. */ gen_and(b0, b1); /* * Now add the check for Ethernet_II frames, and * do that before checking for the other frame * types. */ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)ETHERTYPE_IPX); gen_or(b0, b1); return b1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -