struct in6_addr *, int, u_int, u_int);
#endif
static struct block *gen_ahostop(compiler_state_t *, const uint8_t, int);
-static struct block *gen_mac48hostop(compiler_state_t *, const u_char *,
- const int, const u_int, const u_int);
-static struct block *gen_ehostop(compiler_state_t *, const u_char *, int);
-static struct block *gen_fhostop(compiler_state_t *, const u_char *, int);
-static struct block *gen_thostop(compiler_state_t *, const u_char *, int);
static struct block *gen_wlanhostop(compiler_state_t *, const u_char *, int);
-static struct block *gen_ipfchostop(compiler_state_t *, const u_char *, int);
+static unsigned char is_mac48_linktype(const int);
+static struct block *gen_mac48host(compiler_state_t *, const u_char *,
+ const u_char, const char *);
static struct block *gen_dnhostop(compiler_state_t *, bpf_u_int32, int);
static struct block *gen_mpls_linktype(compiler_state_t *, bpf_u_int32);
static struct block *gen_host(compiler_state_t *, bpf_u_int32, bpf_u_int32,
#define ERRSTR_802_11_ONLY_KW "'%s' is valid for 802.11 syntax only"
#define ERRSTR_INVALID_QUAL "'%s' is not a valid qualifier for '%s'"
+#define ERRSTR_UNKNOWN_MAC48HOST "unknown Ethernet-like host '%s'"
// Validate a port/portrange proto qualifier and map to an IP protocol number.
static int
}
#endif
-// MAC-48 address matching with the address offsets parametrised.
-static struct block *
-gen_mac48hostop(compiler_state_t *cstate, const u_char *addr, const int dir,
- const u_int src_off, const u_int dst_off)
-{
- struct block *b0, *b1;
-
- switch (dir) {
- case Q_SRC:
- return gen_bcmp(cstate, OR_LINKHDR, src_off, 6, addr);
-
- case Q_DST:
- return gen_bcmp(cstate, OR_LINKHDR, dst_off, 6, addr);
-
- case Q_AND:
- b0 = gen_mac48hostop(cstate, addr, Q_SRC, src_off, dst_off);
- b1 = gen_mac48hostop(cstate, addr, Q_DST, src_off, dst_off);
- gen_and(b0, b1);
- return b1;
-
- case Q_DEFAULT:
- case Q_OR:
- b0 = gen_mac48hostop(cstate, addr, Q_SRC, src_off, dst_off);
- b1 = gen_mac48hostop(cstate, addr, Q_DST, src_off, dst_off);
- gen_or(b0, b1);
- return b1;
-
- case Q_ADDR1:
- case Q_ADDR2:
- case Q_ADDR3:
- case Q_ADDR4:
- case Q_RA:
- case Q_TA:
- bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
- /*NOTREACHED*/
- }
- abort();
- /*NOTREACHED*/
-}
-
-static struct block *
-gen_ehostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
-{
- return gen_mac48hostop(cstate, eaddr, dir, 6, 0);
-}
-
-/*
- * Like gen_ehostop, but for DLT_FDDI
- */
-static struct block *
-gen_fhostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
-{
- return gen_mac48hostop(cstate, eaddr, dir,
- 6 + 1 + cstate->pcap_fddipad,
- 0 + 1 + cstate->pcap_fddipad);
-}
-
-/*
- * Like gen_ehostop, but for DLT_IEEE802 (Token Ring)
- */
-static struct block *
-gen_thostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
-{
- return gen_mac48hostop(cstate, eaddr, dir, 8, 2);
-}
-
/*
- * Like gen_ehostop, but for DLT_IEEE802_11 (802.11 wireless LAN) and
+ * Like gen_mac48host(), but for DLT_IEEE802_11 (802.11 wireless LAN) and
* various 802.11 + radio headers.
*/
static struct block *
/*NOTREACHED*/
}
-/*
- * Like gen_ehostop, but for RFC 2625 IP-over-Fibre-Channel.
- * (We assume that the addresses are IEEE 48-bit MAC addresses,
- * as the RFC states.)
- */
-static struct block *
-gen_ipfchostop(compiler_state_t *cstate, const u_char *eaddr, int dir)
-{
- return gen_mac48hostop(cstate, eaddr, dir, 10, 2);
-}
-
/*
* This is quite tricky because there may be pad bytes in front of the
* DECNET header, and then there are two possible data packet formats that
}
#endif
+static unsigned char
+is_mac48_linktype(const int linktype)
+{
+ switch (linktype) {
+ case DLT_EN10MB:
+ case DLT_FDDI:
+ case DLT_IEEE802:
+ case DLT_IEEE802_11:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IP_OVER_FC:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ case DLT_PPI:
+ case DLT_PRISM_HEADER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static struct block *
+gen_mac48host(compiler_state_t *cstate, const u_char *eaddr, const u_char dir,
+ const char *keyword)
+{
+ struct block *b1 = NULL;
+ u_int src_off, dst_off;
+
+ switch (cstate->linktype) {
+ case DLT_EN10MB:
+ case DLT_NETANALYZER:
+ case DLT_NETANALYZER_TRANSPARENT:
+ b1 = gen_prevlinkhdr_check(cstate);
+ src_off = 6;
+ dst_off = 0;
+ break;
+ case DLT_FDDI:
+ src_off = 6 + 1 + cstate->pcap_fddipad;
+ dst_off = 0 + 1 + cstate->pcap_fddipad;
+ break;
+ case DLT_IEEE802:
+ src_off = 8;
+ dst_off = 2;
+ break;
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_PPI:
+ return gen_wlanhostop(cstate, eaddr, dir);
+ case DLT_IP_OVER_FC:
+ /*
+ * Assume that the addresses are IEEE 48-bit MAC addresses,
+ * as RFC 2625 states.
+ */
+ src_off = 10;
+ dst_off = 2;
+ break;
+ case DLT_SUNATM:
+ /*
+ * This is LLC-multiplexed traffic; if it were
+ * LANE, cstate->linktype would have been set to
+ * DLT_EN10MB.
+ */
+ /* FALLTHROUGH */
+ default:
+ fail_kw_on_dlt(cstate, keyword);
+ }
+
+ struct block *b0, *tmp;
+
+ switch (dir) {
+ case Q_SRC:
+ b0 = gen_bcmp(cstate, OR_LINKHDR, src_off, 6, eaddr);
+ break;
+ case Q_DST:
+ b0 = gen_bcmp(cstate, OR_LINKHDR, dst_off, 6, eaddr);
+ break;
+ case Q_AND:
+ tmp = gen_bcmp(cstate, OR_LINKHDR, src_off, 6, eaddr);
+ b0 = gen_bcmp(cstate, OR_LINKHDR, dst_off, 6, eaddr);
+ gen_and(tmp, b0);
+ break;
+ case Q_DEFAULT:
+ case Q_OR:
+ tmp = gen_bcmp(cstate, OR_LINKHDR, src_off, 6, eaddr);
+ b0 = gen_bcmp(cstate, OR_LINKHDR, dst_off, 6, eaddr);
+ gen_or(tmp, b0);
+ break;
+ default:
+ bpf_error(cstate, ERRSTR_802_11_ONLY_KW, dqkw(dir));
+ }
+
+ if (b1 != NULL)
+ gen_and(b1, b0);
+ return b0;
+}
+
#ifndef INET6
/*
* This primitive is non-directional by design, so the grammar does not allow
case Q_IP:
case Q_ARP:
case Q_RARP:
- switch (cstate->linktype) {
- case DLT_EN10MB:
- case DLT_NETANALYZER:
- case DLT_NETANALYZER_TRANSPARENT:
- b1 = gen_prevlinkhdr_check(cstate);
- b0 = gen_ehostop(cstate, eaddr, Q_OR);
- if (b1 != NULL)
- gen_and(b1, b0);
- break;
- case DLT_FDDI:
- b0 = gen_fhostop(cstate, eaddr, Q_OR);
- break;
- case DLT_IEEE802:
- b0 = gen_thostop(cstate, eaddr, Q_OR);
- break;
- case DLT_IEEE802_11:
- case DLT_PRISM_HEADER:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- case DLT_PPI:
- b0 = gen_wlanhostop(cstate, eaddr, Q_OR);
- break;
- case DLT_IP_OVER_FC:
- b0 = gen_ipfchostop(cstate, eaddr, Q_OR);
- break;
- case DLT_SUNATM:
- /*
- * This is LLC-multiplexed traffic; if it were
- * LANE, cstate->linktype would have been set to
- * DLT_EN10MB.
- */
- /* FALLTHROUGH */
- default:
- bpf_error(cstate,
- "'gateway' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
- }
+ b0 = gen_mac48host(cstate, eaddr, Q_OR, "gateway");
b1 = NULL;
for (ai = alist; ai != NULL; ai = ai->ai_next) {
/*
case Q_DEFAULT:
case Q_HOST:
if (proto == Q_LINK) {
- switch (cstate->linktype) {
-
- case DLT_EN10MB:
- case DLT_NETANALYZER:
- case DLT_NETANALYZER_TRANSPARENT:
- eaddrp = pcap_ether_hostton(name);
- if (eaddrp == NULL)
- bpf_error(cstate,
- "unknown ether host '%s'", name);
- memcpy(eaddr, eaddrp, sizeof(eaddr));
- free(eaddrp);
- tmp = gen_prevlinkhdr_check(cstate);
- b = gen_ehostop(cstate, eaddr, dir);
- if (tmp != NULL)
- gen_and(tmp, b);
- return b;
-
- case DLT_FDDI:
- eaddrp = pcap_ether_hostton(name);
- if (eaddrp == NULL)
- bpf_error(cstate,
- "unknown FDDI host '%s'", name);
- memcpy(eaddr, eaddrp, sizeof(eaddr));
- free(eaddrp);
- b = gen_fhostop(cstate, eaddr, dir);
- return b;
-
- case DLT_IEEE802:
- eaddrp = pcap_ether_hostton(name);
- if (eaddrp == NULL)
- bpf_error(cstate,
- "unknown token ring host '%s'", name);
- memcpy(eaddr, eaddrp, sizeof(eaddr));
- free(eaddrp);
- b = gen_thostop(cstate, eaddr, dir);
- return b;
-
- case DLT_IEEE802_11:
- case DLT_PRISM_HEADER:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- case DLT_PPI:
- eaddrp = pcap_ether_hostton(name);
- if (eaddrp == NULL)
- bpf_error(cstate,
- "unknown 802.11 host '%s'", name);
- memcpy(eaddr, eaddrp, sizeof(eaddr));
- free(eaddrp);
- b = gen_wlanhostop(cstate, eaddr, dir);
- return b;
-
- case DLT_IP_OVER_FC:
- eaddrp = pcap_ether_hostton(name);
- if (eaddrp == NULL)
- bpf_error(cstate,
- "unknown Fibre Channel host '%s'", name);
- memcpy(eaddr, eaddrp, sizeof(eaddr));
- free(eaddrp);
- b = gen_ipfchostop(cstate, eaddr, dir);
- return b;
- }
-
- bpf_error(cstate, "only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name");
+ const char *context = "link host NAME";
+ if (! is_mac48_linktype(cstate->linktype))
+ fail_kw_on_dlt(cstate, context);
+ eaddrp = pcap_ether_hostton(name);
+ if (eaddrp == NULL)
+ bpf_error(cstate, ERRSTR_UNKNOWN_MAC48HOST, name);
+ memcpy(eaddr, eaddrp, sizeof(eaddr));
+ free(eaddrp);
+ return gen_mac48host(cstate, eaddr, q.dir, context);
} else if (proto == Q_DECNET) {
/*
* A long time ago on Ultrix libpcap supported
case Q_GATEWAY:
#ifndef INET6
+ if (! is_mac48_linktype(cstate->linktype))
+ fail_kw_on_dlt(cstate, "gateway");
eaddrp = pcap_ether_hostton(name);
if (eaddrp == NULL)
- bpf_error(cstate, "unknown ether host: %s", name);
+ bpf_error(cstate, ERRSTR_UNKNOWN_MAC48HOST, name);
memcpy(eaddr, eaddrp, sizeof(eaddr));
free(eaddrp);
struct block *
gen_ecode(compiler_state_t *cstate, const char *s, struct qual q)
{
- struct block *b, *tmp;
-
/*
* Catch errors reported by us and routines below us, and return NULL
* on an error.
return (NULL);
if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
+ const char *context = "link host XX:XX:XX:XX:XX:XX";
+ if (! is_mac48_linktype(cstate->linktype))
+ fail_kw_on_dlt(cstate, context);
cstate->e = pcap_ether_aton(s);
if (cstate->e == NULL)
bpf_error(cstate, "malloc");
- switch (cstate->linktype) {
- case DLT_EN10MB:
- case DLT_NETANALYZER:
- case DLT_NETANALYZER_TRANSPARENT:
- tmp = gen_prevlinkhdr_check(cstate);
- b = gen_ehostop(cstate, cstate->e, (int)q.dir);
- if (tmp != NULL)
- gen_and(tmp, b);
- break;
- case DLT_FDDI:
- b = gen_fhostop(cstate, cstate->e, (int)q.dir);
- break;
- case DLT_IEEE802:
- b = gen_thostop(cstate, cstate->e, (int)q.dir);
- break;
- case DLT_IEEE802_11:
- case DLT_PRISM_HEADER:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- case DLT_PPI:
- b = gen_wlanhostop(cstate, cstate->e, (int)q.dir);
- break;
- case DLT_IP_OVER_FC:
- b = gen_ipfchostop(cstate, cstate->e, (int)q.dir);
- break;
- default:
- free(cstate->e);
- cstate->e = NULL;
- bpf_error(cstate, "ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel");
- /*NOTREACHED*/
- }
+ struct block *b = gen_mac48host(cstate, cstate->e, q.dir, context);
free(cstate->e);
cstate->e = NULL;
return (b);
case DLT_ARCNET_LINUX:
// ARCnet broadcast is [8-bit] destination address 0.
return gen_ahostop(cstate, 0, Q_DST);
- case DLT_EN10MB:
- case DLT_NETANALYZER:
- case DLT_NETANALYZER_TRANSPARENT:
- b1 = gen_prevlinkhdr_check(cstate);
- b0 = gen_ehostop(cstate, ebroadcast, Q_DST);
- if (b1 != NULL)
- gen_and(b1, b0);
- return b0;
- case DLT_FDDI:
- return gen_fhostop(cstate, ebroadcast, Q_DST);
- case DLT_IEEE802:
- return gen_thostop(cstate, ebroadcast, Q_DST);
- case DLT_IEEE802_11:
- case DLT_PRISM_HEADER:
- case DLT_IEEE802_11_RADIO_AVS:
- case DLT_IEEE802_11_RADIO:
- case DLT_PPI:
- return gen_wlanhostop(cstate, ebroadcast, Q_DST);
- case DLT_IP_OVER_FC:
- return gen_ipfchostop(cstate, ebroadcast, Q_DST);
}
- fail_kw_on_dlt(cstate, "broadcast");
+ return gen_mac48host(cstate, ebroadcast, Q_DST, "broadcast");
/*NOTREACHED*/
case Q_IP:
expr => 'proto 1.2.3.4',
errstr => '\'proto\' qualifier applied to IPv4 address',
},
- # In the tests below the hostname normally should not matter because the
- # lookup would be made not in the IPv4/IPv6 space, or not at all. Still
- # use a hostname that does not exist on the Internet, just in case.
- {
- name => 'link_host_en10mb',
- DLT => 'EN10MB',
- expr => "link host ${nonexistent}",
- errstr => "unknown ether host '${nonexistent}'",
- },
- {
- name => 'link_host_netanalyzer',
- DLT => 'NETANALYZER',
- expr => "link host ${nonexistent}",
- errstr => "unknown ether host '${nonexistent}'",
- },
- {
- name => 'link_host_netanalyzer_transparent',
- DLT => 'NETANALYZER_TRANSPARENT',
- expr => "link host ${nonexistent}",
- errstr => "unknown ether host '${nonexistent}'",
- },
- {
- name => 'link_host_fddi',
- DLT => 'FDDI',
- expr => "link host ${nonexistent}",
- errstr => "unknown FDDI host '${nonexistent}'",
- },
- {
- name => 'link_host_ieee802',
- DLT => 'IEEE802',
- expr => "link host ${nonexistent}",
- errstr => "unknown token ring host '${nonexistent}'",
- },
- {
- name => 'link_host_802_11',
- DLT => 'IEEE802_11',
- expr => "link host ${nonexistent}",
- errstr => "unknown 802.11 host '${nonexistent}'",
- },
- {
- name => 'link_host_802_11_radio',
- DLT => 'IEEE802_11_RADIO_AVS',
- expr => "link host ${nonexistent}",
- errstr => "unknown 802.11 host '${nonexistent}'",
- },
- {
- name => 'link_host_802_11_radio_avs',
- DLT => 'IEEE802_11_RADIO_AVS',
- expr => "link host ${nonexistent}",
- errstr => "unknown 802.11 host '${nonexistent}'",
- },
- {
- name => 'link_host_prism_header',
- DLT => 'PRISM_HEADER',
- expr => "link host ${nonexistent}",
- errstr => "unknown 802.11 host '${nonexistent}'",
- },
- {
- name => 'link_host_ip_over_fc',
- DLT => 'IP_OVER_FC',
- expr => "link host ${nonexistent}",
- errstr => "unknown Fibre Channel host '${nonexistent}'",
- },
- {
- name => 'link_host_other',
- DLT => 'ARCNET',
- expr => "link host ${nonexistent}",
- errstr => 'supports link-level host name',
- },
{
name => 'decnet_host',
DLT => 'EN10MB',
expr => 'gateway eth-noipv4-ipv6.host123.libpcap.test',
errstr => 'unknown host', # no IPv4 address in /etc/hosts
},
- {
- name => 'gateway_noeth',
- skip => skip_config_def1 ('INET6') ||
- skip_no_ethers() ||
- skip_no_hosts(),
- DLT => 'EN10MB',
- expr => 'gateway noeth-ipv4-noipv6.host123.libpcap.test',
- errstr => 'unknown ether host', # not in /etc/ethers
- },
{
name => 'src_gateway',
skip => skip_config_def1 ('INET6') ||
skip_no_hosts(),
DLT => $_,
expr => 'gateway eth-ipv4-noipv6.host123.libpcap.test',
- errstr => '\'gateway\' supported only on',
+ errstr => '\'gateway\' not supported on',
};
# ID -> gen_scode() -> case Q_GATEWAY -> gen_gateway() -> case Q_DEFAULT -> default
# Invokes bpf_error() after pcap_ether_hostton().
skip_no_hosts(),
DLT => $_,
expr => 'gateway eth-ipv4-ipv6.host123.libpcap.test',
- errstr => '\'gateway\' supported only on',
+ errstr => '\'gateway\' not supported on',
};
}
};
}
-# gen_broadcast() -> case Q_LINK -> default
+# gen_broadcast() -> case Q_LINK -> gen_mac48host() -> fail_kw_on_dlt()
foreach (DLTs_without 'link_broadcast') {
push @reject_tests, {
name => "link_broadcast_${_}",
};
}
-# gen_scode() -> case Q_HOST -> proto == Q_LINK -> non-WLAN case -> gen_mac48hostop() -> default case
+# gen_scode() -> case Q_HOST -> proto == Q_LINK -> non-WLAN case -> gen_mac48host() -> default case
# Invokes bpf_error() after pcap_ether_hostton().
foreach my $DLT (DLTs_without '') {
next if ! DLT_feature ($DLT, 'link_host_mac48') || DLT_feature ($DLT, 'wlan');
}
foreach (DLTs_without 'link_host_mac48') {
- # gen_gateway() -> case Q_DEFAULT -> default
+ # gen_scode() -> case Q_GATEWAY -> fail_kw_on_dlt()
push @reject_tests, {
name => "gateway_name_${_}",
skip => skip_config_def1 ('INET6') ||
skip_no_hosts(),
DLT => $_,
expr => 'gateway eth-ipv4-noipv6.host123.libpcap.test',
- errstr => '\'gateway\' supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel',
+ errstr => '\'gateway\' not supported on',
};
- # gen_scode() -> case Q_DEFAULT -> Q_LINK
+ # gen_scode() -> case Q_DEFAULT -> Q_LINK -> fail_kw_on_dlt()
push @reject_tests, {
name => "link_host_name_${_}",
skip => skip_no_ethers(),
DLT => $_,
expr => 'link host eth-noipv4-noipv6.host123.libpcap.test',
- errstr => 'only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name',
+ errstr => '\'link host NAME\' not supported on',
+ };
+ # gen_ecode() -> fail_kw_on_dlt()
+ push @reject_tests, {
+ name => "link_host_mac48_${_}",
+ DLT => $_,
+ expr => 'link host a:b:c:d:e:f',
+ errstr => '\'link host XX:XX:XX:XX:XX:XX\' not supported on',
+ };
+}
+
+foreach (DLTs_with 'link_host_mac48') {
+ # gen_scode() -> case Q_GATEWAY -> eaddrp == NULL
+ push @reject_tests, {
+ name => "gateway_nonex_${_}",
+ skip => skip_config_def1 ('INET6') ||
+ skip_no_hosts(),
+ DLT => $_,
+ expr => 'gateway noeth-ipv4-noipv6.host123.libpcap.test',
+ errstr => "unknown Ethernet-like host 'noeth-ipv4-noipv6.host123.libpcap.test'",
+ };
+ # In the test below the hostname normally should not matter because the
+ # lookup would be made not in the IPv4/IPv6 space, or not at all. Still
+ # use a hostname that does not exist on the Internet, just in case.
+ # gen_scode() -> case Q_HOST -> proto == Q_LINK -> eaddrp == NULL
+ push @reject_tests, {
+ name => "link_host_nonex_${_}",
+ DLT => $_,
+ expr => "link host ${nonexistent}",
+ errstr => "unknown Ethernet-like host '${nonexistent}'",
};
}