summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2017-02-08 13:43:34 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2017-02-08 13:43:34 +0000
commitcd2524f09be30847939156745d135fedabc4a01f (patch)
tree46d8f4b4f605560d43d576548a8a8ecffafafdba /usr.bin
parent124b495bcd37e862385e7d887a8cc7126d8ecbad (diff)
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@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/nc/netcat.c63
1 files changed, 42 insertions, 21 deletions
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 <ericj@monkey.org>
* 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)