From cd2524f09be30847939156745d135fedabc4a01f Mon Sep 17 00:00:00 2001 From: Alexander Bluhm Date: Wed, 8 Feb 2017 13:43:34 +0000 Subject: Due to non-blocking sockets, tls_handshake() could wait in a busy loop. Use an additional poll(2) during the handshake and also respect the -w timeout option there. From Shuo Chen; OK beck@ --- usr.bin/nc/netcat.c | 63 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 21 deletions(-) (limited to 'usr.bin') diff --git a/usr.bin/nc/netcat.c b/usr.bin/nc/netcat.c index 5a6cb9dadd4..8984e8f3035 100644 --- a/usr.bin/nc/netcat.c +++ b/usr.bin/nc/netcat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: netcat.c,v 1.172 2017/02/05 01:39:14 jca Exp $ */ +/* $OpenBSD: netcat.c,v 1.173 2017/02/08 13:43:33 bluhm Exp $ */ /* * Copyright (c) 2001 Eric Jackson * Copyright (c) 2015 Bob Beck. All rights reserved. @@ -121,6 +121,7 @@ int local_listen(char *, char *, struct addrinfo); void readwrite(int, struct tls *); void fdpass(int nfd) __attribute__((noreturn)); int remote_connect(const char *, const char *, struct addrinfo); +int timeout_handshake(int, struct tls *); int timeout_connect(int, const struct sockaddr *, socklen_t); int socks_connect(const char *, const char *, struct addrinfo, const char *, const char *, struct addrinfo, int, const char *); @@ -727,21 +728,48 @@ unix_bind(char *path, int flags) return (s); } +int +timeout_handshake(int s, struct tls *tls_ctx) +{ + struct pollfd pfd; + int ret; + + while ((ret = tls_handshake(tls_ctx)) != 0) { + if (ret == TLS_WANT_POLLIN) + pfd.events = POLLIN; + else if (ret == TLS_WANT_POLLOUT) + pfd.events = POLLOUT; + else + break; + pfd.fd = s; + if ((ret = poll(&pfd, 1, timeout)) == 1) + continue; + else if (ret == 0) { + errno = ETIMEDOUT; + ret = -1; + break; + } else + err(1, "poll failed"); + } + + return (ret); +} + void tls_setup_client(struct tls *tls_ctx, int s, char *host) { - int i; + const char *errstr; if (tls_connect_socket(tls_ctx, s, tls_expectname ? tls_expectname : host) == -1) { errx(1, "tls connection failed (%s)", tls_error(tls_ctx)); } - do { - if ((i = tls_handshake(tls_ctx)) == -1) - errx(1, "tls handshake failed (%s)", - tls_error(tls_ctx)); - } while (i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); + if (timeout_handshake(s, tls_ctx) == -1) { + if ((errstr = tls_error(tls_ctx)) == NULL) + errstr = strerror(errno); + errx(1, "tls handshake failed (%s)", errstr); + } if (vflag) report_tls(tls_ctx, host, tls_expectname); if (tls_expecthash && tls_peer_cert_hash(tls_ctx) && @@ -753,22 +781,15 @@ struct tls * tls_setup_server(struct tls *tls_ctx, int connfd, char *host) { struct tls *tls_cctx; + const char *errstr; - if (tls_accept_socket(tls_ctx, &tls_cctx, - connfd) == -1) { - warnx("tls accept failed (%s)", - tls_error(tls_ctx)); - tls_cctx = NULL; + if (tls_accept_socket(tls_ctx, &tls_cctx, connfd) == -1) { + warnx("tls accept failed (%s)", tls_error(tls_ctx)); + } else if (timeout_handshake(connfd, tls_cctx) == -1) { + if ((errstr = tls_error(tls_ctx)) == NULL) + errstr = strerror(errno); + warnx("tls handshake failed (%s)", errstr); } else { - int i; - - do { - if ((i = tls_handshake(tls_cctx)) == -1) - warnx("tls handshake failed (%s)", - tls_error(tls_cctx)); - } while(i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); - } - if (tls_cctx) { int gotcert = tls_peer_cert_provided(tls_cctx); if (vflag && gotcert) -- cgit v1.2.3