summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbluhm <bluhm@openbsd.org>2020-01-16 21:11:17 +0000
committerbluhm <bluhm@openbsd.org>2020-01-16 21:11:17 +0000
commitd80889b64d867b81cba72762c7c90972967e5ef6 (patch)
treeced387e9732ce8a474d27330099fd586e0d024c8
parentAdd sub test for ftpd(8) that test delete of files. (diff)
downloadwireguard-openbsd-d80889b64d867b81cba72762c7c90972967e5ef6.tar.xz
wireguard-openbsd-d80889b64d867b81cba72762c7c90972967e5ef6.zip
Implement custom TCP client and server to test netcat corner cases.
-rw-r--r--regress/usr.bin/nc/Makefile49
-rw-r--r--regress/usr.bin/nc/client-tcp.c125
-rw-r--r--regress/usr.bin/nc/server-tcp.c158
-rw-r--r--regress/usr.bin/nc/util.c135
-rw-r--r--regress/usr.bin/nc/util.h23
5 files changed, 487 insertions, 3 deletions
diff --git a/regress/usr.bin/nc/Makefile b/regress/usr.bin/nc/Makefile
index f94bd2bb2bc..30ae4b825cf 100644
--- a/regress/usr.bin/nc/Makefile
+++ b/regress/usr.bin/nc/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.3 2020/01/08 13:23:48 bluhm Exp $
+# $OpenBSD: Makefile,v 1.4 2020/01/16 21:11:17 bluhm Exp $
# Copyright (c) 2020 Alexander Bluhm <bluhm@openbsd.org>
#
@@ -14,6 +14,11 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+PROGS = client-tcp server-tcp
+SRCS_client-tcp = client-tcp.c util.c
+SRCS_server-tcp = server-tcp.c util.c
+WARNINGS = yes
+
NC = ./netcat-regress
CLEANFILES = ${NC:T} {client,server}.{out,err,port,sock} ktrace.out
@@ -23,6 +28,7 @@ setup:
@echo '======== $@ ========'
pkill ${NC:T} || true
rm -f ${NC:T}
+ # copying global netcat to local name allows to pkill it during cleanup
cp /usr/bin/nc ${NC:T}
chmod 755 ${NC:T}
@@ -74,6 +80,11 @@ TRANSFER_WAIT = \
until grep -q 'greeting' client.out && grep -q 'command' server.out; \
do [[ `date +%s` -lt $$timeout ]] || { echo timeout; exit 1; }; done
+TRANSFER_CLIENT_WAIT = \
+ let timeout=`date +%s`+5; \
+ until grep -q 'greeting' client.out; \
+ do [[ `date +%s` -lt $$timeout ]] || { echo timeout; exit 1; }; done
+
TRANSFER_SERVER_WAIT = \
let timeout=`date +%s`+5; \
until grep -q 'command' server.out; \
@@ -438,7 +449,7 @@ run-tls-bad-client: client.crt server.crt ca.crt
! grep 'command' server.out
REGRESS_TARGETS += run-tls-client-bad-ca
-run-tls-client-bad-ca: client.crt server.crt ca.crt
+run-tls-client-bad-ca: client.crt server.crt ca.crt fake-ca.crt
@echo '======== $@ ========'
# the server uses the wrong root ca to verify the client cert
${SERVER_NC} -c -R fake-ca.crt -C server.crt -K server.key -v -l \
@@ -452,7 +463,9 @@ run-tls-client-bad-ca: client.crt server.crt ca.crt
grep 'Connection received on localhost ' server.err
grep 'Connection to localhost .* succeeded!' client.err
# XXX no specific error message for bogus ca
- grep 'CRYPTO_internal:block type is not 01' server.err
+ egrep \
+ 'CRYPTO_internal:(block type is not 01|data too large for modulus)'\
+ server.err
! grep 'greeting' client.out
! grep 'command' server.out
@@ -880,6 +893,36 @@ run-unix-dgram-keep:
# XXX message succeeded is missing
! grep 'Connection to 127.0.0.1 .* succeeded!' client.err
+### TCP with custom peer
+
+REGRESS_TARGETS += run-tcp-custom
+run-tcp-custom: server-tcp client-tcp
+ @echo '======== $@ ========'
+ ./server-tcp -s greeting -r command 127.0.0.1 0 >server.port
+ ./client-tcp -r greeting -s command 127.0.0.1 ${PORT}
+
+REGRESS_TARGETS += run-tcp-server
+run-tcp-server: client-tcp
+ @echo '======== $@ ========'
+ ${SERVER_NC} -n -v -l 127.0.0.1 0 ${SERVER_BG}
+ ${LISTEN_WAIT}
+ ${PORT_GET}
+ ./client-tcp -r greeting -s command 127.0.0.1 ${PORT}
+ ${TRANSFER_SERVER_WAIT}
+ grep '^command$$' server.out
+ grep 'Listening on 127.0.0.1 ' server.err
+ grep 'Connection received on 127.0.0.1 ' server.err
+
+REGRESS_TARGETS += run-tcp-client
+run-tcp-client: server-tcp
+ @echo '======== $@ ========'
+ ./server-tcp -s greeting -r command 127.0.0.1 0 >server.port
+ ${CLIENT_NC} -n -v 127.0.0.1 ${PORT} ${CLIENT_BG}
+ ${CONNECT_WAIT}
+ ${TRANSFER_CLIENT_WAIT}
+ grep '^greeting$$' client.out
+ grep 'Connection to 127.0.0.1 .* succeeded!' client.err
+
.PHONY: ${REGRESS_SETUP} ${REGRESS_CLEANUP} ${REGRESS_TARGETS}
### create certificates for TLS
diff --git a/regress/usr.bin/nc/client-tcp.c b/regress/usr.bin/nc/client-tcp.c
new file mode 100644
index 00000000000..09938848409
--- /dev/null
+++ b/regress/usr.bin/nc/client-tcp.c
@@ -0,0 +1,125 @@
+/* $OpenBSD: client-tcp.c,v 1.1 2020/01/16 21:11:17 bluhm Exp $ */
+
+/*
+ * Copyright (c) 2020 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+void __dead usage(void);
+int connect_socket(const char *, const char *);
+
+void __dead
+usage(void)
+{
+ fprintf(stderr, "client [-r rcvmsg] [-s sndmsg] host port\n"
+ " -r rcvmsg receive from server and check message\n"
+ " -s sndmsg send message to server\n");
+ exit(2);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *host, *port;
+ const char *rcvmsg = NULL, *sndmsg = NULL;
+ int ch, s;
+
+ while ((ch = getopt(argc, argv, "r:s:")) != -1) {
+ switch (ch) {
+ case 'r':
+ rcvmsg = optarg;
+ break;
+ case 's':
+ sndmsg = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 2) {
+ host = argv[0];
+ port = argv[1];
+ } else {
+ usage();
+ }
+
+ alarm_timeout();
+ s = connect_socket(host, port);
+ print_sockname(s);
+ print_peername(s);
+ if (rcvmsg != NULL)
+ receive_line(s, rcvmsg);
+ if (sndmsg != NULL)
+ send_line(s, sndmsg);
+
+ if (close(s) == -1)
+ err(1, "close");
+
+ return 0;
+}
+
+int
+connect_socket(const char *host, const char *port)
+{
+ struct addrinfo hints, *res, *res0;
+ int error;
+ int save_errno;
+ int s;
+ const char *cause = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(host, port, &hints, &res0);
+ if (error)
+ errx(1, "%s", gai_strerror(error));
+ s = -1;
+ for (res = res0; res; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s == -1) {
+ cause = "socket";
+ continue;
+ }
+ if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
+ cause = "connect";
+ save_errno = errno;
+ close(s);
+ errno = save_errno;
+ s = -1;
+ continue;
+ }
+ break; /* okay we got one */
+ }
+ if (s == -1)
+ err(1, "%s", cause);
+ freeaddrinfo(res0);
+
+ return s;
+}
diff --git a/regress/usr.bin/nc/server-tcp.c b/regress/usr.bin/nc/server-tcp.c
new file mode 100644
index 00000000000..07a2a49500d
--- /dev/null
+++ b/regress/usr.bin/nc/server-tcp.c
@@ -0,0 +1,158 @@
+/* $OpenBSD: server-tcp.c,v 1.1 2020/01/16 21:11:17 bluhm Exp $ */
+
+/*
+ * Copyright (c) 2020 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+void __dead usage(void);
+int listen_socket(const char *, const char *);
+int accept_socket(int);
+
+void __dead
+usage(void)
+{
+ fprintf(stderr, "server-tcp [-r rcvmsg] [-s sndmsg] host port\n"
+ " -r rcvmsg receive from client and check message\n"
+ " -s sndmsg send message to client\n");
+ exit(2);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *host, *port;
+ const char *rcvmsg = NULL, *sndmsg = NULL;
+ int ch, s;
+
+ while ((ch = getopt(argc, argv, "r:s:")) != -1) {
+ switch (ch) {
+ case 'r':
+ rcvmsg = optarg;
+ break;
+ case 's':
+ sndmsg = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 2) {
+ host = argv[0];
+ port = argv[1];
+ } else {
+ usage();
+ }
+
+ alarm_timeout();
+ s = listen_socket(host, port);
+ print_sockname(s);
+
+ switch (fork()) {
+ case -1:
+ err(1, "fork");
+ case 0:
+ /* child continues */
+ break;
+ default:
+ /* parent exits and test runs in parallel */
+ _exit(0);
+ }
+
+ s = accept_socket(s);
+ if (sndmsg != NULL)
+ send_line(s, sndmsg);
+ if (rcvmsg != NULL)
+ receive_line(s, rcvmsg);
+
+ if (close(s) == -1)
+ err(1, "close");
+
+ return 0;
+}
+
+int
+listen_socket(const char *host, const char *port)
+{
+ struct addrinfo hints, *res, *res0;
+ int error;
+ int save_errno;
+ int s;
+ const char *cause = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ error = getaddrinfo(host, port, &hints, &res0);
+ if (error)
+ errx(1, "%s", gai_strerror(error));
+ for (res = res0; res; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s == -1) {
+ cause = "socket";
+ continue;
+ }
+ if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
+ cause = "bind";
+ save_errno = errno;
+ close(s);
+ errno = save_errno;
+ continue;
+ }
+ break; /* okay we got one */
+ }
+ if (s == -1)
+ err(1, "%s", cause);
+ freeaddrinfo(res0);
+
+ if (listen(s, 5) == -1)
+ err(1, "listen");
+ return s;
+}
+
+int
+accept_socket(int s)
+{
+ struct sockaddr_storage ss;
+ socklen_t slen;
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+
+ slen = sizeof(ss);
+ s = accept(s, (struct sockaddr *)&ss, &slen);
+ if (s == -1)
+ err(1, "accept");
+ if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
+ errx(1, "getnameinfo");
+ fprintf(stderr, "peer: %s %s\n", host, port);
+
+ return s;
+}
diff --git a/regress/usr.bin/nc/util.c b/regress/usr.bin/nc/util.c
new file mode 100644
index 00000000000..ac96190fc8d
--- /dev/null
+++ b/regress/usr.bin/nc/util.c
@@ -0,0 +1,135 @@
+/* $OpenBSD: util.c,v 1.1 2020/01/16 21:11:17 bluhm Exp $ */
+
+/*
+ * Copyright (c) 2020 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+void
+alarm_timeout(void)
+{
+ /* just abort after 10 seconds */
+ if ((int)alarm(10) == -1)
+ err(1, "alarm");
+}
+
+void
+print_sockname(int s)
+{
+ struct sockaddr_storage ss;
+ socklen_t slen;
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+
+ slen = sizeof(ss);
+ if (getsockname(s, (struct sockaddr *)&ss, &slen) == -1)
+ err(1, "getsockname");
+ if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
+ errx(1, "getnameinfo");
+ printf("%s\n", port);
+ if (fflush(stdout) != 0)
+ err(1, "fflush stdout");
+ fprintf(stderr, "sock: %s %s\n", host, port);
+}
+
+void
+print_peername(int s)
+{
+ struct sockaddr_storage ss;
+ socklen_t slen;
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+
+ slen = sizeof(ss);
+ if (getpeername(s, (struct sockaddr *)&ss, &slen) == -1)
+ err(1, "getpeername");
+ if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, sizeof(host),
+ port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV))
+ errx(1, "getnameinfo");
+ fprintf(stderr, "peer: %s %s\n", host, port);
+}
+
+void
+receive_line(int s, const char *msg)
+{
+ char buf[100];
+ size_t off, len;
+ ssize_t n;
+
+ len = 0;
+ while (len < sizeof(buf)) {
+ off = len;
+ n = recv(s, buf + off, sizeof(buf) - off, 0);
+ if (n == -1)
+ err(1, "recv");
+ if (n == 0) {
+ fprintf(stderr, "<<< EOF\n");
+ break;
+ }
+ len += n;
+ buf[len] = '\0';
+ if (buf[len - 1] == '\n')
+ fprintf(stderr, "<<< %s", buf + off);
+ else
+ fprintf(stderr, "<<< %s\n", buf + off);
+ if (strchr(buf + off, '\n') != NULL)
+ break;
+ }
+ if (len == 0)
+ errx(1, "empty receive buffer");
+ if (buf[len - 1] != '\n')
+ errx(1, "new line missing in receive buffer");
+ buf[--len] = '\0';
+ if (strcmp(msg, buf) != 0)
+ errx(1, "expected receive '%s', got '%s'", msg, buf);
+}
+
+void
+send_line(int s, const char *msg)
+{
+ char buf[100];
+ size_t off, len;
+ ssize_t n;
+
+ len = strlcpy(buf, msg, sizeof(buf));
+ if (len >= sizeof(buf))
+ errx(1, "message too long for send buffer");
+ if (buf[len] != '\n') {
+ buf[len++] = '\n';
+ if (len >= sizeof(buf))
+ errx(1, "new line too long for send buffer");
+ buf[len] = 0;
+ }
+
+ off = 0;
+ while (off < len) {
+ fprintf(stderr, ">>> %s", buf + off);
+ n = send(s, buf + off, len - off, 0);
+ if (n == -1)
+ err(1, "send");
+ off += n;
+ }
+}
diff --git a/regress/usr.bin/nc/util.h b/regress/usr.bin/nc/util.h
new file mode 100644
index 00000000000..f70b6865ac7
--- /dev/null
+++ b/regress/usr.bin/nc/util.h
@@ -0,0 +1,23 @@
+/* $OpenBSD: util.h,v 1.1 2020/01/16 21:11:17 bluhm Exp $ */
+
+/*
+ * Copyright (c) 2020 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.
+ */
+
+void alarm_timeout(void);
+void print_sockname(int);
+void print_peername(int);
+void receive_line(int, const char *);
+void send_line(int, const char *);