version 1.132, 2015/09/08 17:28:47 |
version 1.133, 2015/09/11 21:07:01 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* |
/* |
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org> |
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org> |
|
* Copyright (c) 2015 Bob Beck. All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
|
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
#include <tls.h> |
#include "atomicio.h" |
#include "atomicio.h" |
|
|
#ifndef SUN_LEN |
#ifndef SUN_LEN |
|
|
#define POLL_NETIN 2 |
#define POLL_NETIN 2 |
#define POLL_STDOUT 3 |
#define POLL_STDOUT 3 |
#define BUFSIZE 16384 |
#define BUFSIZE 16384 |
|
#define DEFAULT_CA_FILE "/etc/ssl/cert.pem" |
|
|
|
#define TLS_LEGACY (1 << 1) |
|
#define TLS_NOVERIFY (1 << 2) |
|
#define TLS_NONAME (1 << 3) |
|
#define TLS_CCERT (1 << 4) |
|
|
/* Command Line Options */ |
/* Command Line Options */ |
int dflag; /* detached, no stdin */ |
int dflag; /* detached, no stdin */ |
int Fflag; /* fdpass sock to stdout */ |
int Fflag; /* fdpass sock to stdout */ |
|
|
int Tflag = -1; /* IP Type of Service */ |
int Tflag = -1; /* IP Type of Service */ |
int rtableid = -1; |
int rtableid = -1; |
|
|
|
int usetls; /* use TLS */ |
|
char *Cflag; /* Public cert file */ |
|
char *Kflag; /* Private key file */ |
|
char *Rflag = DEFAULT_CA_FILE; /* Root CA file */ |
|
int tls_cachanged; /* Using non-default CA file */ |
|
int TLSopt; /* TLS options */ |
|
char *tls_expectname; /* required name in peer cert */ |
|
char *tls_peerhash; /* hash of peer cert */ |
|
char *tls_expecthash; /* required hash of peer cert */ |
|
|
int timeout = -1; |
int timeout = -1; |
int family = AF_UNSPEC; |
int family = AF_UNSPEC; |
char *portlist[PORT_MAX+1]; |
char *portlist[PORT_MAX+1]; |
|
|
void build_ports(char *); |
void build_ports(char *); |
void help(void); |
void help(void); |
int local_listen(char *, char *, struct addrinfo); |
int local_listen(char *, char *, struct addrinfo); |
void readwrite(int); |
void readwrite(int, struct tls *); |
void fdpass(int nfd) __attribute__((noreturn)); |
void fdpass(int nfd) __attribute__((noreturn)); |
int remote_connect(const char *, const char *, struct addrinfo); |
int remote_connect(const char *, const char *, struct addrinfo); |
int timeout_connect(int, const struct sockaddr *, socklen_t); |
int timeout_connect(int, const struct sockaddr *, socklen_t); |
|
|
int unix_listen(char *); |
int unix_listen(char *); |
void set_common_sockopts(int, int); |
void set_common_sockopts(int, int); |
int map_tos(char *, int *); |
int map_tos(char *, int *); |
|
int map_tls(char *, int *); |
void report_connect(const struct sockaddr *, socklen_t); |
void report_connect(const struct sockaddr *, socklen_t); |
|
void report_tls(struct tls * tls_ctx, char * host, char *tls_expectname); |
void usage(int); |
void usage(int); |
ssize_t drainbuf(int, unsigned char *, size_t *); |
ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *); |
ssize_t fillbuf(int, unsigned char *, size_t *); |
ssize_t fillbuf(int, unsigned char *, size_t *, struct tls *); |
|
void tls_setup_client(struct tls *, int, char *); |
|
struct tls * tls_setup_server(struct tls *, int, char *); |
|
|
int |
int |
main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
|
|
const char *errstr, *proxyhost = "", *proxyport = NULL; |
const char *errstr, *proxyhost = "", *proxyport = NULL; |
struct addrinfo proxyhints; |
struct addrinfo proxyhints; |
char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; |
char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; |
|
struct tls_config *tls_cfg = NULL; |
|
struct tls *tls_ctx = NULL; |
|
|
ret = 1; |
ret = 1; |
s = 0; |
s = 0; |
|
|
signal(SIGPIPE, SIG_IGN); |
signal(SIGPIPE, SIG_IGN); |
|
|
while ((ch = getopt(argc, argv, |
while ((ch = getopt(argc, argv, |
"46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) { |
"46C:cDde:FH:hI:i:K:klNnO:P:p:R:rSs:T:tUuV:vw:X:x:z")) != -1) { |
switch (ch) { |
switch (ch) { |
case '4': |
case '4': |
family = AF_INET; |
family = AF_INET; |
|
|
else |
else |
errx(1, "unsupported proxy protocol"); |
errx(1, "unsupported proxy protocol"); |
break; |
break; |
|
case 'C': |
|
Cflag = optarg; |
|
break; |
|
case 'c': |
|
usetls = 1; |
|
break; |
case 'd': |
case 'd': |
dflag = 1; |
dflag = 1; |
break; |
break; |
|
case 'e': |
|
tls_expectname = optarg; |
|
break; |
case 'F': |
case 'F': |
Fflag = 1; |
Fflag = 1; |
break; |
break; |
|
case 'H': |
|
tls_expecthash = optarg; |
|
break; |
case 'h': |
case 'h': |
help(); |
help(); |
break; |
break; |
|
|
if (errstr) |
if (errstr) |
errx(1, "interval %s: %s", errstr, optarg); |
errx(1, "interval %s: %s", errstr, optarg); |
break; |
break; |
|
case 'K': |
|
Kflag = optarg; |
|
break; |
case 'k': |
case 'k': |
kflag = 1; |
kflag = 1; |
break; |
break; |
|
|
case 'p': |
case 'p': |
pflag = optarg; |
pflag = optarg; |
break; |
break; |
|
case 'R': |
|
tls_cachanged = 1; |
|
Rflag = optarg; |
|
break; |
case 'r': |
case 'r': |
rflag = 1; |
rflag = 1; |
break; |
break; |
|
|
errno = 0; |
errno = 0; |
if (map_tos(optarg, &Tflag)) |
if (map_tos(optarg, &Tflag)) |
break; |
break; |
|
if (map_tls(optarg, &TLSopt)) |
|
break; |
if (strlen(optarg) > 1 && optarg[0] == '0' && |
if (strlen(optarg) > 1 && optarg[0] == '0' && |
optarg[1] == 'x') |
optarg[1] == 'x') |
Tflag = (int)strtol(optarg, NULL, 16); |
Tflag = (int)strtol(optarg, NULL, 16); |
|
|
Tflag = (int)strtonum(optarg, 0, 255, |
Tflag = (int)strtonum(optarg, 0, 255, |
&errstr); |
&errstr); |
if (Tflag < 0 || Tflag > 255 || errstr || errno) |
if (Tflag < 0 || Tflag > 255 || errstr || errno) |
errx(1, "illegal tos value %s", optarg); |
errx(1, "illegal tos/tls value %s", optarg); |
break; |
break; |
default: |
default: |
usage(1); |
usage(1); |
|
|
errx(1, "cannot use -z and -l"); |
errx(1, "cannot use -z and -l"); |
if (!lflag && kflag) |
if (!lflag && kflag) |
errx(1, "must use -l with -k"); |
errx(1, "must use -l with -k"); |
|
if (uflag && usetls) |
|
errx(1, "cannot use -c and -u"); |
|
if ((family == AF_UNIX) && usetls) |
|
errx(1, "cannot use -c and -U"); |
|
if (TLSopt && !usetls) |
|
errx(1, "you must specify -c to use TLS options"); |
|
if (Cflag && !usetls) |
|
errx(1, "you must specify -c to use -C"); |
|
if (Kflag && !usetls) |
|
errx(1, "you must specify -c to use -K"); |
|
if (tls_cachanged && !usetls) |
|
errx(1, "you must specify -c to use -R"); |
|
if (tls_expecthash && !usetls) |
|
errx(1, "you must specify -c to use -H"); |
|
if (tls_expectname && !usetls) |
|
errx(1, "you must specify -c to use -e"); |
|
|
/* Get name of temporary socket for unix datagram client */ |
/* Get name of temporary socket for unix datagram client */ |
if ((family == AF_UNIX) && uflag && !lflag) { |
if ((family == AF_UNIX) && uflag && !lflag) { |
|
|
proxyhints.ai_flags |= AI_NUMERICHOST; |
proxyhints.ai_flags |= AI_NUMERICHOST; |
} |
} |
|
|
|
if (usetls) { |
|
if (tls_init() == -1) |
|
errx(1, "unable to initialize TLS"); |
|
if ((tls_cfg = tls_config_new()) == NULL) |
|
errx(1, "unable to allocate TLS config"); |
|
if (Cflag && (tls_config_set_cert_file(tls_cfg, Cflag) == -1)) |
|
errx(1, "unable to set TLS certificate file %s", Cflag); |
|
if (Kflag && (tls_config_set_key_file(tls_cfg, Kflag) == -1)) |
|
errx(1, "unable to set TLS key file %s", Kflag); |
|
if (Rflag && (tls_config_set_ca_file(tls_cfg, Rflag) == -1)) |
|
errx(1, "unable to set root CA file %s", Rflag); |
|
if (TLSopt & TLS_LEGACY) { |
|
tls_config_set_protocols(tls_cfg, TLS_PROTOCOLS_ALL); |
|
tls_config_set_ciphers(tls_cfg, "legacy"); |
|
} |
|
if (!lflag && (TLSopt & TLS_CCERT)) |
|
errx(1, "clientcert is only valid with -l"); |
|
if (TLSopt & TLS_NONAME) |
|
tls_config_insecure_noverifyname(tls_cfg); |
|
if (TLSopt & TLS_NOVERIFY) { |
|
if (tls_expecthash != NULL) |
|
errx(1, "-H and -T noverify may not be used" |
|
"together"); |
|
tls_config_insecure_noverifycert(tls_cfg); |
|
} |
|
} |
if (lflag) { |
if (lflag) { |
|
struct tls *tls_cctx = NULL; |
int connfd; |
int connfd; |
ret = 0; |
ret = 0; |
|
|
|
|
s = unix_listen(host); |
s = unix_listen(host); |
} |
} |
|
|
|
if (usetls) { |
|
tls_config_verify_client_optional(tls_cfg); |
|
if ((tls_ctx = tls_server()) == NULL) |
|
errx(1, "tls server creation failed"); |
|
if (tls_configure(tls_ctx, tls_cfg) == -1) |
|
errx(1, "tls configuration failed (%s)", |
|
tls_error(tls_ctx)); |
|
} |
/* Allow only one connection at a time, but stay alive. */ |
/* Allow only one connection at a time, but stay alive. */ |
for (;;) { |
for (;;) { |
if (family != AF_UNIX) |
if (family != AF_UNIX) |
|
|
* receive datagrams from multiple socket pairs. |
* receive datagrams from multiple socket pairs. |
*/ |
*/ |
if (uflag && kflag) |
if (uflag && kflag) |
readwrite(s); |
readwrite(s, NULL); |
/* |
/* |
* For UDP and not -k, we will use recvfrom() initially |
* For UDP and not -k, we will use recvfrom() initially |
* to wait for a caller, then use the regular functions |
* to wait for a caller, then use the regular functions |
|
|
if (vflag) |
if (vflag) |
report_connect((struct sockaddr *)&z, len); |
report_connect((struct sockaddr *)&z, len); |
|
|
readwrite(s); |
readwrite(s, NULL); |
} else { |
} else { |
len = sizeof(cliaddr); |
len = sizeof(cliaddr); |
connfd = accept4(s, (struct sockaddr *)&cliaddr, |
connfd = accept4(s, (struct sockaddr *)&cliaddr, |
|
|
} |
} |
if (vflag) |
if (vflag) |
report_connect((struct sockaddr *)&cliaddr, len); |
report_connect((struct sockaddr *)&cliaddr, len); |
|
if ((usetls) && |
readwrite(connfd); |
(tls_cctx = tls_setup_server(tls_ctx, connfd, |
|
host))) |
|
readwrite(connfd, tls_cctx); |
|
if (!usetls) |
|
readwrite(connfd, NULL); |
|
if (tls_cctx) { |
|
int i; |
|
do { |
|
i = tls_close(tls_cctx); |
|
} while (i == TLS_WANT_POLLIN || |
|
i == TLS_WANT_POLLOUT); |
|
tls_free(tls_cctx); |
|
tls_cctx = NULL; |
|
} |
close(connfd); |
close(connfd); |
} |
} |
|
|
if (family != AF_UNIX) |
if (family != AF_UNIX) |
close(s); |
close(s); |
else if (uflag) { |
else if (uflag) { |
|
|
ret = 0; |
ret = 0; |
|
|
if ((s = unix_connect(host)) > 0 && !zflag) { |
if ((s = unix_connect(host)) > 0 && !zflag) { |
readwrite(s); |
readwrite(s, NULL); |
close(s); |
close(s); |
} else |
} else |
ret = 1; |
ret = 1; |
|
|
if (s) |
if (s) |
close(s); |
close(s); |
|
|
|
if (usetls) { |
|
if ((tls_ctx = tls_client()) == NULL) |
|
errx(1, "tls client creation failed"); |
|
if (tls_configure(tls_ctx, tls_cfg) == -1) |
|
errx(1, "tls configuration failed (%s)", |
|
tls_error(tls_ctx)); |
|
} |
if (xflag) |
if (xflag) |
s = socks_connect(host, portlist[i], hints, |
s = socks_connect(host, portlist[i], hints, |
proxyhost, proxyport, proxyhints, socksv, |
proxyhost, proxyport, proxyhints, socksv, |
|
|
} |
} |
if (Fflag) |
if (Fflag) |
fdpass(s); |
fdpass(s); |
else if (!zflag) |
else { |
readwrite(s); |
if (usetls) |
|
tls_setup_client(tls_ctx, s, host); |
|
if (!zflag) |
|
readwrite(s, tls_ctx); |
|
if (tls_ctx) { |
|
int j; |
|
do { |
|
j = tls_close(tls_ctx); |
|
} while (j == TLS_WANT_POLLIN || |
|
j == TLS_WANT_POLLOUT); |
|
tls_free(tls_ctx); |
|
tls_ctx = NULL; |
|
} |
|
} |
} |
} |
} |
} |
|
|
if (s) |
if (s) |
close(s); |
close(s); |
|
|
|
free(tls_peerhash); |
|
tls_config_free(tls_cfg); |
|
|
exit(ret); |
exit(ret); |
} |
} |
|
|
|
|
return (s); |
return (s); |
} |
} |
|
|
|
void |
|
tls_setup_client(struct tls *tls_ctx, int s, char *host) |
|
|
|
{ |
|
int i; |
|
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 (tls_peer_cert_hash(tls_ctx, &tls_peerhash) == -1) |
|
errx(1, "hash of peer certificate failed"); |
|
if (vflag) |
|
report_tls(tls_ctx, host, tls_expectname); |
|
if (tls_expecthash && tls_peerhash && |
|
strcmp(tls_expecthash, tls_peerhash) != 0) |
|
errx(1, "peer certificate is not %s", tls_expecthash); |
|
} |
|
struct tls * |
|
tls_setup_server(struct tls *tls_ctx, int connfd, char *host) |
|
{ |
|
struct tls *tls_cctx; |
|
if (tls_accept_socket(tls_ctx, &tls_cctx, |
|
connfd) == -1) { |
|
warnx("tls accept failed (%s)", |
|
tls_error(tls_ctx)); |
|
tls_cctx = NULL; |
|
} 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 (gotcert && tls_peer_cert_hash(tls_cctx, &tls_peerhash) == -1) |
|
warn("hash of peer certificate failed"); |
|
if (vflag && gotcert) |
|
report_tls(tls_cctx, host, tls_expectname); |
|
if ((TLSopt & TLS_CCERT) && !gotcert) |
|
warnx("No client certificate provided"); |
|
else if (gotcert && tls_peerhash && tls_expecthash && |
|
strcmp(tls_expecthash, tls_peerhash) != 0) |
|
warnx("peer certificate is not %s", tls_expecthash); |
|
else if (gotcert && tls_expectname && |
|
(! tls_peer_cert_contains_name(tls_cctx, tls_expectname))) |
|
warnx("name (%s) not found in client cert", |
|
tls_expectname); |
|
else { |
|
return tls_cctx; |
|
} |
|
} |
|
return NULL; |
|
} |
/* |
/* |
* unix_connect() |
* unix_connect() |
* Returns a socket connected to a local unix socket. Returns -1 on failure. |
* Returns a socket connected to a local unix socket. Returns -1 on failure. |
|
|
* Loop that polls on the network file descriptor and stdin. |
* Loop that polls on the network file descriptor and stdin. |
*/ |
*/ |
void |
void |
readwrite(int net_fd) |
readwrite(int net_fd, struct tls *tls_ctx) |
{ |
{ |
struct pollfd pfd[4]; |
struct pollfd pfd[4]; |
int stdin_fd = STDIN_FILENO; |
int stdin_fd = STDIN_FILENO; |
|
|
/* try to read from stdin */ |
/* try to read from stdin */ |
if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { |
if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { |
ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, |
ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, |
&stdinbufpos); |
&stdinbufpos, NULL); |
/* error or eof on stdin - remove from pfd */ |
if (ret == TLS_WANT_POLLIN) |
if (ret == 0 || ret == -1) |
pfd[POLL_STDIN].events = POLLIN; |
|
else if (ret == TLS_WANT_POLLOUT) |
|
pfd[POLL_STDIN].events = POLLOUT; |
|
else if (ret == 0 || ret == -1) |
pfd[POLL_STDIN].fd = -1; |
pfd[POLL_STDIN].fd = -1; |
/* read something - poll net out */ |
/* read something - poll net out */ |
if (stdinbufpos > 0) |
if (stdinbufpos > 0) |
|
|
/* try to write to network */ |
/* try to write to network */ |
if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { |
if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { |
ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, |
ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, |
&stdinbufpos); |
&stdinbufpos, tls_ctx); |
if (ret == -1) |
if (ret == TLS_WANT_POLLIN) |
|
pfd[POLL_NETOUT].events = POLLIN; |
|
else if (ret == TLS_WANT_POLLOUT) |
|
pfd[POLL_NETOUT].events = POLLOUT; |
|
else if (ret == -1) |
pfd[POLL_NETOUT].fd = -1; |
pfd[POLL_NETOUT].fd = -1; |
/* buffer empty - remove self from polling */ |
/* buffer empty - remove self from polling */ |
if (stdinbufpos == 0) |
if (stdinbufpos == 0) |
|
|
/* try to read from network */ |
/* try to read from network */ |
if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { |
if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { |
ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, |
ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, |
&netinbufpos); |
&netinbufpos, tls_ctx); |
if (ret == -1) |
if (ret == TLS_WANT_POLLIN) |
|
pfd[POLL_NETIN].events = POLLIN; |
|
else if (ret == TLS_WANT_POLLOUT) |
|
pfd[POLL_NETIN].events = POLLOUT; |
|
else if (ret == -1) |
pfd[POLL_NETIN].fd = -1; |
pfd[POLL_NETIN].fd = -1; |
/* eof on net in - remove from pfd */ |
/* eof on net in - remove from pfd */ |
if (ret == 0) { |
if (ret == 0) { |
|
|
/* try to write to stdout */ |
/* try to write to stdout */ |
if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { |
if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { |
ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, |
ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, |
&netinbufpos); |
&netinbufpos, NULL); |
if (ret == -1) |
if (ret == TLS_WANT_POLLIN) |
|
pfd[POLL_STDOUT].events = POLLIN; |
|
else if (ret == TLS_WANT_POLLOUT) |
|
pfd[POLL_STDOUT].events = POLLOUT; |
|
else if (ret == -1) |
pfd[POLL_STDOUT].fd = -1; |
pfd[POLL_STDOUT].fd = -1; |
/* buffer empty - remove self from polling */ |
/* buffer empty - remove self from polling */ |
if (netinbufpos == 0) |
if (netinbufpos == 0) |
|
|
} |
} |
|
|
ssize_t |
ssize_t |
drainbuf(int fd, unsigned char *buf, size_t *bufpos) |
drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls) |
{ |
{ |
ssize_t n; |
ssize_t n; |
ssize_t adjust; |
ssize_t adjust; |
|
|
n = write(fd, buf, *bufpos); |
if (tls) |
/* don't treat EAGAIN, EINTR as error */ |
n = tls_write(tls, buf, *bufpos); |
if (n == -1 && (errno == EAGAIN || errno == EINTR)) |
else { |
n = -2; |
n = write(fd, buf, *bufpos); |
|
/* don't treat EAGAIN, EINTR as error */ |
|
if (n == -1 && (errno == EAGAIN || errno == EINTR)) |
|
n = TLS_WANT_POLLOUT; |
|
} |
if (n <= 0) |
if (n <= 0) |
return n; |
return n; |
/* adjust buffer */ |
/* adjust buffer */ |
|
|
|
|
|
|
ssize_t |
ssize_t |
fillbuf(int fd, unsigned char *buf, size_t *bufpos) |
fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls) |
{ |
{ |
size_t num = BUFSIZE - *bufpos; |
size_t num = BUFSIZE - *bufpos; |
ssize_t n; |
ssize_t n; |
|
|
n = read(fd, buf + *bufpos, num); |
if (tls) |
/* don't treat EAGAIN, EINTR as error */ |
n = tls_read(tls, buf + *bufpos, num); |
if (n == -1 && (errno == EAGAIN || errno == EINTR)) |
else { |
n = -2; |
n = read(fd, buf + *bufpos, num); |
|
/* don't treat EAGAIN, EINTR as error */ |
|
if (n == -1 && (errno == EAGAIN || errno == EINTR)) |
|
n = TLS_WANT_POLLIN; |
|
} |
if (n <= 0) |
if (n <= 0) |
return n; |
return n; |
*bufpos += n; |
*bufpos += n; |
|
|
return (0); |
return (0); |
} |
} |
|
|
|
int |
|
map_tls(char *s, int *val) |
|
{ |
|
const struct tlskeywords { |
|
const char *keyword; |
|
int val; |
|
} *t, tlskeywords[] = { |
|
{ "tlslegacy", TLS_LEGACY }, |
|
{ "noverify", TLS_NOVERIFY }, |
|
{ "noname", TLS_NONAME }, |
|
{ "clientcert", TLS_CCERT}, |
|
{ NULL, -1 }, |
|
}; |
|
|
|
for (t = tlskeywords; t->keyword != NULL; t++) { |
|
if (strcmp(s, t->keyword) == 0) { |
|
*val |= t->val; |
|
return (1); |
|
} |
|
} |
|
return (0); |
|
} |
|
|
void |
void |
|
report_tls(struct tls * tls_ctx, char * host, char *tls_expectname) |
|
{ |
|
char *subject = NULL, *issuer = NULL; |
|
if (tls_peer_cert_subject(tls_ctx, &subject) == -1) |
|
errx(1, "unable to get certificate subject"); |
|
if (tls_peer_cert_issuer(tls_ctx, &issuer) == -1) |
|
errx(1, "unable to get certificate issuer"); |
|
fprintf(stderr, "TLS handshake completed with %s\n", host); |
|
fprintf(stderr, "Peer name %s\n", |
|
tls_expectname ? tls_expectname : host); |
|
if (subject) |
|
fprintf(stderr, "Subject: %s\n", subject); |
|
if (issuer) |
|
fprintf(stderr, "Issuer: %s\n", issuer); |
|
if (tls_peerhash) |
|
fprintf(stderr, "Cert Hash: %s\n", tls_peerhash); |
|
free(subject); |
|
free(issuer); |
|
} |
|
void |
report_connect(const struct sockaddr *sa, socklen_t salen) |
report_connect(const struct sockaddr *sa, socklen_t salen) |
{ |
{ |
char remote_host[NI_MAXHOST]; |
char remote_host[NI_MAXHOST]; |
|
|
usage(int ret) |
usage(int ret) |
{ |
{ |
fprintf(stderr, |
fprintf(stderr, |
"usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" |
"usage: nc [-46cDdFhklNnrStUuvz] [-C certfile] [-e name] \n" |
"\t [-P proxy_username] [-p source_port] [-s source] [-T toskeyword]\n" |
"\t [-I length] [-i interval] [-H hash] [-K keyfile] [-O length]\n" |
"\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" |
"\t [-P proxy_username] [-p source_port] [-R cafile] [-s source]\n" |
"\t [-x proxy_address[:port]] [destination] [port]\n"); |
"\t [-T tls|toskeyword] [-V rtable] [-w timeout]\n" |
|
"\t [-X proxy_protocol] [-x proxy_address[:port]]\n" |
|
"\t [destination] [port]\n"); |
if (ret) |
if (ret) |
exit(1); |
exit(1); |
} |
} |