summaryrefslogtreecommitdiffstats
path: root/contrib/libpcap/gencode.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libpcap/gencode.c')
-rw-r--r--contrib/libpcap/gencode.c271
1 files changed, 214 insertions, 57 deletions
diff --git a/contrib/libpcap/gencode.c b/contrib/libpcap/gencode.c
index 33ad950..8672171 100644
--- a/contrib/libpcap/gencode.c
+++ b/contrib/libpcap/gencode.c
@@ -21,7 +21,7 @@
*/
#ifndef lint
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.24 2005/06/20 21:52:53 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.221.2.34 2005/09/05 09:08:04 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -100,8 +100,8 @@ static const char rcsid[] _U_ =
static jmp_buf top_ctx;
static pcap_t *bpf_pcap;
-/* Hack for updating VLAN, MPLS offsets. */
-static u_int orig_linktype = -1U, orig_nl = -1U;
+/* Hack for updating VLAN, MPLS, and PPPoE offsets. */
+static u_int orig_linktype = -1U, orig_nl = -1U, label_stack_depth = -1U;
/* XXX */
#ifdef PCAP_FDDIPAD
@@ -205,6 +205,7 @@ 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);
#ifdef INET6
static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int);
@@ -778,6 +779,9 @@ init_linktype(p)
off_proto = -1;
off_payload = -1;
+ /*
+ * And assume we're not doing SS7.
+ */
off_sio = -1;
off_opc = -1;
off_dpc = -1;
@@ -790,6 +794,7 @@ init_linktype(p)
orig_linktype = -1;
orig_nl = -1;
+ label_stack_depth = 0;
reg_ll_size = -1;
@@ -1113,8 +1118,12 @@ init_linktype(p)
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 */
@@ -1135,6 +1144,7 @@ init_linktype(p)
/* 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 */
@@ -1851,6 +1861,25 @@ gen_linktype(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:
@@ -2240,6 +2269,7 @@ gen_linktype(proto)
/*NOTREACHED*/
break;
+ case DLT_JUNIPER_MFR:
case DLT_JUNIPER_MLFR:
case DLT_JUNIPER_MLPPP:
case DLT_JUNIPER_ATM1:
@@ -2250,6 +2280,10 @@ gen_linktype(proto)
case DLT_JUNIPER_ES:
case DLT_JUNIPER_MONITOR:
case DLT_JUNIPER_SERVICES:
+ case DLT_JUNIPER_ETHER:
+ case DLT_JUNIPER_PPP:
+ case DLT_JUNIPER_FRELAY:
+ case DLT_JUNIPER_CHDLC:
/* just lets verify the magic number for now -
* on ATM we may have up to 6 different encapsulations on the wire
* and need a lot of heuristics to figure out that the payload
@@ -3034,6 +3068,40 @@ gen_dnhostop(addr, dir)
return b1;
}
+/*
+ * Generate a check for IPv4 or IPv6 for MPLS-encapsulated packets;
+ * test the bottom-of-stack bit, and then check the version number
+ * field in the IP header.
+ */
+static struct block *
+gen_mpls_linktype(proto)
+ int proto;
+{
+ struct block *b0, *b1;
+
+ switch (proto) {
+
+ case Q_IP:
+ /* match the bottom-of-stack bit */
+ b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01);
+ /* match the IPv4 version number */
+ b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x40, 0xf0);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_IPV6:
+ /* match the bottom-of-stack bit */
+ b0 = gen_mcmp(OR_NET, -2, BPF_B, 0x01, 0x01);
+ /* match the IPv4 version number */
+ b1 = gen_mcmp(OR_NET, 0, BPF_B, 0x60, 0xf0);
+ gen_and(b0, b1);
+ return b1;
+
+ default:
+ abort();
+ }
+}
+
static struct block *
gen_host(addr, mask, proto, dir)
bpf_u_int32 addr;
@@ -3047,11 +3115,15 @@ gen_host(addr, mask, proto, dir)
case Q_DEFAULT:
b0 = gen_host(addr, mask, Q_IP, dir);
- if (off_linktype != (u_int)-1) {
- b1 = gen_host(addr, mask, Q_ARP, dir);
- gen_or(b0, b1);
- b0 = gen_host(addr, mask, Q_RARP, dir);
- gen_or(b1, b0);
+ /*
+ * Only check for non-IPv4 addresses if we're not
+ * checking MPLS-encapsulated packets.
+ */
+ if (label_stack_depth == 0) {
+ b1 = gen_host(addr, mask, Q_ARP, dir);
+ gen_or(b0, b1);
+ b0 = gen_host(addr, mask, Q_RARP, dir);
+ gen_or(b1, b0);
}
return b0;
@@ -4393,6 +4465,7 @@ gen_proto(v, proto, dir)
*
* So we always check for ETHERTYPE_IP.
*/
+
b0 = gen_linktype(ETHERTYPE_IP);
#ifndef CHASE_CHAIN
b1 = gen_cmp(OR_NET, 9, BPF_B, (bpf_int32)v);
@@ -5983,6 +6056,7 @@ gen_inbound(dir)
}
break;
+ case DLT_JUNIPER_MFR:
case DLT_JUNIPER_MLFR:
case DLT_JUNIPER_MLPPP:
case DLT_JUNIPER_ATM1:
@@ -5993,6 +6067,10 @@ gen_inbound(dir)
case DLT_JUNIPER_ES:
case DLT_JUNIPER_MONITOR:
case DLT_JUNIPER_SERVICES:
+ case DLT_JUNIPER_ETHER:
+ case DLT_JUNIPER_PPP:
+ case DLT_JUNIPER_FRELAY:
+ case DLT_JUNIPER_CHDLC:
/* juniper flags (including direction) are stored
* the byte after the 3-byte magic number */
if (dir) {
@@ -6036,7 +6114,7 @@ gen_pf_ifname(const char *ifname)
return (b0);
}
-/* PF firewall log matched interface */
+/* PF firewall log ruleset name */
struct block *
gen_pf_ruleset(char *ruleset)
{
@@ -6175,7 +6253,11 @@ struct block *
gen_vlan(vlan_num)
int vlan_num;
{
- struct block *b0;
+ struct block *b0, *b1;
+
+ /* can't check for VLAN-encapsulated packets inside MPLS */
+ if (label_stack_depth > 0)
+ bpf_error("no VLAN match after MPLS");
/*
* Change the offsets to point to the type and data fields within
@@ -6207,30 +6289,28 @@ gen_vlan(vlan_num)
* be done assuming a VLAN, even though the "or" could be viewed
* as meaning "or, if this isn't a VLAN packet...".
*/
- orig_linktype = off_linktype; /* save original values */
- orig_nl = off_nl;
+ orig_linktype = off_linktype; /* save original values */
+ orig_nl = off_nl;
- switch (linktype) {
+ switch (linktype) {
- case DLT_EN10MB:
- off_linktype += 4;
- off_nl_nosnap += 4;
- off_nl += 4;
- break;
+ case DLT_EN10MB:
+ off_linktype += 4;
+ off_nl_nosnap += 4;
+ off_nl += 4;
+ break;
- default:
- bpf_error("no VLAN support for data link type %d",
- linktype);
- /*NOTREACHED*/
- }
+ default:
+ bpf_error("no VLAN support for data link type %d",
+ linktype);
+ /*NOTREACHED*/
+ }
/* check for VLAN */
b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q);
/* If a specific VLAN is requested, check VLAN id */
if (vlan_num >= 0) {
- struct block *b1;
-
b1 = gen_mcmp(OR_LINK, orig_nl, BPF_H, (bpf_int32)vlan_num,
0x0fff);
gen_and(b0, b1);
@@ -6247,7 +6327,7 @@ struct block *
gen_mpls(label_num)
int label_num;
{
- struct block *b0;
+ struct block *b0,*b1;
/*
* Change the offsets to point to the type and data fields within
@@ -6258,44 +6338,46 @@ gen_mpls(label_num)
*
* XXX - this is a bit of a kludge. See comments in gen_vlan().
*/
- orig_linktype = off_linktype; /* save original values */
orig_nl = off_nl;
- switch (linktype) {
-
- case DLT_C_HDLC: /* fall through */
- case DLT_EN10MB:
- off_nl_nosnap += 4;
- off_nl += 4;
-
- b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H,
- (bpf_int32)ETHERTYPE_MPLS);
- break;
-
- case DLT_PPP:
- off_nl_nosnap += 4;
- off_nl += 4;
-
- b0 = gen_cmp(OR_LINK, orig_linktype, BPF_H,
- (bpf_int32)PPP_MPLS_UCAST);
- break;
-
- /* FIXME add other DLT_s ...
- * for Frame-Relay/and ATM this may get messy due to SNAP headers
- * leave it for now */
-
- default:
- bpf_error("no MPLS support for data link type %d",
+ if (label_stack_depth > 0) {
+ /* just match the bottom-of-stack bit clear */
+ b0 = gen_mcmp(OR_LINK, orig_nl-2, BPF_B, 0, 0x01);
+ } else {
+ /*
+ * Indicate that we're checking MPLS-encapsulated headers,
+ * to make sure higher level code generators don't try to
+ * match against IP-related protocols such as Q_ARP, Q_RARP
+ * etc.
+ */
+ switch (linktype) {
+
+ case DLT_C_HDLC: /* fall through */
+ case DLT_EN10MB:
+ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+ (bpf_int32)ETHERTYPE_MPLS);
+ break;
+
+ case DLT_PPP:
+ b0 = gen_cmp(OR_LINK, off_linktype, BPF_H,
+ (bpf_int32)PPP_MPLS_UCAST);
+ break;
+
+ /* FIXME add other DLT_s ...
+ * for Frame-Relay/and ATM this may get messy due to SNAP headers
+ * leave it for now */
+
+ default:
+ bpf_error("no MPLS support for data link type %d",
linktype);
- b0 = NULL;
- /*NOTREACHED*/
- break;
+ b0 = NULL;
+ /*NOTREACHED*/
+ break;
+ }
}
/* If a specific MPLS label is requested, check it */
if (label_num >= 0) {
- struct block *b1;
-
label_num = label_num << 12; /* label is shifted 12 bits on the wire */
b1 = gen_mcmp(OR_LINK, orig_nl, BPF_W, (bpf_int32)label_num,
0xfffff000); /* only compare the first 20 bits */
@@ -6303,9 +6385,84 @@ gen_mpls(label_num)
b0 = b1;
}
+ off_nl_nosnap += 4;
+ off_nl += 4;
+ label_stack_depth++;
return (b0);
}
+/*
+ * Support PPPOE discovery and session.
+ */
+struct block *
+gen_pppoed()
+{
+ /* check for PPPoE discovery */
+ return gen_linktype((bpf_int32)ETHERTYPE_PPPOED);
+}
+
+struct block *
+gen_pppoes()
+{
+ struct block *b0;
+
+ /*
+ * Test against the PPPoE session link-layer type.
+ */
+ b0 = gen_linktype((bpf_int32)ETHERTYPE_PPPOES);
+
+ /*
+ * Change the offsets to point to the type and data fields within
+ * the PPP packet.
+ *
+ * XXX - this is a bit of a kludge. If we were to split the
+ * compiler into a parser that parses an expression and
+ * generates an expression tree, and a code generator that
+ * takes an expression tree (which could come from our
+ * parser or from some other parser) and generates BPF code,
+ * we could perhaps make the offsets parameters of routines
+ * and, in the handler for an "AND" node, pass to subnodes
+ * other than the PPPoE node the adjusted offsets.
+ *
+ * This would mean that "pppoes" would, instead of changing the
+ * behavior of *all* tests after it, change only the behavior
+ * of tests ANDed with it. That would change the documented
+ * semantics of "pppoes", which might break some expressions.
+ * However, it would mean that "(pppoes and ip) or ip" would check
+ * both for VLAN-encapsulated IP and IP-over-Ethernet, rather than
+ * checking only for VLAN-encapsulated IP, so that could still
+ * be considered worth doing; it wouldn't break expressions
+ * that are of the form "pppoes and ..." which I suspect are the
+ * most common expressions involving "pppoes". "pppoes or ..."
+ * doesn't necessarily do what the user would really want, now,
+ * as all the "or ..." tests would be done assuming PPPoE, even
+ * though the "or" could be viewed as meaning "or, if this isn't
+ * a PPPoE packet...".
+ */
+ orig_linktype = off_linktype; /* save original values */
+ orig_nl = off_nl;
+
+ /*
+ * The "network-layer" protocol is PPPoE, which has a 6-byte
+ * PPPoE header, followed by PPP payload, so we set the
+ * offsets to the network layer offset plus 6 bytes for
+ * the PPPoE header plus the values appropriate for PPP when
+ * encapsulated in Ethernet (which means there's no HDLC
+ * encapsulation).
+ */
+ off_linktype = orig_nl + 6;
+ off_nl = orig_nl + 6 + 2;
+ off_nl_nosnap = orig_nl + 6 + 2;
+
+ /*
+ * Set the link-layer type to PPP, as all subsequent tests will
+ * be on the encapsulated PPP header.
+ */
+ linktype = DLT_PPP;
+
+ return b0;
+}
+
struct block *
gen_atmfield_code(atmfield, jvalue, jtype, reverse)
int atmfield;
OpenPOWER on IntegriCloud