diff options
author | 2020-01-16 21:11:17 +0000 | |
---|---|---|
committer | 2020-01-16 21:11:17 +0000 | |
commit | d80889b64d867b81cba72762c7c90972967e5ef6 (patch) | |
tree | ced387e9732ce8a474d27330099fd586e0d024c8 | |
parent | Add sub test for ftpd(8) that test delete of files. (diff) | |
download | wireguard-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/Makefile | 49 | ||||
-rw-r--r-- | regress/usr.bin/nc/client-tcp.c | 125 | ||||
-rw-r--r-- | regress/usr.bin/nc/server-tcp.c | 158 | ||||
-rw-r--r-- | regress/usr.bin/nc/util.c | 135 | ||||
-rw-r--r-- | regress/usr.bin/nc/util.h | 23 |
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 *); |