diff --git a/tests/sys/netpfil/pf/pflow.sh b/tests/sys/netpfil/pf/pflow.sh index 4bed49ef6f76..88478cfbfe84 100644 --- a/tests/sys/netpfil/pf/pflow.sh +++ b/tests/sys/netpfil/pf/pflow.sh @@ -124,7 +124,7 @@ state_defaults_body() ping -c 1 192.0.2.1 # We default to version 5 - atf_check -o match:"^v=5.*" \ + atf_check -o match:".*v=5.*" \ $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055 # Switch to version 10 @@ -132,7 +132,7 @@ state_defaults_body() ping -c 1 192.0.2.1 - atf_check -o match:"^v=10.*" \ + atf_check -o match:".*v=10.*" \ $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055 } @@ -174,7 +174,7 @@ v6_body() ping -6 -c 1 2001:db8::1 - atf_check -o match:"^v=10.*" \ + atf_check -o match:".*v=10,IPv6,proto=58,src=2001:db8::2,dst=2001:db8::1.*" \ $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}a --port 2055 } @@ -183,9 +183,61 @@ v6_cleanup() pft_cleanup } +atf_test_case "nat" "cleanup" +nat_head() +{ + atf_set descr 'Test pflow export for NAT44' + atf_set require.user root + atf_set require.progs scapy +} + +nat_body() +{ + pflow_init + + epair=$(vnet_mkepair) + epair_srv=$(vnet_mkepair) + + vnet_mkjail srv ${epair_srv}a + vnet_mkjail rtr ${epair_srv}b ${epair}a + + ifconfig ${epair}b 192.0.2.2/24 up + + jexec srv ifconfig ${epair_srv}a 198.51.100.2/24 up + jexec srv route add default 198.51.100.1 + + jexec rtr ifconfig ${epair_srv}b 198.51.100.1/24 up + jexec rtr ifconfig ${epair}a 192.0.2.1/24 up + jexec rtr sysctl net.inet.ip.forwarding=1 + + route add -net 198.51.100.0/24 192.0.2.1 + + jexec rtr pfctl -e + pft_set_rules rtr \ + "set state-defaults pflow" \ + "nat pass on ${epair_srv}b inet from 192.0.2.0/24 to any -> (${epair_srv}b)" \ + "pass" + + pflow=$(jexec rtr pflowctl -c) + jexec rtr pflowctl -s ${pflow} dst 192.0.2.2:2055 proto 10 + + # Sanity check + atf_check -s exit:0 -o ignore \ + ping -c 1 198.51.100.2 + + atf_check -o match:".*v=10,NAT=4,proto=1,src=192.0.2.2-198.51.100.1.*" \ + $(atf_get_srcdir)/pft_read_ipfix.py --recvif ${epair}b --port 2055 +} + +nat_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "basic" atf_add_test_case "state_defaults" atf_add_test_case "v6" + atf_add_test_case "nat" } diff --git a/tests/sys/netpfil/pf/pft_read_ipfix.py b/tests/sys/netpfil/pf/pft_read_ipfix.py index 64d4fcb3c523..2c11bdfd130c 100644 --- a/tests/sys/netpfil/pf/pft_read_ipfix.py +++ b/tests/sys/netpfil/pf/pft_read_ipfix.py @@ -31,6 +31,34 @@ logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp +def parse_ipfix(p): + if not sp.NetflowDataflowsetV9 in p: + # A template? + return + + c = p + while sp.NetflowDataflowsetV9 in c: + datafl = c[sp.NetflowDataflowsetV9] + if datafl.templateID == 258: + # NAT + for r in datafl.records: + print("v=10,NAT=%d,proto=%s,src=%s-%s,dst=%s-%s" % + (int.from_bytes(r.natEvent, "big"), r.PROTOCOL, + r.IPV4_SRC_ADDR, r.postNATSourceIPv4Address, + r.IPV4_DST_ADDR, r.postNATDestinationIPv4Address)) + elif datafl.templateID == 257: + # IPv6 + for r in datafl.records: + print("v=10,IPv6,proto=%s,src=%s,dst=%s" % + (r.PROTOCOL, r.IPV6_SRC_ADDR, r.IPV6_DST_ADDR)) + elif datafl.templateID == 256: + # IPv4 + for r in datafl.records: + print("v=10,proto=%s,src=%s,dst=%s" % + (r.PROTOCOL, r.IPV4_SRC_ADDR, r.IPV4_DST_ADDR)) + + c = datafl.payload + def receive(recvif, recvport): pkts = sp.sniff(iface=recvif, timeout=65) @@ -38,6 +66,8 @@ def receive(recvif, recvport): print("No data") return + pkts = sp.ipfix_defragment(pkts) + for pkt in pkts: udp = pkt.getlayer(sp.UDP) if not udp: @@ -46,18 +76,19 @@ def receive(recvif, recvport): if udp.dport != recvport: continue - hdr = pkt.getlayer(sp.NetflowHeader) + if not sp.NetflowHeader in pkt: + continue + hdr = pkt.getlayer(sp.NetflowHeader) if hdr.version == 5: v5hdr = pkt.getlayer(sp.NetflowHeaderV5) out="" for i in range(1, v5hdr.count + 1): r = pkt.getlayer(sp.NetflowRecordV5, nb=i) - out = "%s,proto=%d,src=%s,dst=%s,srcport=%d,dstport=%d" % (out, r.prot, r.src, r.dst, r.srcport, r.dstport) - print("v=%d,count=%d%s" % (hdr.version, v5hdr.count, out)) + print("v=%d,proto=%d,src=%s,dst=%s,srcport=%d,dstport=%d" % + (hdr.version, r.prot, r.src, r.dst, r.srcport, r.dstport)) elif hdr.version == 10: - print("v=10") - return + parse_ipfix(pkt) def main(): parser = argparse.ArgumentParser("pft_read_ipfix.py",