gencode.c

来自「Ubuntu packages of security software。 相」· C语言 代码 · 共 2,698 行 · 第 1/5 页

C
2,698
字号
		 *		 *	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.		 *		 * First, do the checks on LINUX_SLL_P_802_2		 * frames; generate the check for either		 * Ethernet_802.2 or Ethernet_SNAP frames, and		 * then put a check for LINUX_SLL_P_802_2 frames		 * before it.		 */		b0 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,		    (bpf_int32)LLCSAP_IPX);		b1 = gen_snap(0x000000, ETHERTYPE_IPX,		    off_linktype + 2);		gen_or(b0, b1);		b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);		gen_and(b0, b1);		/*		 * Now check for 802.3 frames and OR that with		 * the previous test.		 */		b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_3);		gen_or(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;	case ETHERTYPE_ATALK:	case ETHERTYPE_AARP:		/*		 * EtherTalk (AppleTalk protocols on Ethernet link		 * layer) may use 802.2 encapsulation.		 */		/*		 * Check for 802.2 encapsulation (EtherTalk phase 2?);		 * we check for the 802.2 protocol type in the		 * "Ethernet type" field.		 */		b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, LINUX_SLL_P_802_2);		/*		 * 802.2-encapsulated ETHERTYPE_ATALK packets are		 * SNAP packets with an organization code of		 * 0x080007 (Apple, for Appletalk) and a protocol		 * type of ETHERTYPE_ATALK (Appletalk).		 *		 * 802.2-encapsulated ETHERTYPE_AARP packets are		 * SNAP packets with an organization code of		 * 0x000000 (encapsulated Ethernet) and a protocol		 * type of ETHERTYPE_AARP (Appletalk ARP).		 */		if (proto == ETHERTYPE_ATALK)			b1 = gen_snap(0x080007, ETHERTYPE_ATALK,			    off_linktype + 2);		else	/* proto == ETHERTYPE_AARP */			b1 = gen_snap(0x000000, ETHERTYPE_AARP,			    off_linktype + 2);		gen_and(b0, b1);		/*		 * Check for Ethernet encapsulation (Ethertalk		 * phase 1?); we just check for the Ethernet		 * protocol type.		 */		b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, (bpf_int32)proto);		gen_or(b0, b1);		return b1;	default:		if (proto <= ETHERMTU) {			/*			 * This is an LLC SAP value, so the frames			 * that match would be 802.2 frames.			 * Check for the 802.2 protocol type			 * in the "Ethernet type" field, and			 * then check the DSAP.			 */			b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,			    LINUX_SLL_P_802_2);			b1 = gen_cmp(OR_LINK, off_linktype + 2, BPF_B,			     (bpf_int32)proto);			gen_and(b0, b1);			return b1;		} else {			/*			 * This is an Ethernet type, so compare			 * the length/type field with it (if			 * the frame is an 802.2 frame, the length			 * field will be <= ETHERMTU, and, as			 * "proto" is > ETHERMTU, this test			 * will fail and the frame won't match,			 * which is what we want).			 */			return gen_cmp(OR_LINK, off_linktype, BPF_H,			    (bpf_int32)proto);		}	}}static voidinsert_radiotap_load_llprefixlen(b)	struct block *b;{	struct slist *s1, *s2;	/*	 * Prepend to the statements in this block code to load the	 * length of the radiotap header into the register assigned	 * to hold that length, if one has been assigned.	 */	if (reg_ll_size != -1) {		/*		 * The 2 bytes at offsets of 2 and 3 from the beginning		 * of the radiotap header are the length of the radiotap		 * header; unfortunately, it's little-endian, so we have		 * to load it a byte at a time and construct the value.		 */		/*		 * Load the high-order byte, at an offset of 3, shift it		 * left a byte, and put the result in the X register.		 */		s1 = new_stmt(BPF_LD|BPF_B|BPF_ABS);		s1->s.k = 3;		s2 = new_stmt(BPF_ALU|BPF_LSH|BPF_K);		sappend(s1, s2);		s2->s.k = 8;		s2 = new_stmt(BPF_MISC|BPF_TAX);		sappend(s1, s2);		/*		 * Load the next byte, at an offset of 2, and OR the		 * value from the X register into it.		 */		s2 = new_stmt(BPF_LD|BPF_B|BPF_ABS);		sappend(s1, s2);		s2->s.k = 2;		s2 = new_stmt(BPF_ALU|BPF_OR|BPF_X);		sappend(s1, s2);		/*		 * Now allocate a register to hold that value and store		 * it.		 */		s2 = new_stmt(BPF_ST);		s2->s.k = reg_ll_size;		sappend(s1, s2);		/*		 * Now move it into the X register.		 */		s2 = new_stmt(BPF_MISC|BPF_TAX);		sappend(s1, s2);		/*		 * Now append all the existing statements in this		 * block to these statements.		 */		sappend(s1, b->stmts);		b->stmts = s1;	}}static voidinsert_load_llprefixlen(b)	struct block *b;{	switch (linktype) {	case DLT_IEEE802_11_RADIO:		insert_radiotap_load_llprefixlen(b);	}}static struct slist *gen_radiotap_llprefixlen(void){	struct slist *s;	if (reg_ll_size == -1) {		/*		 * We haven't yet assigned a register for the length		 * of the radiotap header; allocate one.		 */		reg_ll_size = alloc_reg();	}	/*	 * Load the register containing the radiotap length	 * into the X register.	 */	s = new_stmt(BPF_LDX|BPF_MEM);	s->s.k = reg_ll_size;	return s;}/* * Generate code to compute the link-layer header length, if necessary, * putting it into the X register, and to return either a pointer to a * "struct slist" for the list of statements in that code, or NULL if * no code is necessary. */static struct slist *gen_llprefixlen(void){	switch (linktype) {	case DLT_IEEE802_11_RADIO:		return gen_radiotap_llprefixlen();	default:		return NULL;	}}/* * Generate code to match a particular packet type by matching the * link-layer type field or fields in the 802.2 LLC header. * * "proto" is an Ethernet type value, if > ETHERMTU, or an LLC SAP * value, if <= ETHERMTU. */static struct block *gen_linktype(proto)	register int proto;{	struct block *b0, *b1, *b2;	/* are we checking MPLS-encapsulated packets? */	if (label_stack_depth > 0) {		switch (proto) {		case ETHERTYPE_IP:		case PPP_IP:		/* FIXME add other L3 proto IDs */			return gen_mpls_linktype(Q_IP); 		case ETHERTYPE_IPV6:		case PPP_IPV6:		/* FIXME add other L3 proto IDs */			return gen_mpls_linktype(Q_IPV6); 		default:			bpf_error("unsupported protocol over mpls");			/* NOTREACHED */		}	}	switch (linktype) {	case DLT_EN10MB:		return gen_ether_linktype(proto);		/*NOTREACHED*/		break;	case DLT_C_HDLC:		switch (proto) {		case LLCSAP_ISONS:			proto = (proto << 8 | LLCSAP_ISONS);			/* fall through */		default:			return gen_cmp(OR_LINK, off_linktype, BPF_H,			    (bpf_int32)proto);			/*NOTREACHED*/			break;		}		break;	case DLT_FDDI:	case DLT_IEEE802:	case DLT_IEEE802_11:	case DLT_IEEE802_11_RADIO_AVS:	case DLT_IEEE802_11_RADIO:	case DLT_PRISM_HEADER:	case DLT_ATM_RFC1483:	case DLT_ATM_CLIP:	case DLT_IP_OVER_FC:		return gen_llc_linktype(proto);		/*NOTREACHED*/		break;	case DLT_SUNATM:		/*		 * If "is_lane" is set, check for a LANE-encapsulated		 * version of this protocol, otherwise check for an		 * LLC-encapsulated version of this protocol.		 *		 * We assume LANE means Ethernet, not Token Ring.		 */		if (is_lane) {			/*			 * Check that the packet doesn't begin with an			 * LE Control marker.  (We've already generated			 * a test for LANE.)			 */			b0 = gen_cmp(OR_LINK, SUNATM_PKT_BEGIN_POS, BPF_H,			    0xFF00);			gen_not(b0);			/*			 * Now generate an Ethernet test.			 */			b1 = gen_ether_linktype(proto);			gen_and(b0, b1);			return b1;		} else {			/*			 * Check for LLC encapsulation and then check the			 * protocol.			 */			b0 = gen_atmfield_code(A_PROTOTYPE, PT_LLC, BPF_JEQ, 0);			b1 = gen_llc_linktype(proto);			gen_and(b0, b1);			return b1;		}		/*NOTREACHED*/		break;	case DLT_LINUX_SLL:		return gen_linux_sll_linktype(proto);		/*NOTREACHED*/		break;	case DLT_SLIP:	case DLT_SLIP_BSDOS:	case DLT_RAW:		/*		 * These types don't provide any type field; packets		 * are always IP.		 *		 * XXX - for IPv4, check for a version number of 4, and,		 * for IPv6, check for a version number of 6?		 */		switch (proto) {		case ETHERTYPE_IP:#ifdef INET6		case ETHERTYPE_IPV6:#endif			return gen_true();		/* always true */		default:			return gen_false();		/* always false */		}		/*NOTREACHED*/		break;	case DLT_PPP:	case DLT_PPP_PPPD:	case DLT_PPP_SERIAL:	case DLT_PPP_ETHER:		/*		 * We use Ethernet protocol types inside libpcap;		 * map them to the corresponding PPP protocol types.		 */		switch (proto) {		case ETHERTYPE_IP:			proto = PPP_IP;			break;#ifdef INET6		case ETHERTYPE_IPV6:			proto = PPP_IPV6;			break;#endif		case ETHERTYPE_DN:			proto = PPP_DECNET;			break;		case ETHERTYPE_ATALK:			proto = PPP_APPLE;			break;		case ETHERTYPE_NS:			proto = PPP_NS;			break;		case LLCSAP_ISONS:			proto = PPP_OSI;			break;		case LLCSAP_8021D:			/*			 * I'm assuming the "Bridging PDU"s that go			 * over PPP are Spanning Tree Protocol			 * Bridging PDUs.			 */			proto = PPP_BRPDU;			break;		case LLCSAP_IPX:			proto = PPP_IPX;			break;		}		break;	case DLT_PPP_BSDOS:		/*		 * We use Ethernet protocol types inside libpcap;		 * map them to the corresponding PPP protocol types.		 */		switch (proto) {		case ETHERTYPE_IP:			b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_IP);			b1 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_VJC);			gen_or(b0, b1);			b0 = gen_cmp(OR_LINK, off_linktype, BPF_H, PPP_VJNC);			gen_or(b1, b0);			return b0;#ifdef INET6		case ETHERTYPE_IPV6:			proto = PPP_IPV6;			/* more to go? */			break;#endif		case ETHERTYPE_DN:			proto = PPP_DECNET;			break;		case ETHERTYPE_ATALK:			proto = PPP_APPLE;			break;		case ETHERTYPE_NS:			proto = PPP_NS;			break;		case LLCSAP_ISONS:			proto = PPP_OSI;			break;		case LLCSAP_8021D:			/*			 * I'm assuming the "Bridging PDU"s that go			 * over PPP are Spanning Tree Protocol			 * Bridging PDUs.			 */			proto = PPP_BRPDU;			break;		case LLCSAP_IPX:			proto = PPP_IPX;			break;		}		break;	case DLT_NULL:	case DLT_LOOP:	case DLT_ENC:		/*		 * For DLT_NULL, the link-layer header is a 32-bit		 * word containing an AF_ value in *host* byte order,		 * and for DLT_ENC, the link-layer header begins		 * with a 32-bit work containing an AF_ value in		 * host byte order.		 *		 * In addition, if we're reading a saved capture file,		 * the host byte order in the capture may not be the		 * same as the host byte order on this machine.		 *		 * For DLT_LOOP, the link-layer header is a 32-bit		 * word containing an AF_ value in *network* byte order.		 *		 * XXX - AF_ values may, unfortunately, be platform-		 * dependent; for example, FreeBSD's AF_INET6 is 24		 * whilst NetBSD's and OpenBSD's is 26.		 *		 * This means that, when reading a capture file, just		 * checking for our AF_INET6 value won't work if the		 * capture file came from another OS.		 */		switch (proto) {		case ETHERTYPE_IP:			proto = AF_INET;			break;#ifdef INET6		case ETHERTYPE_IPV6:			proto = AF_INET6;			break;#endif		default:			/*			 * Not a type on which we support filtering.			 * XXX - support those that have AF_ values			 * #defined on this platform, at least?			 */			return gen_false();		}		if (linktype == DLT_NULL || linktype == DLT_ENC) {			/*			 * The AF_ value is in host byte order, but			 * the BPF interpreter will convert it to			 * network byte order.			 *			 * If this is a save file, and it's from a			 * machine with the opposite byte order to			 * ours, we byte-swap the AF_ value.			 *			 * Then we run it through "htonl()", and			 * generate code to compare against the result.			 */			if (bpf_pcap->sf.rfile != NULL &&			    bpf_pcap->sf.swapped)				proto = SWAPLONG(proto);			proto = htonl(proto);		}		return (gen_cmp(OR_LINK, 0, BPF_W, (bpf_int32)proto));	case DLT_PFLOG:		/*		 * af field is host byte order in contrast to the rest of		 * the packet.		 */		if (proto == ETHERTYPE_IP)			return (gen_cmp(OR_LINK, offsetof(struct pfloghdr, af),

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?