From: Guilhem Moulin Date: Fri, 09 Jun 2017 13:21:23 +0200 Subject: compile without TLS support tls.h isn't available in libsd-dev, and -C is already taken for CRLF line-ending in the Debian-specific patches. --- Makefile | 2 nc.1 | 63 ----------------------- netcat.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 144 insertions(+), 87 deletions(-) --- a/Makefile +++ b/Makefile @@ -2,8 +2,6 @@ PROG= nc SRCS= netcat.c atomicio.c socks.c -LDADD+= -ltls -lssl -lcrypto -DPADD+= ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} LIBS= `pkg-config --libs libbsd` -lresolv OBJS= $(SRCS:.c=.o) --- a/nc.1 +++ b/nc.1 @@ -33,20 +33,14 @@ .Nd arbitrary TCP and UDP connections and listens .Sh SYNOPSIS .Nm nc -.Op Fl 46cDdFhklNnrStUuvz -.Op Fl C Ar certfile -.Op Fl e Ar name -.Op Fl H Ar hash +.Op Fl 46DdFhklNnrStUuvz .Op Fl I Ar length .Op Fl i Ar interval -.Op Fl K Ar keyfile .Op Fl M Ar ttl .Op Fl m Ar minttl .Op Fl O Ar length -.Op Fl o Ar staplefile .Op Fl P Ar proxy_username .Op Fl p Ar source_port -.Op Fl R Ar CAfile .Op Fl s Ar source .Op Fl T Ar keyword .Op Fl V Ar rtable @@ -101,20 +95,10 @@ to use IPv4 addresses only. Forces .Nm to use IPv6 addresses only. -.It Fl C Ar certfile -Specifies the filename from which the public key part of the TLS -certificate is loaded, in PEM format. -May only be used with TLS. -.It Fl c -If using a TCP socket to connect or listen, use TLS. -Illegal if not using TCP sockets. .It Fl D Enable debugging on the socket. .It Fl d Do not attempt to read from stdin. -.It Fl e Ar name -Specify the name that must be present in the peer certificate when using TLS. -Illegal if not using TLS. .It Fl F Pass the first connected socket using .Xr sendmsg 2 @@ -130,11 +114,6 @@ using the .Xr ssh_config 5 .Cm ProxyUseFdpass option). -.It Fl H Ar hash -Specifies the required hash string of the peer certificate when using TLS. -The string format required is that used by -.Xr tls_peer_cert_hash 3 . -Illegal if not using TLS, and may not be used with -T noverify. .It Fl h Prints out .Nm @@ -144,10 +123,6 @@ Specifies the size of the TCP receive bu .It Fl i Ar interval Specifies a delay time interval between lines of text sent and received. Also causes a delay time between connections to multiple ports. -.It Fl K Ar keyfile -Specifies the filename from which the private key -is loaded in PEM format. -May only be used with TLS. .It Fl k Forces .Nm @@ -188,12 +163,6 @@ Do not do any DNS or service lookups on hostnames or ports. .It Fl O Ar length Specifies the size of the TCP send buffer. -.It Fl o Ar staplefile -Specifies the filename from which to load data to be stapled -during the TLS handshake. -The file is expected to contain an OCSP response from an OCSP server in -DER format. -May only be used with TLS and when a certificate is being used. .It Fl P Ar proxy_username Specifies a username to present to a proxy server that requires authentication. If no username is specified then authentication will not be attempted. @@ -202,12 +171,6 @@ Proxy authentication is only supported f Specifies the source port .Nm should use, subject to privilege restrictions and availability. -.It Fl R Ar CAfile -Specifies the filename from which the root CA bundle for certificate -verification is loaded, in PEM format. -Illegal if not using TLS. -The default is -.Pa /etc/ssl/cert.pem . .It Fl r Specifies that source and/or destination ports should be chosen randomly instead of sequentially within a range or in the order that the system @@ -224,24 +187,7 @@ It is an error to use this option in con .Fl l option. .It Fl T Ar keyword -Change IPv4 TOS value or TLS options. -For TLS options -.Ar keyword -may be one of -.Ar tlsall ; -which allows the use of all supported TLS protocols and ciphers, -.Ar noverify ; -which disables certificate verification; -.Ar noname , -which disables certificate name checking; -.Ar clientcert , -which requires a client certificate on incoming connections; or -.Ar muststaple , -which requires the peer to provide a valid stapled OCSP response -with the handshake. -It is illegal to specify TLS options if not using TLS. -.Pp -For IPv4 TOS value +Change IPv4 TOS value. .Ar keyword may be one of .Ar critical , @@ -483,11 +429,6 @@ the source port, with a timeout of 5 sec .Pp .Dl $ nc -p 31337 -w 5 host.example.com 42 .Pp -Open a TCP connection to port 443 of www.google.ca, and negotiate TLS. -Check for a different name in the certificate for validation. -.Pp -.Dl $ nc -v -c -e adsf.au.doubleclick.net www.google.ca 443 -.Pp Open a UDP connection to port 53 of host.example.com: .Pp .Dl $ nc -u host.example.com 53 --- a/netcat.c +++ b/netcat.c @@ -99,7 +99,9 @@ #include #include #include -#include +#ifdef TLS +# include +#endif #include #include #include "atomicio.h" @@ -112,13 +114,15 @@ #define POLL_NETIN 2 #define POLL_STDOUT 3 #define BUFSIZE 16384 -#define DEFAULT_CA_FILE "/etc/ssl/cert.pem" +#ifdef TLS +# define DEFAULT_CA_FILE "/etc/ssl/cert.pem" -#define TLS_ALL (1 << 1) -#define TLS_NOVERIFY (1 << 2) -#define TLS_NONAME (1 << 3) -#define TLS_CCERT (1 << 4) -#define TLS_MUSTSTAPLE (1 << 5) +# define TLS_ALL (1 << 1) +# define TLS_NOVERIFY (1 << 2) +# define TLS_NONAME (1 << 3) +# define TLS_CCERT (1 << 4) +# define TLS_MUSTSTAPLE (1 << 5) +#endif /* Command Line Options */ int dflag; /* detached, no stdin */ @@ -144,6 +148,7 @@ int Sflag; /* TCP MD5 signature opti int Tflag = -1; /* IP Type of Service */ int rtableid = -1; +# if defined(TLS) int usetls; /* use TLS */ char *Cflag; /* Public cert file */ char *Kflag; /* Private key file */ @@ -153,6 +158,7 @@ int tls_cachanged; /* Using non-defau int TLSopt; /* TLS options */ char *tls_expectname; /* required name in peer cert */ char *tls_expecthash; /* required hash of peer cert */ +# endif int timeout = -1; int family = AF_UNSPEC; @@ -165,10 +171,16 @@ void atelnet(int, unsigned char *, unsig void build_ports(char *); void help(void); int local_listen(char *, char *, struct addrinfo); +# if defined(TLS) void readwrite(int, struct tls *); +# else +void readwrite(int); +# endif void fdpass(int nfd) __attribute__((noreturn)); int remote_connect(const char *, const char *, struct addrinfo); +# if defined(TLS) int timeout_tls(int, struct tls *, int (*)(struct tls *)); +# endif 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 *); @@ -178,14 +190,23 @@ int unix_connect(char *); int unix_listen(char *); void set_common_sockopts(int, int); int map_tos(char *, int *); +# if defined(TLS) int map_tls(char *, int *); +# endif void report_connect(const struct sockaddr *, socklen_t, char *); +# if defined(TLS) void report_tls(struct tls *tls_ctx, char * host, char *tls_expectname); +# endif void usage(int); +# if defined(TLS) ssize_t drainbuf(int, unsigned char *, size_t *, struct tls *); 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 *); +# else +ssize_t drainbuf(int, unsigned char *, size_t *); +ssize_t fillbuf(int, unsigned char *, size_t *); +# endif int main(int argc, char *argv[]) @@ -200,8 +221,10 @@ main(int argc, char *argv[]) const char *errstr; struct addrinfo proxyhints; char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; +# if defined(TLS) struct tls_config *tls_cfg = NULL; struct tls *tls_ctx = NULL; +# endif ret = 1; socksv = 5; @@ -212,7 +235,11 @@ main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); while ((ch = getopt(argc, argv, +# if defined(TLS) "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vw:X:x:z")) != -1) { +# else + "46DdFhI:i:klM:m:NnO:P:p:rSs:T:tUuV:vw:X:x:z")) != -1) { +# endif switch (ch) { case '4': family = AF_INET; @@ -233,24 +260,30 @@ main(int argc, char *argv[]) else errx(1, "unsupported proxy protocol"); break; +# if defined(TLS) case 'C': Cflag = optarg; break; case 'c': usetls = 1; break; +# endif case 'd': dflag = 1; break; +# if defined(TLS) case 'e': tls_expectname = optarg; break; +# endif case 'F': Fflag = 1; break; +# if defined(TLS) case 'H': tls_expecthash = optarg; break; +# endif case 'h': help(); break; @@ -259,9 +292,11 @@ main(int argc, char *argv[]) if (errstr) errx(1, "interval %s: %s", errstr, optarg); break; +# if defined(TLS) case 'K': Kflag = optarg; break; +# endif case 'k': kflag = 1; break; @@ -290,10 +325,12 @@ main(int argc, char *argv[]) case 'p': pflag = optarg; break; +# if defined(TLS) case 'R': tls_cachanged = 1; Rflag = optarg; break; +# endif case 'r': rflag = 1; break; @@ -348,9 +385,11 @@ main(int argc, char *argv[]) errx(1, "TCP send window %s: %s", errstr, optarg); break; +# if defined(TLS) case 'o': oflag = optarg; break; +# endif case 'S': # if defined(TCP_MD5SIG) Sflag = 1; @@ -363,8 +402,10 @@ main(int argc, char *argv[]) errno = 0; if (map_tos(optarg, &Tflag)) break; +# if defined(TLS) if (map_tls(optarg, &TLSopt)) break; +# endif if (strlen(optarg) > 1 && optarg[0] == '0' && optarg[1] == 'x') Tflag = (int)strtol(optarg, NULL, 16); @@ -372,7 +413,11 @@ main(int argc, char *argv[]) Tflag = (int)strtonum(optarg, 0, 255, &errstr); if (Tflag < 0 || Tflag > 255 || errstr || errno) +# if defined(TLS) errx(1, "illegal tos/tls value %s", optarg); +# else + errx(1, "illegal tos value %s", optarg); +# endif break; default: usage(1); @@ -411,12 +456,15 @@ main(int argc, char *argv[]) if (!lflag && kflag) errx(1, "must use -l with -k"); +# if defined(TLS) if (uflag && usetls) errx(1, "cannot use -c and -u"); if ((family == AF_UNIX) && usetls) errx(1, "cannot use -c and -U"); +# endif if ((family == AF_UNIX) && Fflag) errx(1, "cannot use -F and -U"); +# if defined(TLS) if (Fflag && usetls) errx(1, "cannot use -c and -F"); if (TLSopt && !usetls) @@ -433,6 +481,7 @@ main(int argc, char *argv[]) errx(1, "you must specify -c to use -H"); if (tls_expectname && !usetls) errx(1, "you must specify -c to use -e"); +# endif /* Get name of temporary socket for unix datagram client */ if ((family == AF_UNIX) && uflag && !lflag) { @@ -499,6 +548,7 @@ main(int argc, char *argv[]) proxyhints.ai_flags |= AI_NUMERICHOST; } +# if defined(TLS) if (usetls) { if (Pflag) { if (pledge("stdio inet dns tty rpath", NULL) == -1) @@ -544,8 +594,11 @@ main(int argc, char *argv[]) } else if (pledge("stdio inet dns", NULL) == -1) err(1, "pledge"); } +# endif if (lflag) { +# if defined(TLS) struct tls *tls_cctx = NULL; +# endif int connfd; ret = 0; @@ -556,6 +609,7 @@ main(int argc, char *argv[]) s = unix_listen(host); } +# if defined(TLS) if (usetls) { tls_config_verify_client_optional(tls_cfg); if ((tls_ctx = tls_server()) == NULL) @@ -564,6 +618,7 @@ main(int argc, char *argv[]) errx(1, "tls configuration failed (%s)", tls_error(tls_ctx)); } +# endif /* Allow only one connection at a time, but stay alive. */ for (;;) { if (family != AF_UNIX) @@ -575,7 +630,11 @@ main(int argc, char *argv[]) * receive datagrams from multiple socket pairs. */ if (uflag && kflag) +# if defined(TLS) readwrite(s, NULL); +# else + readwrite(s); +# endif /* * For UDP and not -k, we will use recvfrom() initially * to wait for a caller, then use the regular functions @@ -600,7 +659,11 @@ main(int argc, char *argv[]) if (vflag) report_connect((struct sockaddr *)&z, len, NULL); +# if defined(TLS) readwrite(s, NULL); +# else + readwrite(s); +# endif } else { len = sizeof(cliaddr); connfd = accept4(s, (struct sockaddr *)&cliaddr, @@ -612,6 +675,7 @@ main(int argc, char *argv[]) if (vflag) report_connect((struct sockaddr *)&cliaddr, len, family == AF_UNIX ? host : NULL); +# if defined(TLS) if ((usetls) && (tls_cctx = tls_setup_server(tls_ctx, connfd, host))) readwrite(connfd, tls_cctx); @@ -622,6 +686,9 @@ main(int argc, char *argv[]) tls_free(tls_cctx); tls_cctx = NULL; } +# else + readwrite(connfd); +# endif close(connfd); } if (family != AF_UNIX) @@ -639,7 +706,11 @@ main(int argc, char *argv[]) if ((s = unix_connect(host)) > 0) { if (!zflag) +# if defined(TLS) readwrite(s, NULL); +# else + readwrite(s); +# endif close(s); } else ret = 1; @@ -659,6 +730,7 @@ main(int argc, char *argv[]) if (s != -1) close(s); +# if defined(TLS) if (usetls) { if ((tls_ctx = tls_client()) == NULL) errx(1, "tls client creation failed"); @@ -666,6 +738,7 @@ main(int argc, char *argv[]) errx(1, "tls configuration failed (%s)", tls_error(tls_ctx)); } +# endif if (xflag) s = socks_connect(host, portlist[i], hints, proxy, proxyport, proxyhints, socksv, @@ -703,6 +776,7 @@ main(int argc, char *argv[]) } if (Fflag) fdpass(s); +# if defined(TLS) else { if (usetls) tls_setup_client(tls_ctx, s, host); @@ -714,13 +788,19 @@ main(int argc, char *argv[]) tls_ctx = NULL; } } +# else + else if (!zflag) + readwrite(s); +# endif } } if (s != -1) close(s); +# if defined(TLS) tls_config_free(tls_cfg); +# endif exit(ret); } @@ -759,6 +839,7 @@ unix_bind(char *path, int flags) return (s); } +# if defined(TLS) int timeout_tls(int s, struct tls *tls_ctx, int (*func)(struct tls *)) { @@ -840,6 +921,7 @@ tls_setup_server(struct tls *tls_ctx, in } return NULL; } +# endif /* * unix_connect() @@ -1052,7 +1134,11 @@ local_listen(char *host, char *port, str * Loop that polls on the network file descriptor and stdin. */ void +# if defined(TLS) readwrite(int net_fd, struct tls *tls_ctx) +# else +readwrite(int net_fd) +# endif { struct pollfd pfd[4]; int stdin_fd = STDIN_FILENO; @@ -1152,12 +1238,17 @@ readwrite(int net_fd, struct tls *tls_ct /* try to read from stdin */ if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, +# if defined(TLS) &stdinbufpos, NULL); if (ret == TLS_WANT_POLLIN) pfd[POLL_STDIN].events = POLLIN; else if (ret == TLS_WANT_POLLOUT) pfd[POLL_STDIN].events = POLLOUT; - else if (ret == 0 || ret == -1) + else +# else + &stdinbufpos); +# endif + if (ret == 0 || ret == -1) pfd[POLL_STDIN].fd = -1; /* read something - poll net out */ if (stdinbufpos > 0) @@ -1169,12 +1260,17 @@ readwrite(int net_fd, struct tls *tls_ct /* try to write to network */ if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, +# if defined(TLS) &stdinbufpos, tls_ctx); 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) + else +# else + &stdinbufpos); +# endif + if (ret == -1) pfd[POLL_NETOUT].fd = -1; /* buffer empty - remove self from polling */ if (stdinbufpos == 0) @@ -1186,12 +1282,17 @@ readwrite(int net_fd, struct tls *tls_ct /* try to read from network */ if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, +# if defined(TLS) &netinbufpos, tls_ctx); 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) + else +# else + &netinbufpos); +# endif + if (ret == -1) pfd[POLL_NETIN].fd = -1; /* eof on net in - remove from pfd */ if (ret == 0) { @@ -1212,12 +1313,17 @@ readwrite(int net_fd, struct tls *tls_ct /* try to write to stdout */ if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, +# if defined(TLS) &netinbufpos, NULL); 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) + else +# else + &netinbufpos); +# endif + if (ret == -1) pfd[POLL_STDOUT].fd = -1; /* buffer empty - remove self from polling */ if (netinbufpos == 0) @@ -1241,19 +1347,29 @@ readwrite(int net_fd, struct tls *tls_ct } ssize_t +# if defined(TLS) drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls) +# else +drainbuf(int fd, unsigned char *buf, size_t *bufpos) +# endif { ssize_t n; ssize_t adjust; +# if defined(TLS) if (tls) n = tls_write(tls, buf, *bufpos); else { +# endif n = write(fd, buf, *bufpos); /* don't treat EAGAIN, EINTR as error */ if (n == -1 && (errno == EAGAIN || errno == EINTR)) +# if defined(TLS) n = TLS_WANT_POLLOUT; } +# else + n = -2; +# endif if (n <= 0) return n; /* adjust buffer */ @@ -1265,19 +1381,29 @@ drainbuf(int fd, unsigned char *buf, siz } ssize_t +# if defined(TLS) fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls) +# else +fillbuf(int fd, unsigned char *buf, size_t *bufpos) +# endif { size_t num = BUFSIZE - *bufpos; ssize_t n; +# if defined(TLS) if (tls) n = tls_read(tls, buf + *bufpos, num); else { +# endif n = read(fd, buf + *bufpos, num); /* don't treat EAGAIN, EINTR as error */ if (n == -1 && (errno == EAGAIN || errno == EINTR)) +# if defined(TLS) n = TLS_WANT_POLLIN; } +# else + n = -2; +# endif if (n <= 0) return n; *bufpos += n; @@ -1581,6 +1707,7 @@ map_tos(char *s, int *val) return (0); } +# if defined(TLS) int map_tls(char *s, int *val) { @@ -1662,6 +1789,7 @@ report_tls(struct tls * tls_ctx, char * } } +# endif void report_connect(const struct sockaddr *sa, socklen_t salen, char *path) @@ -1704,17 +1832,12 @@ help(void) fprintf(stderr, "\tCommand Summary:\n\ \t-4 Use IPv4\n\ \t-6 Use IPv6\n\ - \t-C certfile Public key file\n\ - \t-c Use TLS\n\ \t-D Enable the debug socket option\n\ \t-d Detach from stdin\n\ - \t-e name\t Required name in peer certificate\n\ \t-F Pass socket fd\n\ - \t-H hash\t Hash string of peer certificate\n\ \t-h This help text\n\ \t-I length TCP receive buffer length\n\ \t-i interval Delay interval for lines sent, ports scanned\n\ - \t-K keyfile Private key file\n\ \t-k Keep inbound sockets open for multiple connects\n\ \t-l Listen mode, for inbound connects\n\ \t-M ttl Outgoing TTL / Hop Limit\n\ @@ -1722,14 +1845,12 @@ help(void) \t-N Shutdown the network socket after EOF on stdin\n\ \t-n Suppress name/port resolutions\n\ \t-O length TCP send buffer length\n\ - \t-o staplefile Staple file\n\ \t-P proxyuser\tUsername for proxy authentication\n\ \t-p port\t Specify local port for remote connects\n\ - \t-R CAfile CA bundle\n\ \t-r Randomize remote ports\n\ \t-S Enable the TCP MD5 signature option\n\ \t-s source Local source address\n\ - \t-T keyword TOS value or TLS options\n\ + \t-T keyword TOS value\n\ \t-t Answer TELNET negotiation\n\ \t-U Use UNIX domain socket\n\ \t-u UDP mode\n\ @@ -1747,11 +1868,8 @@ void usage(int ret) { fprintf(stderr, - "usage: nc [-46cDdFhklNnrStUuvz] [-C certfile] [-e name] " - "[-H hash] [-I length]\n" - "\t [-i interval] [-K keyfile] [-M ttl] [-m minttl] [-O length]\n" - "\t [-o staplefile] [-P proxy_username] [-p source_port] " - "[-R CAfile]\n" + "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-M ttl]\n" + "\t [-m minttl] [-O length] [-P proxy_username] [-p source_port]\n" "\t [-s source] [-T keyword] [-V rtable] [-w timeout] " "[-X proxy_protocol]\n" "\t [-x proxy_address[:port]] [destination] [port]\n");