use pktbaffle::{compile, LinkType, Target};
fn eth_prog(filter: &str) -> pktbaffle::Program {
compile(filter, LinkType::Ethernet, Target::Classic)
.unwrap_or_else(|e| panic!("compile({filter:?}): {e}"))
}
fn last_two_are_ret(prog: &pktbaffle::Program) {
let insns = prog.instructions();
let n = insns.len();
assert!(
n >= 2,
"program must have at least 2 instructions (accept + drop)"
);
let ret_k = 0x0006u16;
assert_eq!(
insns[n - 2].code,
ret_k,
"second-to-last must be ret ACCEPT"
);
assert_eq!(insns[n - 1].code, ret_k, "last must be ret DROP");
assert_eq!(insns[n - 2].k, 0xffff_ffff, "ACCEPT value");
assert_eq!(insns[n - 1].k, 0, "DROP value");
}
#[test]
fn host_ipv4() {
let p = eth_prog("host 192.168.1.1");
last_two_are_ret(&p);
assert!(p.len() > 2);
}
#[test]
fn src_host() {
let p = eth_prog("src host 10.0.0.1");
last_two_are_ret(&p);
}
#[test]
fn dst_host() {
let p = eth_prog("dst host 10.0.0.2");
last_two_are_ret(&p);
}
#[test]
fn net_cidr() {
let p = eth_prog("net 10.0.0.0/8");
last_two_are_ret(&p);
}
#[test]
fn tcp_port() {
let p = eth_prog("tcp port 443");
last_two_are_ret(&p);
}
#[test]
fn udp_port() {
let p = eth_prog("udp port 53");
last_two_are_ret(&p);
}
#[test]
fn bare_port() {
let p = eth_prog("port 80");
last_two_are_ret(&p);
}
#[test]
fn portrange() {
let p = eth_prog("portrange 1024-65535");
last_two_are_ret(&p);
}
#[test]
fn proto_tcp() {
let p = eth_prog("tcp");
last_two_are_ret(&p);
}
#[test]
fn proto_icmp() {
let p = eth_prog("icmp");
last_two_are_ret(&p);
}
#[test]
fn proto_arp() {
let p = eth_prog("arp");
last_two_are_ret(&p);
}
#[test]
fn ether_host() {
let p = eth_prog("ether host aa:bb:cc:dd:ee:ff");
last_two_are_ret(&p);
}
#[test]
fn ether_broadcast() {
let p = eth_prog("ether broadcast");
last_two_are_ret(&p);
}
#[test]
fn less_than() {
let p = eth_prog("less 64");
last_two_are_ret(&p);
}
#[test]
fn greater_than() {
let p = eth_prog("greater 1500");
last_two_are_ret(&p);
}
#[test]
fn and_explicit() {
let p = eth_prog("tcp and port 80");
last_two_are_ret(&p);
}
#[test]
fn and_implicit() {
let p = eth_prog("tcp port 80"); last_two_are_ret(&p);
}
#[test]
fn or_simple() {
let p = eth_prog("tcp or udp");
last_two_are_ret(&p);
}
#[test]
fn not_simple() {
let p = eth_prog("not arp");
last_two_are_ret(&p);
}
#[test]
fn complex_and_or() {
let p = eth_prog("(tcp or udp) and port 53");
last_two_are_ret(&p);
}
#[test]
fn host_and_port() {
let p = eth_prog("host 1.2.3.4 and tcp port 80");
last_two_are_ret(&p);
}
#[test]
fn not_host() {
let p = eth_prog("not host 1.2.3.4");
last_two_are_ret(&p);
}
#[test]
fn byte_access_tcp_syn() {
let p = eth_prog("tcp[13] & 0x02 != 0");
last_two_are_ret(&p);
}
#[test]
fn byte_access_ip_ttl() {
let p = eth_prog("ip[8] = 64");
last_two_are_ret(&p);
}
#[test]
fn tcpflags_constant() {
let p = eth_prog("tcp[tcpflags] & tcp-syn != 0");
last_two_are_ret(&p);
}
#[test]
fn icmp_named_constants() {
let p = eth_prog("icmp[icmptype] = icmp-echo");
last_two_are_ret(&p);
}
#[test]
fn net_mask_syntax() {
let p = eth_prog("net 192.168.0.0 mask 255.255.0.0");
last_two_are_ret(&p);
}
#[test]
fn net_mask_and_cidr_equivalent() {
let p_mask = eth_prog("net 10.0.0.0 mask 255.0.0.0");
let p_cidr = eth_prog("net 10.0.0.0/8");
assert_eq!(p_mask.len(), p_cidr.len());
}
#[test]
fn proto_ah() {
let p = eth_prog("ah");
last_two_are_ret(&p);
}
#[test]
fn proto_esp() {
let p = eth_prog("esp");
last_two_are_ret(&p);
}
#[test]
fn proto_pim() {
let p = eth_prog("pim");
last_two_are_ret(&p);
}
#[test]
fn proto_igrp() {
let p = eth_prog("igrp");
last_two_are_ret(&p);
}
#[test]
fn proto_vrrp() {
let p = eth_prog("vrrp");
last_two_are_ret(&p);
}
#[test]
fn ip_proto_number() {
let p = eth_prog("ip proto 6");
last_two_are_ret(&p);
}
#[test]
fn ip6_proto_number() {
let p = eth_prog("ip6 proto 58");
last_two_are_ret(&p);
}
#[test]
fn ip6_proto_tcp() {
let p = eth_prog("ip6 proto 6");
last_two_are_ret(&p);
}
#[test]
fn ether_multicast() {
let p = eth_prog("ether multicast");
last_two_are_ret(&p);
}
#[test]
fn bare_broadcast() {
let p = eth_prog("broadcast");
last_two_are_ret(&p);
}
#[test]
fn bare_multicast() {
let p = eth_prog("multicast");
last_two_are_ret(&p);
}
#[test]
fn ip_broadcast() {
let p = eth_prog("ip broadcast");
last_two_are_ret(&p);
}
#[test]
fn ip_multicast() {
let p = eth_prog("ip multicast");
last_two_are_ret(&p);
}
#[test]
fn ip6_multicast() {
let p = eth_prog("ip6 multicast");
last_two_are_ret(&p);
}
#[test]
fn vlan_any() {
let p = eth_prog("vlan");
last_two_are_ret(&p);
}
#[test]
fn vlan_with_id() {
let p = eth_prog("vlan 100");
last_two_are_ret(&p);
}
#[test]
fn vlan_and_tcp() {
let p = eth_prog("vlan and tcp port 22");
last_two_are_ret(&p);
}
#[test]
fn mpls_any() {
let p = eth_prog("mpls");
last_two_are_ret(&p);
}
#[test]
fn mpls_with_label() {
let p = eth_prog("mpls 12345");
last_two_are_ret(&p);
}
#[test]
fn pppoe_discovery() {
let p = eth_prog("pppoed");
last_two_are_ret(&p);
}
#[test]
fn pppoe_session() {
let p = eth_prog("pppoes");
last_two_are_ret(&p);
}
#[test]
fn len_eq() {
let p = eth_prog("len = 60");
last_two_are_ret(&p);
}
#[test]
fn len_ne() {
let p = eth_prog("len != 60");
last_two_are_ret(&p);
}
#[test]
fn len_gt() {
let p = eth_prog("len > 1000");
last_two_are_ret(&p);
}
#[test]
fn len_ge() {
let p = eth_prog("len >= 1000");
last_two_are_ret(&p);
}
#[test]
fn len_lt() {
let p = eth_prog("len < 64");
last_two_are_ret(&p);
}
#[test]
fn len_le() {
let p = eth_prog("len <= 64");
last_two_are_ret(&p);
}
#[test]
fn ether_src_mac_no_host() {
let p = eth_prog("ether src aa:bb:cc:dd:ee:ff");
last_two_are_ret(&p);
}
#[test]
fn ether_dst_mac_no_host() {
let p = eth_prog("ether dst 11:22:33:44:55:66");
last_two_are_ret(&p);
}
#[test]
fn sctp_port() {
let p = eth_prog("src sctp port 36412");
last_two_are_ret(&p);
}
#[test]
fn inbound_is_codegen_error() {
let r = compile("inbound", LinkType::Ethernet, Target::Classic);
assert!(r.is_err());
}
#[test]
fn outbound_is_codegen_error() {
let r = compile("outbound", LinkType::Ethernet, Target::Classic);
assert!(r.is_err());
}
#[test]
fn empty_filter_is_error() {
let result = compile("", LinkType::Ethernet, Target::Classic);
assert!(result.is_err());
}
#[test]
fn unknown_keyword_is_error() {
let result = compile(
"frobnicator host 1.2.3.4",
LinkType::Ethernet,
Target::Classic,
);
assert!(result.is_err());
}
#[test]
fn bytes_length_matches_instruction_count() {
let p = eth_prog("tcp port 80");
assert_eq!(p.to_le_bytes().len(), p.len() * 8);
}
#[test]
fn rawip_host() {
let p = compile("host 192.168.1.1", LinkType::RawIp, Target::Classic).unwrap();
last_two_are_ret(&p);
}
#[test]
fn rawip_ether_host_is_error() {
let r = compile(
"ether host aa:bb:cc:dd:ee:ff",
LinkType::RawIp,
Target::Classic,
);
assert!(r.is_err());
}
#[test]
fn rawip_ether_multicast_is_error() {
let r = compile("ether multicast", LinkType::RawIp, Target::Classic);
assert!(r.is_err());
}
#[test]
fn linuxsll_host() {
let p = compile("host 10.0.0.1", LinkType::LinuxSll, Target::Classic).unwrap();
last_two_are_ret(&p);
}
#[test]
fn linuxsll_tcp_port() {
let p = compile("tcp port 443", LinkType::LinuxSll, Target::Classic).unwrap();
last_two_are_ret(&p);
}