summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2012-01-31 00:14:03 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2012-01-31 00:14:03 +0000
commitc6452939c8a1e14f76be9d2b5a4ad26d6684fcad (patch)
treec3990d43ac44c490c5070855abf8bd7099db3722
parent0839783b8e2a4b45caa8837ed126434a5150810b (diff)
Add test suite for IPv6 neighbor discovery protocol. Send all kind
of solicitations to remote host and check responses. This can be used to test both pf neighbor discovery states and the IPv6 stack.
-rw-r--r--regress/sys/netinet6/nd6/Makefile111
-rw-r--r--regress/sys/netinet6/nd6/nd6_ar.py48
-rw-r--r--regress/sys/netinet6/nd6/nd6_dad.py48
-rw-r--r--regress/sys/netinet6/nd6/nd6_nud.py48
-rw-r--r--regress/sys/netinet6/nd6/nd6_una.py32
5 files changed, 287 insertions, 0 deletions
diff --git a/regress/sys/netinet6/nd6/Makefile b/regress/sys/netinet6/nd6/Makefile
new file mode 100644
index 00000000000..3b0d54a4585
--- /dev/null
+++ b/regress/sys/netinet6/nd6/Makefile
@@ -0,0 +1,111 @@
+# $OpenBSD: Makefile,v 1.1 2012/01/31 00:14:02 bluhm Exp $
+
+# The following ports must be installed:
+#
+# python-2.7 interpreted object-oriented programming language
+# py-libdnet python interface to libdnet
+# scapy powerful interactive packet manipulation in python
+
+# This test needs a manual setup of two machines
+# Set up machines: SRC DST
+# SRC is the machine where this makefile is running.
+# DST is running OpenBSD with pf to test the neighbor discovery states.
+#
+# +---+ 1 +---+
+# |SRC| ----> |DST|
+# +---+ +---+
+# out in
+
+# Configure Addresses on the machines.
+# Adapt interface and addresse variables to your local setup.
+#
+SRC_IF = tun0
+SRC_MAC = fe:e1:ba:d1:56:1f
+DST_MAC = 52:54:00:12:34:50
+
+SRC_OUT6 = fdd7:e83e:66bc:211:fce1:baff:fed1:561f
+DST_IN6 = fdd7:e83e:66bc:211:5054:ff:fe12:3450
+
+# pf rules on DST should look like this:
+#
+# block log
+# pass inet6 proto icmp6 icmp6-type echoreq keep state
+# pass inet6 proto icmp6 icmp6-type neighbrsol keep state
+# pass inet6 proto icmp6 icmp6-type neighbradv keep state
+
+# RFC 4861 7. describes the following test cases for ND:
+#
+# Duplicate Address Detection
+# - request NS from unspecified address to target solicitated-node multicast
+# - response NA from interface address to all-nodes multicast
+#
+# Address Resolution
+# - request NS from interface address to target solicitated-node multicast
+# - response NA from interface address to source of NS
+#
+# Unsolicited Neighbor Advertisements
+# - request NA from interface address to all-nodes multicast
+#
+# Neighbor Unreachability Detection
+# - request NS from interface address to target unicast
+# - response NA from interface address to source of NS
+
+depend: addr.py
+
+# Create python include file containing the addresses.
+addr.py: Makefile
+ rm -f $@ $@.tmp
+ echo 'SRC_IF = "${SRC_IF}"' >>$@.tmp
+ echo 'SRC_MAC = "${SRC_MAC}"' >>$@.tmp
+ echo 'DST_MAC = "${DST_MAC}"' >>$@.tmp
+.for var in SRC_OUT DST_IN
+ echo '${var} = "${${var}}"' >>$@.tmp
+ echo '${var}6 = "${${var}6}"' >>$@.tmp
+.endfor
+ mv $@.tmp $@
+
+# Clear neighbor cache and ping all addresses. This ensures that
+# the ip addresses are configured and all routing table are set up
+# to allow bidirectional packet flow.
+TARGETS += ping6
+run-regress-ping6:
+ @echo '\n======== $@ ========'
+ sudo ndp -c
+.for ip in SRC_OUT DST_IN
+ @echo Check ping6 ${ip}6:
+ ping6 -n -c 1 ${${ip}6}
+.endfor
+
+# Send hand-crafted duplicate address detection neighbor solicitation packet
+TARGETS += nd6_dad
+run-regress-nd6_dad: addr.py
+ @echo '\n======== $@ ========'
+ @echo Check duplicate address detection
+ ${SUDO} python2.7 nd6_dad.py
+
+# Send hand-crafted address resolution neighbor solicitation packet
+TARGETS += nd6_ar
+run-regress-nd6_ar: addr.py
+ @echo '\n======== $@ ========'
+ @echo Check address resolution
+ ${SUDO} python2.7 nd6_ar.py
+
+# Send hand-crafted unsolicited neighbor advertisement packet
+TARGETS += nd6_una
+run-regress-nd6_una: addr.py
+ @echo '\n======== $@ ========'
+ @echo Check unsolicited neighbor advertisement
+ ${SUDO} python2.7 nd6_una.py
+
+# Send hand-crafted neighbor unreachability detection solicitation packet
+TARGETS += nd6_nud
+run-regress-nd6_nud: addr.py
+ @echo '\n======== $@ ========'
+ @echo Check neighbor unreachability detection
+ ${SUDO} python2.7 nd6_nud.py
+
+REGRESS_TARGETS = ${TARGETS:S/^/run-regress-/}
+
+CLEANFILES += addr.py *.pyc *.log
+
+.include <bsd.regress.mk>
diff --git a/regress/sys/netinet6/nd6/nd6_ar.py b/regress/sys/netinet6/nd6/nd6_ar.py
new file mode 100644
index 00000000000..2c138951b9f
--- /dev/null
+++ b/regress/sys/netinet6/nd6/nd6_ar.py
@@ -0,0 +1,48 @@
+#!/usr/local/bin/python2.7
+# send Address Resolution neighbor solicitation
+# expect an neighbor advertisement answer and check it
+
+import os
+from addr import *
+from scapy.all import *
+
+# link-local solicited-node multicast address
+def nsma(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return inet_ntop(socket.AF_INET6, in6_getnsma(n))
+
+# ethernet multicast address of multicast address
+def nsmac(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return in6_getnsmac(n)
+
+# ethernet multicast address of solicited-node multicast address
+def nsmamac(a):
+ return nsmac(nsma(a))
+
+# link-local address
+def lla(m):
+ return "fe80::"+in6_mactoifaceid(m)
+
+ip=IPv6(src=SRC_OUT6, dst=nsma(DST_IN6))/ICMPv6ND_NS(tgt=DST_IN6)
+eth=Ether(src=SRC_MAC, dst=nsmamac(DST_IN6))/ip
+
+if os.fork() == 0:
+ time.sleep(1)
+ sendp(eth, iface=SRC_IF)
+ os._exit(0)
+
+ans=sniff(iface=SRC_IF, timeout=3, filter=
+ "ip6 and src "+DST_IN6+" and dst "+SRC_OUT6+" and icmp6")
+for a in ans:
+ if a and a.type == scapy.layers.dot11.ETHER_TYPES.IPv6 and \
+ ipv6nh[a.payload.nh] == 'ICMPv6' and \
+ icmp6types[a.payload.payload.type] == 'Neighbor Advertisement':
+ tgt=a.payload.payload.tgt
+ print "target=%s" % (tgt)
+ if tgt == DST_IN6:
+ exit(0)
+ print "TARGET!=%s" % (DST_IN6)
+ exit(1)
+print "NO NEIGHBOR ADVERTISEMENT"
+exit(2)
diff --git a/regress/sys/netinet6/nd6/nd6_dad.py b/regress/sys/netinet6/nd6/nd6_dad.py
new file mode 100644
index 00000000000..054b06f0864
--- /dev/null
+++ b/regress/sys/netinet6/nd6/nd6_dad.py
@@ -0,0 +1,48 @@
+#!/usr/local/bin/python2.7
+# send Duplicate Address Detection neighbor solicitation
+# expect an neighbor advertisement answer and check it
+
+import os
+from addr import *
+from scapy.all import *
+
+# link-local solicited-node multicast address
+def nsma(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return inet_ntop(socket.AF_INET6, in6_getnsma(n))
+
+# ethernet multicast address of multicast address
+def nsmac(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return in6_getnsmac(n)
+
+# ethernet multicast address of solicited-node multicast address
+def nsmamac(a):
+ return nsmac(nsma(a))
+
+# link-local address
+def lla(m):
+ return "fe80::"+in6_mactoifaceid(m)
+
+ip=IPv6(src="::", dst=nsma(DST_IN6))/ICMPv6ND_NS(tgt=DST_IN6)
+eth=Ether(src=SRC_MAC, dst=nsmamac(DST_IN6))/ip
+
+if os.fork() == 0:
+ time.sleep(1)
+ sendp(eth, iface=SRC_IF)
+ os._exit(0)
+
+ans=sniff(iface=SRC_IF, timeout=3, filter=
+ "ip6 and src "+lla(DST_MAC)+" and dst ff02::1 and icmp6")
+for a in ans:
+ if a and a.type == scapy.layers.dot11.ETHER_TYPES.IPv6 and \
+ ipv6nh[a.payload.nh] == 'ICMPv6' and \
+ icmp6types[a.payload.payload.type] == 'Neighbor Advertisement':
+ tgt=a.payload.payload.tgt
+ print "target=%s" % (tgt)
+ if tgt == DST_IN6:
+ exit(0)
+ print "TARGET!=%s" % (DST_IN6)
+ exit(1)
+print "NO NEIGHBOR ADVERTISEMENT"
+exit(2)
diff --git a/regress/sys/netinet6/nd6/nd6_nud.py b/regress/sys/netinet6/nd6/nd6_nud.py
new file mode 100644
index 00000000000..b7a7c1a9cf0
--- /dev/null
+++ b/regress/sys/netinet6/nd6/nd6_nud.py
@@ -0,0 +1,48 @@
+#!/usr/local/bin/python2.7
+# send Neighbor Unreachability Detection neighbor solicitation
+# expect an neighbor advertisement answer and check it
+
+import os
+from addr import *
+from scapy.all import *
+
+# link-local solicited-node multicast address
+def nsma(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return inet_ntop(socket.AF_INET6, in6_getnsma(n))
+
+# ethernet multicast address of multicast address
+def nsmac(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return in6_getnsmac(n)
+
+# ethernet multicast address of solicited-node multicast address
+def nsmamac(a):
+ return nsmac(nsma(a))
+
+# link-local address
+def lla(m):
+ return "fe80::"+in6_mactoifaceid(m)
+
+ip=IPv6(src=SRC_OUT6, dst=DST_IN6)/ICMPv6ND_NS(tgt=DST_IN6)
+eth=Ether(src=SRC_MAC, dst=DST_MAC)/ip
+
+if os.fork() == 0:
+ time.sleep(1)
+ sendp(eth, iface=SRC_IF)
+ os._exit(0)
+
+ans=sniff(iface=SRC_IF, timeout=3, filter=
+ "ip6 and src "+DST_IN6+" and dst "+SRC_OUT6+" and icmp6")
+for a in ans:
+ if a and a.type == scapy.layers.dot11.ETHER_TYPES.IPv6 and \
+ ipv6nh[a.payload.nh] == 'ICMPv6' and \
+ icmp6types[a.payload.payload.type] == 'Neighbor Advertisement':
+ tgt=a.payload.payload.tgt
+ print "target=%s" % (tgt)
+ if tgt == DST_IN6:
+ exit(0)
+ print "TARGET!=%s" % (DST_IN6)
+ exit(1)
+print "NO NEIGHBOR ADVERTISEMENT"
+exit(2)
diff --git a/regress/sys/netinet6/nd6/nd6_una.py b/regress/sys/netinet6/nd6/nd6_una.py
new file mode 100644
index 00000000000..a190a07c1ab
--- /dev/null
+++ b/regress/sys/netinet6/nd6/nd6_una.py
@@ -0,0 +1,32 @@
+#!/usr/local/bin/python2.7
+# send Unsolicited Neighbor Advertisement
+
+import os
+from addr import *
+from scapy.all import *
+
+# link-local solicited-node multicast address
+def nsma(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return inet_ntop(socket.AF_INET6, in6_getnsma(n))
+
+# ethernet multicast address of multicast address
+def nsmac(a):
+ n = inet_pton(socket.AF_INET6, a)
+ return in6_getnsmac(n)
+
+# ethernet multicast address of solicited-node multicast address
+def nsmamac(a):
+ return nsmac(nsma(a))
+
+# link-local address
+def lla(m):
+ return "fe80::"+in6_mactoifaceid(m)
+
+ip=IPv6(src=lla(SRC_MAC), dst="ff02::1")/ICMPv6ND_NA(tgt=SRC_OUT6)
+eth=Ether(src=SRC_MAC, dst=nsmac("ff02::1"))/ip
+
+sendp(eth, iface=SRC_IF)
+time.sleep(1)
+
+exit(0)