Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F149840699
D11401.id30498.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D11401.id30498.diff
View Options
Index: tests/sys/netpfil/pf/Makefile
===================================================================
--- /dev/null
+++ tests/sys/netpfil/pf/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/netpfil/pf
+BINDIR= ${TESTSDIR}
+
+ATF_TESTS_SH= pf_test
+
+SUBDIR+= files
+
+.include <bsd.test.mk>
Index: tests/sys/netpfil/pf/files/Makefile
===================================================================
--- /dev/null
+++ tests/sys/netpfil/pf/files/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/netpfil/pf/files
+BINDIR= ${TESTSDIR}
+
+FILES= pf_test_conf.sh scrub.py conf.py
+
+.include <bsd.progs.mk>
Index: tests/sys/netpfil/pf/files/conf.py
===================================================================
--- /dev/null
+++ tests/sys/netpfil/pf/files/conf.py
@@ -0,0 +1,10 @@
+# python2
+
+# Read conf variables from pf_test_conf.sh.
+
+conffile = open('pf_test_conf.sh')
+
+for line in conffile:
+ # Simple test that line is of the form var=val.
+ if len(line.split('=', 1)) == 2:
+ exec(line)
Index: tests/sys/netpfil/pf/files/pf_test_conf.sh
===================================================================
--- /dev/null
+++ tests/sys/netpfil/pf/files/pf_test_conf.sh
@@ -0,0 +1,23 @@
+# You need to set these variables for the tests to work.
+# Keep the contents of the file in the form 'var=val' as below,
+# as this file will be read from python as well.
+
+SSH='root@192.168.0.2'
+
+LOCAL_IF_1='tap1'
+REMOTE_IF_1='vtnet1'
+LOCAL_MAC_1='00:bd:6e:8c:ff:01'
+REMOTE_MAC_1='00:a0:98:eb:76:05'
+LOCAL_ADDR_1='192.168.1.1'
+REMOTE_ADDR_1='192.168.1.2'
+
+LOCAL_IF_2='tap2'
+REMOTE_IF_2='vtnet2'
+LOCAL_MAC_2='00:bd:54:7d:98:02'
+REMOTE_MAC_2='00:a0:98:8f:42:f7'
+LOCAL_ADDR_2='192.168.2.1'
+REMOTE_ADDR_2='192.168.2.2'
+
+LOCAL_IF_3='tap3'
+LOCAL_ADDR_2='192.168.2.1'
+LOCAL_ADDR_3='192.168.3.1'
Index: tests/sys/netpfil/pf/files/scrub.py
===================================================================
--- /dev/null
+++ tests/sys/netpfil/pf/files/scrub.py
@@ -0,0 +1,59 @@
+# /usr/bin/env python2
+
+import multiprocessing as mp
+import scapy.all as sp
+import conf
+import time
+import random
+import util
+
+raw_500 = ('abcdefghijklmnopqrstuvwxyz' * 22)[random.randrange(26):][:500]
+
+ether1 = sp.Ether(src=conf.LOCAL_MAC_1, dst=conf.REMOTE_MAC_1)
+ether2 = sp.Ether(src=conf.LOCAL_MAC_2, dst=conf.REMOTE_MAC_2)
+ip1 = sp.IP(src=conf.LOCAL_ADDR_1,
+ dst=conf.LOCAL_ADDR_3, id=random.randrange(1 << 16))
+ip2 = sp.IP(src=conf.LOCAL_ADDR_2,
+ dst=conf.LOCAL_ADDR_3, id=random.randrange(1 << 16))
+icmp = sp.ICMP(type='echo-request',
+ id=random.randrange(1 << 16), seq=random.randrange(1 << 16))
+
+p1 = ether1 / ip1 / icmp / raw_500
+p2 = ether2 / ip2 / icmp / raw_500
+
+def sendpackets():
+ time.sleep(1)
+ sp.sendp(sp.fragment(p1, 300), iface=conf.LOCAL_IF_1, verbose=False)
+ sp.sendp(sp.fragment(p2, 300), iface=conf.LOCAL_IF_2, verbose=False)
+
+sender = mp.Process(target=sendpackets)
+sender.start()
+
+sniffed = []
+sp.sniff(iface=conf.LOCAL_IF_3, prn=sniffed.append, timeout=5)
+
+sender.join()
+
+success1, success2 = False, False
+
+defr = util.Defragmenter()
+pp1, pp2 = p1.payload, p2.payload # IP layer
+k1, k2 = util.pkey(pp1), util.pkey(pp2)
+for p in sniffed:
+ pp = defr.more(p)
+ if pp is None:
+ continue
+ k = util.pkey(pp)
+
+ # Success for interface 1 if packet received in 1 fragment,
+ # i.e. scrub active on remote side.
+ success1 = success1 or (k == k1 and defr.stats[k] == 1 and
+ str(pp.payload) == str(pp1.payload))
+
+ # Success for interface 2 if packet received in 2 fragments,
+ # i.e. no scrub on remote side.
+ success2 = success2 or (k == k2 and defr.stats[k] == 2 and
+ str(pp.payload) == str(pp2.payload))
+
+if not (success1 and success2):
+ exit(1)
Index: tests/sys/netpfil/pf/files/util.py
===================================================================
--- /dev/null
+++ tests/sys/netpfil/pf/files/util.py
@@ -0,0 +1,63 @@
+# python2
+
+import scapy.all as sp
+
+def pkey(packet):
+ '''Packet key.'''
+ return (packet.src, packet.dst, packet.proto, packet.id)
+
+class Defragmenter(object):
+ def __init__(self):
+ self.frags = dict()
+ self.stats = dict()
+ def more(self, packet):
+ '''Add fragmented packet, return whole packet if complete.'''
+
+ # Find IP layer.
+ p = packet
+ while p.name != 'NoPayload':
+ if p.name == 'IP':
+ break
+ p = p.payload
+ else:
+ return
+
+ # # Return directly if not fragmented.
+ # if not ((p.flags & 1) or p.frag): # & 1 for MF
+ # return p
+
+ # Add fragment to its packet group.
+ key, val = pkey(p), (p.frag, p)
+ if key in self.frags:
+ self.frags[key].append(val)
+ self.stats[key] += 1
+ else:
+ self.frags[key] = [val]
+ self.stats[key] = 1
+ frag = self.frags[key]
+ frag.sort()
+
+ # Now all fragments in the group are sorted,
+ # go through them and connect them.
+ i = 0
+ while i + 1 < len(frag):
+ f1, p1 = frag[i]
+ f2, p2 = frag[i + 1]
+ len1, len2 = len(p1.payload), len(p2.payload)
+ if len1 == (f2 - f1) * 8:
+ header1 = sp.IP(tos=p1.tos, flags=p1.flags, ttl=p1.ttl,
+ src=p1.src, dst=p1.dst,
+ proto=p1.proto, id=p1.id)
+ # Now copy MF flag from p2.
+ header1.flags = (header1.flags & ~1) | (p2.flags & 1)
+ p = header1 / (str(p1.payload) + str(p2.payload))
+ frag[i:i + 2] = [(f1, p)]
+ else:
+ i += 1
+
+ # Return packet if complete.
+ p = frag[0][1]
+ isfirst, islast = (not p.frag), (not (p.flags & 1))
+ if len(frag) == 1 and isfirst and islast:
+ del self.frags[key]
+ return p
Index: tests/sys/netpfil/pf/pf_test.sh
===================================================================
--- /dev/null
+++ tests/sys/netpfil/pf/pf_test.sh
@@ -0,0 +1,125 @@
+# Make will add a shebang line at the top of this file.
+
+# These tests connect to a remote test machine, load a rules file,
+# possibly start some services, and run some tests. The tests cleanup
+# the test machine in the end.
+#
+# SSH root access to the test machine is required for the tests to
+# work.
+
+. "$(atf_get_srcdir)/files/pf_test_conf.sh"
+
+# Starts two instances of nc on the remote machine, listening on two
+# different ports, of which one port is blocked-with-return by the
+# remote pf. The test tries then to connect to the two instances from
+# the local machine. The test succeeds if one connection succeeds but
+# the other one fails.
+atf_test_case block_return cleanup
+block_return_head () {
+ atf_set descr 'Block-with-return a port and test that it is blocked.'
+}
+block_return_body () {
+ rules="block return in on $REMOTE_IF_1 proto tcp to port 50000"
+ atf_check ssh "$SSH" kldload -n pf
+ echo "$rules" | atf_check -e ignore ssh "$SSH" pfctl -ef -
+ atf_check daemon -p nc.50000.pid ssh "$SSH" nc -l 50000
+ atf_check daemon -p nc.50001.pid ssh "$SSH" nc -l 50001
+ atf_check -s exit:1 -e empty nc -z "$REMOTE_ADDR_1" 50000
+ atf_check -s exit:0 -e ignore nc -z "$REMOTE_ADDR_1" 50001
+}
+block_return_cleanup () {
+ atf_check -e ignore ssh "$SSH" pfctl -dFa
+ [ -e nc.50000.pid ] && kill `cat nc.50000.pid`
+ [ -e nc.50001.pid ] && kill `cat nc.50001.pid`
+}
+
+atf_test_case block_drop cleanup
+block_drop_head () {
+ atf_set descr 'Block-with-drop a port and test that it is blocked.'
+}
+block_drop_body () {
+ rules="block drop in on $REMOTE_IF_1 proto tcp to port 50000"
+ atf_check ssh "$SSH" kldload -n pf
+ echo "$rules" | atf_check -e ignore ssh "$SSH" pfctl -ef -
+ atf_check daemon -p nc.50000.pid ssh "$SSH" nc -l 50000
+ atf_check daemon -p nc.50001.pid ssh "$SSH" nc -l 50001
+ atf_check -s exit:1 -e empty nc -z -w 4 "$REMOTE_ADDR_1" 50000
+ atf_check -s exit:0 -e ignore nc -z "$REMOTE_ADDR_1" 50001
+}
+block_drop_cleanup () {
+ atf_check -e ignore ssh "$SSH" pfctl -dFa
+ [ -e nc.50000.pid ] && kill `cat nc.50000.pid`
+ [ -e nc.50001.pid ] && kill `cat nc.50001.pid`
+}
+
+# # This test uses 2 interfaces to connect to the test machine,
+# # $REMOTE_IF_1 and $REMOTE_IF_2. The test machine is doing reassembly
+# # on one of the two interfaces. We send one echo request on each
+# # interface of size 3000, which will be fragmented before being sent.
+# # We capture the traffic on the test machine's pflog and transfer the
+# # capture file to the host machine for processing. The capture file
+# # should show a reassembled echo request packet on one interface and
+# # the original fragmented set of packets on the other.
+# atf_test_case scrub_todo cleanup
+# scrub_todo_head () {
+# atf_set descr 'Scrub on one of two interfaces and test difference.'
+# }
+# scrub_todo_body () {
+# # files to be used in local directory: tempdir.var tcpdump.pid
+# # files to be used in remote temporary directory: pflog.pcap
+# rules="scrub in on $REMOTE_IF_1 all fragment reassemble
+# pass log (all, to pflog0) on { $REMOTE_IF_1 $REMOTE_IF_2 }"
+# atf_check ssh "$SSH" kldload -n pf pflog
+# echo "$rules" | atf_check -e ignore ssh "$SSH" pfctl -ef -
+# # TODO not sure why this doesn't work with atf_check
+# #atf_check -o file:tempdir.var ssh "$SSH" mktemp -dt pf_test.tmp
+# ssh "$SSH" mktemp -dt pf_test.tmp > tempdir.var
+# tempdir="`cat tempdir.var`"
+# atf_check daemon -p tcpdump.pid \
+# ssh "$SSH" tcpdump -U -i pflog0 -w "$tempdir/pflog.pcap"
+# atf_check -o ignore ping -c1 -s3000 "$REMOTE_ADDR_1"
+# atf_check -o ignore ping -c1 -s3000 "$REMOTE_ADDR_2"
+# sleep 2 # wait for tcpdump to pick up everything
+# kill "`cat tcpdump.pid`"
+# sleep 2 # wait for tcpdump to write out everything
+# atf_check scp "$SSH:$tempdir/pflog.pcap" ./
+# # TODO following will be removed when the test is complete, but
+# # since processing isn't implemented yet, we just save the file
+# # for now.
+# atf_check cp pflog.pcap "$(atf_get_srcdir)/"
+# # TODO process pflog.pcap for verification
+# }
+# scrub_todo_cleanup () {
+# kill "`cat tcpdump.pid`"
+# tempdir="`cat tempdir.var`"
+# ssh "$SSH" "rm -r \"$tempdir\" ;
+# pfctl -dFa"
+# }
+
+atf_test_case scrub_forward cleanup
+scrub_forward_head () {
+ atf_set descr 'Scrub defrag with forward on one \
+of two interfaces and test difference.'
+}
+scrub_forward_body () {
+ rules="scrub in on $REMOTE_IF_1 all fragment reassemble
+ pass log (all, to pflog0) on { $REMOTE_IF_1 $REMOTE_IF_2 }"
+ cd "$(atf_get_srcdir)"
+ atf_check ssh "$SSH" kldload -n pf
+ echo "$rules" | atf_check -e ignore ssh "$SSH" pfctl -ef -
+ atf_check -o ignore ssh "$SSH" sysctl net.inet.ip.forwarding=1
+ cd files &&
+ atf_check python2 scrub.py &&
+ cd ..
+}
+scrub_forward_cleanup () {
+ ssh "$SSH" "pfctl -dFa ;
+ sysctl net.inet.ip.forwarding=0"
+}
+
+atf_init_test_cases () {
+ atf_add_test_case block_return
+ atf_add_test_case block_drop
+ # atf_add_test_case scrub_todo
+ atf_add_test_case scrub_forward
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 28, 12:28 PM (15 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30472389
Default Alt Text
D11401.id30498.diff (11 KB)
Attached To
Mode
D11401: Kernel pf tests
Attached
Detach File
Event Timeline
Log In to Comment