summaryrefslogtreecommitdiff
path: root/regress/sys/netinet6/rip6cksum
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2019-05-09 15:54:32 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2019-05-09 15:54:32 +0000
commite1c4560cd38d5d58c43de18b85398b61eb1bc0a9 (patch)
tree238c333fe37657f08c4af542813dd1f2ec369f87 /regress/sys/netinet6/rip6cksum
parentddaf007d2ca1ad97fc037cf902214116abcae919 (diff)
Test IPv6 raw sockets with checksum calculation in kernel.
Diffstat (limited to 'regress/sys/netinet6/rip6cksum')
-rw-r--r--regress/sys/netinet6/rip6cksum/LICENSE15
-rw-r--r--regress/sys/netinet6/rip6cksum/Makefile137
-rw-r--r--regress/sys/netinet6/rip6cksum/README6
-rw-r--r--regress/sys/netinet6/rip6cksum/rip6cksum.c202
-rwxr-xr-xregress/sys/netinet6/rip6cksum/sendrecv.py94
5 files changed, 454 insertions, 0 deletions
diff --git a/regress/sys/netinet6/rip6cksum/LICENSE b/regress/sys/netinet6/rip6cksum/LICENSE
new file mode 100644
index 00000000000..897cd3e6996
--- /dev/null
+++ b/regress/sys/netinet6/rip6cksum/LICENSE
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
diff --git a/regress/sys/netinet6/rip6cksum/Makefile b/regress/sys/netinet6/rip6cksum/Makefile
new file mode 100644
index 00000000000..0ee1e197d6f
--- /dev/null
+++ b/regress/sys/netinet6/rip6cksum/Makefile
@@ -0,0 +1,137 @@
+# $OpenBSD: Makefile,v 1.1.1.1 2019/05/09 15:54:31 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
+
+.if ! exists(/usr/local/bin/python2) || ! exists(/usr/local/bin/scapy)
+regress:
+ @echo Install python and the scapy module for additional tests.
+ @echo SKIPPED
+.endif
+
+PROG = rip6cksum
+WARNINGS = yes
+
+REGRESS_TARGETS += run-error-negative
+run-error-negative:
+ @echo "\n======== $@ ========"
+ # set socket option IPV6_CHECKSUM to -2, expect error
+ ${SUDO} ./rip6cksum -c -2 -e
+
+REGRESS_TARGETS += run-error-odd
+run-error-odd:
+ @echo "\n======== $@ ========"
+ # set socket option IPV6_CHECKSUM to 1, expect error
+ ${SUDO} ./rip6cksum -c 1 -e
+
+REGRESS_TARGETS += run-no-cksum
+run-no-cksum:
+ # send and receive packet without checksum
+ @echo "\n======== $@ ========"
+ ${SUDO} ./rip6cksum -r 32 -s 8 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -r 8 -s 32
+
+REGRESS_TARGETS += run-bad-cksum
+run-bad-cksum:
+ # enable checksum, send packet without checksum, expect icmp
+ @echo "\n======== $@ ========"
+ ${SUDO} ./rip6cksum -c 0 -- \
+ python2 -u ${.CURDIR}/sendrecv.py -i -r 32 -s 32
+
+REGRESS_TARGETS += run-disable-cksum
+run-disable-cksum:
+ # send and receive packet with explicitly disabled checksum
+ @echo "\n======== $@ ========"
+ ${SUDO} ./rip6cksum -c -1 -r 32 -s 8 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -r 8 -s 32
+
+REGRESS_TARGETS += run-ckoff-0
+run-ckoff-0:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 0
+ ${SUDO} ./rip6cksum -c 0 -r 32 -s 8 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -c 0 -r 8 -s 32
+
+REGRESS_TARGETS += run-ckoff-0-empty
+run-ckoff-0-empty:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 0, but packet is empty, expect icmp
+ ${SUDO} ./rip6cksum -c 0 -- \
+ python2 -u ${.CURDIR}/sendrecv.py -i -r 0 -s 0
+
+REGRESS_TARGETS += run-ckoff-0-short
+run-ckoff-0-short:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 0, but packet is only 1 byte long, expect icmp
+ ${SUDO} ./rip6cksum -c 0 -- \
+ python2 -u ${.CURDIR}/sendrecv.py -i -r 1 -s 1
+
+REGRESS_TARGETS += run-ckoff-0-exact
+run-ckoff-0-exact:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 0, packet is exactly 2 bytes long
+ ${SUDO} ./rip6cksum -c 0 -r 2 -s 2 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -c 0 -s 2
+
+REGRESS_TARGETS += run-ckoff-0-long
+run-ckoff-0-long:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 0, packet is 3 bytes long
+ ${SUDO} ./rip6cksum -c 0 -r 3 -s 3 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -c 0 -s 3
+
+REGRESS_TARGETS += run-ckoff-2
+run-ckoff-2:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 2
+ ${SUDO} ./rip6cksum -c 2 -r 32 -s 8 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -c 2 -r 8 -s 32
+
+REGRESS_TARGETS += run-ckoff-2-empty
+run-ckoff-2-empty:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 2, but packet is empty, expect icmp
+ ${SUDO} ./rip6cksum -c 2 -- \
+ python2 -u ${.CURDIR}/sendrecv.py -i -r 0 -s 0
+
+REGRESS_TARGETS += run-ckoff-2-short-1
+run-ckoff-2-short-1:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 2, but packet is only 1 byte long, expect icmp
+ ${SUDO} ./rip6cksum -c 2 -- \
+ python2 -u ${.CURDIR}/sendrecv.py -i -r 1 -s 1
+
+REGRESS_TARGETS += run-ckoff-2-short-2
+run-ckoff-2-short-2:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 2, but packet is only 2 byte long, expect icmp
+ ${SUDO} ./rip6cksum -c 2 -- \
+ python2 -u ${.CURDIR}/sendrecv.py -i -r 2 -s 2
+
+REGRESS_TARGETS += run-ckoff-2-short-3
+run-ckoff-2-short-3:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 2, but packet is only 3 byte long, expect icmp
+ ${SUDO} ./rip6cksum -c 2 -- \
+ python2 -u ${.CURDIR}/sendrecv.py -i -r 3 -s 3
+
+REGRESS_TARGETS += run-ckoff-2-exact
+run-ckoff-2-exact:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 2, packet is exactly 4 bytes long
+ ${SUDO} ./rip6cksum -c 2 -r 4 -s 4 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -c 2 -s 4
+
+REGRESS_TARGETS += run-ckoff-2-long
+run-ckoff-2-long:
+ @echo "\n======== $@ ========"
+ # use checksum at offset 2, packet is 5 bytes long
+ ${SUDO} ./rip6cksum -c 2 -r 5 -s 5 -w -- \
+ python2 -u ${.CURDIR}/sendrecv.py -c 2 -s 5
+
+${REGRESS_TARGETS}: ${PROG}
+
+.include <bsd.regress.mk>
diff --git a/regress/sys/netinet6/rip6cksum/README b/regress/sys/netinet6/rip6cksum/README
new file mode 100644
index 00000000000..4635b5c60b2
--- /dev/null
+++ b/regress/sys/netinet6/rip6cksum/README
@@ -0,0 +1,6 @@
+Test IPv6 raw sockets with checksum calculation in kernel.
+
+The C program rip6cksum creates a raw socket, binds and connects
+it, and sets the checksum option. Then it forks the scapy program
+sendrecv. It sends a protocol 255 packet and expects an answer or
+ICMP6 error.
diff --git a/regress/sys/netinet6/rip6cksum/rip6cksum.c b/regress/sys/netinet6/rip6cksum/rip6cksum.c
new file mode 100644
index 00000000000..7a701055462
--- /dev/null
+++ b/regress/sys/netinet6/rip6cksum/rip6cksum.c
@@ -0,0 +1,202 @@
+/* $OpenBSD: rip6cksum.c,v 1.1.1.1 2019/05/09 15:54:31 bluhm Exp $ */
+/*
+ * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+void __dead usage(void);
+
+void __dead
+usage(void)
+{
+ fprintf(stderr, "rip6cksum [-ehw] [-c ckoff] [-r recvsz] [-s sendsz] "
+ "[-- scapy ...]\n"
+ " -c ckoff set checksum offset within rip header\n"
+ " -e expect error when setting ckoff\n"
+ " -h help, show usage\n"
+ " -r recvsz expected payload size from socket\n"
+ " -s sendsz send payload of given size to socket\n"
+ " -w wait for packet on socket, timeout 10 seconds\n"
+ " scapy ... run scapy program after socket setup\n"
+ );
+ exit(1);
+}
+
+const struct in6_addr loop6 = IN6ADDR_LOOPBACK_INIT;
+int
+main(int argc, char *argv[])
+{
+ int s, ch, eflag, cflag, rflag, sflag, wflag;
+ int ckoff;
+ size_t recvsz, sendsz;
+ const char *errstr;
+ struct sockaddr_in6 sin6;
+
+ if (setvbuf(stdout, NULL, _IOLBF, 0) != 0)
+ err(1, "setvbuf stdout line buffered");
+
+ eflag = cflag = rflag = sflag = wflag = 0;
+ while ((ch = getopt(argc, argv, "c:ehr:s:w")) != -1) {
+ switch (ch) {
+ case 'c':
+ ckoff = strtonum(optarg, INT_MIN, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "ckoff is %s: %s", errstr, optarg);
+ cflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'r':
+ recvsz = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "recvsz is %s: %s", errstr, optarg);
+ rflag = 1;
+ break;
+ case 's':
+ sendsz = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "sendsz is %s: %s", errstr, optarg);
+ sflag = 1;
+ break;
+ case 'w':
+ wflag = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ printf("socket inet6 raw 255\n");
+ s = socket(AF_INET6, SOCK_RAW, 255);
+ if (s == -1)
+ err(1, "socket raw");
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = loop6;
+ printf("bind ::1\n");
+ if (bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) == -1)
+ err(1, "bind ::1");
+ printf("connect ::1\n");
+ if (connect(s, (struct sockaddr *)&sin6, sizeof(sin6)) == -1)
+ err(1, "connect ::1");
+
+ if (cflag) {
+ printf("setsockopt ipv6 checksum %d\n", ckoff);
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_CHECKSUM, &ckoff,
+ sizeof(ckoff)) == -1) {
+ if (!eflag)
+ err(1, "setsockopt ckoff");
+ printf("setsockopt failed as expected: %s\n",
+ strerror(errno));
+ } else {
+ if (eflag)
+ errx(1, "setsockopt succeeded unexpectedly");
+ }
+ }
+
+ if (argc) {
+ pid_t pid;
+
+ printf("fork child process\n");
+ pid = fork();
+ if (pid == -1)
+ err(1, "fork");
+ if (pid == 0) {
+ /* child */
+ printf("execute %s\n", argv[0]);
+ execvp(argv[0], argv);
+ err(1, "execvp %s", argv[0]);
+ }
+ printf("child pid %d\n", pid);
+ }
+
+ if (wflag) {
+ int n;
+ ssize_t r;
+ size_t rsz;
+ fd_set fds;
+ struct timeval to;
+ char buf[1<<16];
+
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ to.tv_sec = 10;
+ to.tv_usec = 0;
+ printf("select socket read\n");
+ n = select(s + 1, &fds, NULL, NULL, &to);
+ switch (n) {
+ case -1:
+ err(1, "select");
+ case 0:
+ errx(1, "timeout");
+ default:
+ printf("selected %d\n", n);
+ }
+ printf("recv packet\n");
+ r = recv(s, buf, sizeof(buf), 0);
+ if (r < 0)
+ err(1, "recv");
+ rsz = r;
+ printf("received payload size %zd\n", rsz);
+ if (rflag) {
+ if (rsz != recvsz)
+ errx(1, "wrong payload size, expected %zu", recvsz);
+ }
+ }
+
+ if (sflag) {
+ size_t i;
+ char *buf;
+
+ buf = malloc(sendsz);
+ if (buf == NULL)
+ err(1, "malloc sendsz");
+ for (i = 0; i < sendsz; i++)
+ buf[i] = i & 0xff;
+ printf("send payload of size %zu\n", sendsz);
+ if (send(s, buf, sendsz, 0) == -1)
+ err(1, "send");
+ free(buf);
+ }
+
+ if (argc) {
+ int status;
+
+ printf("wait for child\n");
+ if (wait(&status) == -1)
+ err(1, "wait");
+ if (status != 0)
+ errx(1, "child program %s status %d", argv[0], status);
+ printf("child program %s status %d\n", argv[0], status);
+ }
+
+ return 0;
+}
diff --git a/regress/sys/netinet6/rip6cksum/sendrecv.py b/regress/sys/netinet6/rip6cksum/sendrecv.py
new file mode 100755
index 00000000000..d02fb7d8e40
--- /dev/null
+++ b/regress/sys/netinet6/rip6cksum/sendrecv.py
@@ -0,0 +1,94 @@
+#!/usr/local/bin/python2.7
+# $OpenBSD: sendrecv.py,v 1.1.1.1 2019/05/09 15:54:31 bluhm Exp $
+
+import os
+from scapy.all import *
+from struct import pack
+import getopt, sys
+
+def usage():
+ print "raw6-sendrecv [-hi] [-c ckoff] [-r recvsz] [-s sendsz]"
+ print " -c ckoff set checksum offset within payload"
+ print " -h help, show usage"
+ print " -i expect icmp6 error message as response"
+ print " -r recvsz expected payload size"
+ print " -s sendsz set payload size"
+ exit(1)
+
+opts, args = getopt.getopt(sys.argv[1:], "c:hir:s:")
+
+ip = IPv6(src="::1", dst="::1", nh=255)
+
+ckoff = None
+icmp = False
+recvsz = None
+sendsz = None
+for o, a in opts:
+ if o == "-c":
+ ckoff = int(a)
+ elif o == "-i":
+ icmp = True
+ elif o == "-r":
+ recvsz = int(a)
+ elif o == "-s":
+ sendsz = int(a)
+ else:
+ usage()
+
+payload = "";
+if sendsz is not None:
+ for i in range(sendsz):
+ payload += chr(i & 0xff)
+ print "payload length is", len(payload)
+
+if ckoff is not None:
+ payload = payload[:ckoff] + pack("xx") + payload[ckoff+2:]
+ cksum = in6_chksum(255, ip, payload)
+ print "calculated checksum is", cksum
+ payload = payload[:ckoff] + pack("!H", cksum) + payload[ckoff+2:]
+
+req=ip/payload
+# As we are sending from ::1 to ::1 we sniff our own packet as answer.
+# Add a filter that matches on the expected answer using the payload size.
+if icmp:
+ filter="icmp6"
+ if recvsz is not None:
+ filter += (" and len = %d" % (4 + 40 + 8 + 40 + recvsz))
+else:
+ filter="proto 255"
+ if recvsz is not None:
+ filter += (" and len = %d" % (4 + 40 + recvsz))
+print "filter", filter
+ans=sr(req, iface="lo0", filter=filter, timeout=10)
+print ans
+res=ans[0][0][1]
+res.show()
+
+print "response protocol next header is", res.nh
+if icmp:
+ if res.nh != 58:
+ print "response wrong protocol, expected icmp6"
+ exit(1)
+ print "response icmp6 type is", res.payload.type
+ if res.payload.type != 4:
+ print "response wrong icmp6 type, expected parameter problem"
+ exit(1)
+ exit(0)
+
+if res.nh != 255:
+ print "response with wrong protocol, expected 255, got"
+ exit(1)
+
+cksum = in6_chksum(255, res, res.payload.load)
+print "received checksum is", cksum
+if ckoff is not None and cksum != 0:
+ print "received invalid checksum", cksum
+ exit(1)
+
+print "received payload length is", len(res.payload.load)
+if recvsz is not None:
+ if len(res.payload.load) != recvsz:
+ print "wrong payload length, expected", recvsz
+ exit(1)
+
+exit(0)