Page MenuHomeFreeBSD

D45537.diff
No OneTemporary

D45537.diff

diff --git a/contrib/netcat/nc.1 b/contrib/netcat/nc.1
--- a/contrib/netcat/nc.1
+++ b/contrib/netcat/nc.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: nc.1,v 1.68 2015/03/26 10:35:04 tobias Exp $
+.\" $OpenBSD: nc.1,v 1.97 2022/09/11 09:58:06 schwarze Exp $
.\"
.\" Copyright (c) 1996 David Sacerdote
.\" All rights reserved.
@@ -25,9 +25,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $FreeBSD$
-.\"
-.Dd January 17, 2023
+.Dd $Mdocdate: January 17, 2023 $
.Dt NC 1
.Os
.Sh NAME
@@ -35,30 +33,29 @@
.Nd arbitrary TCP and UDP connections and listens
.Sh SYNOPSIS
.Nm nc
-.Bk -words
.Op Fl 46DdEFhklMNnrStUuvz
+.Op Fl -crlf
.Op Fl e Ar IPsec_policy
.Op Fl I Ar length
.Op Fl i Ar interval
.Op Fl -no-tcpopt
-.Op Fl -sctp
-.Op Fl -crlf
+.Op Fl M Ar ttl
+.Op Fl m Ar minttl
.Op Fl O Ar length
.Op Fl P Ar proxy_username
.Op Fl p Ar source_port
-.Op Fl s Ar source
+.Op Fl s Ar sourceaddr
+.Op Fl -sctp
+.Op Fl -stats
.Op Fl T Ar toskeyword
.Op Fl -tun Ar tundev
.Op Fl V Ar rtable
+.Op Fl W Ar recvlimit
.Op Fl w Ar timeout
.Op Fl X Ar proxy_protocol
-.Oo Xo
-.Fl x Ar proxy_address Ns Oo : Ns
-.Ar port Oc
-.Xc Oc
+.Op Fl x Ar proxy_address Ns Op : Ns Ar port
.Op Ar destination
.Op Ar port
-.Ek
.Sh DESCRIPTION
The
.Nm
@@ -98,13 +95,9 @@
The options are as follows:
.Bl -tag -width Ds
.It Fl 4
-Forces
-.Nm
-to use IPv4 addresses only.
+Use IPv4 addresses only.
.It Fl 6
-Forces
-.Nm
-to use IPv6 addresses only.
+Use IPv6 addresses only.
.It Fl -crlf
Convert LF into CRLF when sending data over the network.
.It Fl D
@@ -115,7 +108,7 @@
Shortcut for
.Qo
.Li "-e 'in ipsec esp/transport//require'"
-.Li "-e 'out ipsec esp/transport//require'"
+.Li "-e 'out ipsec esp/transport//require'"
.Qc ,
which enables IPsec ESP transport mode in both
directions.
@@ -140,47 +133,46 @@
.Xr ssh_config 5
.Cm ProxyUseFdpass
option).
+Cannot be used with
+.Fl U .
.It Fl h
-Prints out
+Print out the
.Nm
-help.
+help text and exit.
.It Fl I Ar length
-Specifies the size of the TCP receive buffer.
+Specify the size of the TCP receive buffer.
.It Fl i Ar interval
-Specifies a delay time interval between lines of text sent and received.
+Sleep for
+.Ar interval
+seconds between lines of text sent and received.
Also causes a delay time between connections to multiple ports.
.It Fl k
-Forces
-.Nm
-to stay listening for another connection after its current connection
-is completed.
-It is an error to use this option without the
-.Fl l
-option.
+When a connection is completed, listen for another one.
+Requires
+.Fl l .
When used together with the
.Fl u
option, the server socket is not connected and it can receive UDP datagrams from
multiple hosts.
.It Fl l
-Used to specify that
-.Nm
-should listen for an incoming connection rather than initiate a
+Listen for an incoming connection rather than initiating a
connection to a remote host.
-It is an error to use this option in conjunction with the
-.Fl p ,
-.Fl s ,
-or
-.Fl z
-options.
+Cannot be used together with any of the options
+.Fl psxz .
Additionally, any timeouts specified with the
.Fl w
option are ignored.
-.It Fl M
+.It Fl -stats
Collect per-connection TCP statistics using the
.Xr stats 3
framework and print them in JSON format to
.Xr stderr 4
after the connection is closed.
+.It Fl M Ar ttl
+Set the TTL / hop limit of outgoing packets.
+.It Fl m Ar minttl
+Ask the kernel to drop incoming packets whose TTL / hop limit is under
+.Ar minttl .
.It Fl N
.Xr shutdown 2
the network socket after EOF on the input.
@@ -188,6 +180,7 @@
.It Fl n
Do not do any DNS or service lookups on any specified addresses,
hostnames or ports.
+If a name cannot be resolved without DNS, an error will be reported.
.It Fl -no-tcpopt
Disables the use of TCP options on the socket, by setting the boolean
TCP_NOOPT
@@ -195,52 +188,51 @@
.It Fl -sctp
Use SCTP instead of the default option of TCP.
.It Fl O Ar length
-Specifies the size of the TCP send buffer.
+Specify the size of the TCP send buffer.
.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.
Proxy authentication is only supported for HTTP CONNECT proxies at present.
.It Fl p Ar source_port
-Specifies the source port
+Specify the source port
.Nm
should use, subject to privilege restrictions and availability.
-It is an error to use this option in conjunction with the
-.Fl l
-option.
+Cannot be used together with
+.Fl l .
.It Fl r
-Specifies that source and/or destination ports should be chosen randomly
+Choose source and/or destination ports randomly
instead of sequentially within a range or in the order that the system
assigns them.
.It Fl S
-Enables the RFC 2385 TCP MD5 signature option.
-.It Fl s Ar source
-Specifies the IP of the interface which is used to send the packets.
+Enable the RFC 2385 TCP MD5 signature option.
+.It Fl s Ar sourceaddr
+Set the source address to send packets from,
+which is useful on machines with multiple interfaces.
For
.Ux Ns -domain
datagram sockets, specifies the local temporary socket file
to create and use so that datagrams can be received.
-It is an error to use this option in conjunction with the
+Cannot be used together with
.Fl l
-option.
-.It Fl T Ar toskeyword
-Change IPv4 TOS value.
-.Ar toskeyword
+or
+.Fl x .
+.It Fl T Ar keyword
+Change the IPv4 TOS/IPv6 traffic class value.
+.Ar keyword
may be one of
-.Ar critical ,
-.Ar inetcontrol ,
-.Ar lowdelay ,
-.Ar netcontrol ,
-.Ar throughput ,
-.Ar reliability ,
+.Cm critical ,
+.Cm inetcontrol ,
+.Cm lowdelay ,
+.Cm netcontrol ,
+.Cm throughput ,
+.Cm reliability ,
or one of the DiffServ Code Points:
-.Ar ef ,
-.Ar af11 ... af43 ,
-.Ar cs0 ... cs7 ;
+.Cm ef ,
+.Cm af11 No ... Cm af43 ,
+.Cm cs0 No ... Cm cs7 ;
or a number in either hex or decimal.
.It Fl t
-Causes
-.Nm
-to send RFC 854 DON'T and WON'T responses to RFC 854 DO and WILL requests.
+Send RFC 854 DON'T and WON'T responses to RFC 854 DO and WILL requests.
This makes it possible to use
.Nm
to script telnet sessions.
@@ -251,11 +243,15 @@
.Xr tun 4
for input and output rather than the default of stdin and stdout.
.It Fl U
-Specifies to use
+Use
.Ux Ns -domain
sockets.
+Cannot be used together with any of the options
+.Fl Fx .
.It Fl u
-Use UDP instead of the default option of TCP.
+Use UDP instead of TCP.
+Cannot be used together with
+.Fl x .
For
.Ux Ns -domain
sockets, use a datagram socket instead of a stream socket.
@@ -271,9 +267,11 @@
.Pq Dq FIB
to be used.
.It Fl v
-Have
-.Nm
-give more verbose output.
+Produce more verbose output.
+.It Fl W Ar recvlimit
+Terminate after receiving
+.Ar recvlimit
+packets from the network.
.It Fl w Ar timeout
Connections which cannot be established or are idle timeout after
.Ar timeout
@@ -289,25 +287,20 @@
flag.
The default is no timeout.
.It Fl X Ar proxy_protocol
-Requests that
-.Nm
-should use the specified protocol when talking to the proxy server.
+Use
+.Ar proxy_protocol
+when talking to the proxy server.
Supported protocols are
-.Dq 4
+.Cm 4
(SOCKS v.4),
-.Dq 5
+.Cm 5
(SOCKS v.5)
and
-.Dq connect
+.Cm connect
(HTTPS proxy).
If the protocol is not specified, SOCKS version 5 is used.
-.It Xo
-.Fl x Ar proxy_address Ns Oo : Ns
-.Ar port Oc
-.Xc
-Requests that
-.Nm
-should connect to
+.It Fl x Ar proxy_address Ns Op : Ns Ar port
+Connect to
.Ar destination
using a proxy at
.Ar proxy_address
@@ -317,13 +310,15 @@
.Ar port
is not specified, the well-known port for the proxy protocol is used (1080
for SOCKS, 3128 for HTTPS).
+An IPv6 address can be specified unambiguously by enclosing
+.Ar proxy_address
+in square brackets.
+A proxy cannot be used with any of the options
+.Fl lsuU .
.It Fl z
-Specifies that
-.Nm
-should just scan for listening daemons, without sending any data to them.
-It is an error to use this option in conjunction with the
-.Fl l
-option.
+Only scan for listening daemons, without sending any data to them.
+Cannot be used together with
+.Fl l .
.El
.Pp
.Ar destination
@@ -344,8 +339,9 @@
option is given).
.Pp
.Ar port
-can be a single integer or a range of ports.
-Ranges are in the form nn-mm.
+can be specified as a numeric port number or as a service name.
+Port ranges may be specified as numeric port numbers of the form
+.Ar nn Ns - Ns Ar mm .
In general,
a destination port must be specified,
unless the
@@ -367,7 +363,7 @@
.Pq or a second machine ,
connect to the machine and port being listened on:
.Pp
-.Dl $ nc 127.0.0.1 1234
+.Dl $ nc -N 127.0.0.1 1234
.Pp
There should now be a connection between the ports.
Anything typed at the second console will be concatenated to the first,
@@ -380,7 +376,10 @@
.Sq client .
The connection may be terminated using an
.Dv EOF
-.Pq Sq ^D .
+.Pq Sq ^D ,
+as the
+.Fl N
+flag was given.
.Sh DATA TRANSFER
The example in the previous section can be expanded to build a
basic data transfer model.
@@ -392,13 +391,13 @@
.Nm
to listen on a specific port, with output captured into a file:
.Pp
-.Dl $ nc -l 1234 \*(Gt filename.out
+.Dl $ nc -l 1234 > filename.out
.Pp
Using a second machine, connect to the listening
.Nm
process, feeding it the file which is to be transferred:
.Pp
-.Dl $ nc -N host.example.com 1234 \*(Lt filename.in
+.Dl $ nc -N host.example.com 1234 < filename.in
.Pp
After the file has been transferred, the connection will close automatically.
.Sh TALKING TO SERVERS
@@ -422,10 +421,10 @@
of requests required by the server.
As another example, an email may be submitted to an SMTP server using:
.Bd -literal -offset indent
-$ nc localhost 25 \*(Lt\*(Lt EOF
+$ nc localhost 25 << EOF
HELO host.example.com
-MAIL FROM:\*(Ltuser@host.example.com\*(Gt
-RCPT TO:\*(Ltuser2@host.example.com\*(Gt
+MAIL FROM:<user@host.example.com>
+RCPT TO:<user2@host.example.com>
DATA
Body of email.
\&.
@@ -522,8 +521,8 @@
.Xr ssh 1 ,
.Xr tcp 4
.Sh AUTHORS
-Original implementation by *Hobbit*
-.Aq Mt hobbit@avian.org .
+Original implementation by
+.An *Hobbit* Aq Mt hobbit@avian.org .
.br
Rewritten with IPv6 support by
.An Eric Jackson Aq Mt ericj@monkey.org .
diff --git a/contrib/netcat/netcat.c b/contrib/netcat/netcat.c
--- a/contrib/netcat/netcat.c
+++ b/contrib/netcat/netcat.c
@@ -1,6 +1,7 @@
-/* $OpenBSD: netcat.c,v 1.130 2015/07/26 19:12:28 chl Exp $ */
+/* $OpenBSD: netcat.c,v 1.226 2023/08/14 08:07:27 tb Exp $ */
/*
* 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
* modification, are permitted provided that the following conditions
@@ -24,8 +25,6 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
*/
/*
@@ -55,6 +54,7 @@
#include <netinet/ip.h>
#include <arpa/telnet.h>
+#include <ctype.h>
#include <err.h>
#include <getopt.h>
#include <fcntl.h>
@@ -65,23 +65,27 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
+#ifdef __OpenBSD__
+#include <tls.h>
+#endif
#include <unistd.h>
-#include "atomicio.h"
-#ifndef SUN_LEN
-#define SUN_LEN(su) \
- (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
-#endif
+#include "atomicio.h"
#define PORT_MAX 65535
-#define PORT_MAX_LEN 6
#define UNIX_DG_TMP_SOCKET_SIZE 19
-#define POLL_STDIN 0
-#define POLL_NETOUT 1
-#define POLL_NETIN 2
-#define POLL_STDOUT 3
-#define BUFSIZE 16384
+#define POLL_STDIN 0
+#define POLL_NETOUT 1
+#define POLL_NETIN 2
+#define POLL_STDOUT 3
+#define BUFSIZE 16384
+
+#define TLS_NOVERIFY (1 << 1)
+#define TLS_NONAME (1 << 2)
+#define TLS_CCERT (1 << 3)
+#define TLS_MUSTSTAPLE (1 << 4)
/* Command Line Options */
int dflag; /* detached, no stdin */
@@ -89,7 +93,7 @@
unsigned int iflag; /* Interval Flag */
int kflag; /* More than one connect */
int lflag; /* Bind to local port */
-int FreeBSD_Mflag; /* Measure using stats(3) */
+int FreeBSD_stats; /* Measure using stats(3) */
int Nflag; /* shutdown() network socket */
int nflag; /* Don't do name look up */
int FreeBSD_Oflag; /* Do not use TCP options */
@@ -111,35 +115,74 @@
int Tflag = -1; /* IP Type of Service */
int rtableid = -1;
+int usetls; /* use TLS */
+const char *Cflag; /* Public cert file */
+const char *Kflag; /* Private key file */
+const char *oflag; /* OCSP stapling file */
+const char *Rflag; /* 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_expecthash; /* required hash of peer cert */
+char *tls_ciphers; /* TLS ciphers */
+char *tls_protocols; /* TLS protocols */
+FILE *Zflag; /* file to save peer cert */
+
+int recvcount, recvlimit;
int timeout = -1;
int family = AF_UNSPEC;
int tun_fd = -1;
char *portlist[PORT_MAX+1];
char *unix_dg_tmp_socket;
+int ttl = -1;
+int minttl = -1;
void atelnet(int, unsigned char *, unsigned int);
+int strtoport(char *portstr, int udp);
void build_ports(char *);
-void help(void);
-int local_listen(char *, char *, struct addrinfo);
-void readwrite(int);
+void help(void) __attribute__((noreturn));
+int local_listen(const char *, const char *, struct addrinfo);
+#ifdef __OpenBSD__
+void readwrite(int, struct tls *);
+#else
+void readwrite(int, void *);
+#endif
void fdpass(int nfd) __attribute__((noreturn));
-int remote_connect(const char *, const char *, struct addrinfo);
+int remote_connect(const char *, const char *, struct addrinfo, char *);
+#ifdef __OpenBSD__
+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 *);
int udptest(int);
-int unix_bind(char *);
+void connection_info(const char *, const char *, const char *, const char *);
+int unix_bind(char *, int);
int unix_connect(char *);
int unix_listen(char *);
void FreeBSD_stats_setup(int);
void FreeBSD_stats_print(int);
void set_common_sockopts(int, int);
-int map_tos(char *, int *);
-void report_connect(const struct sockaddr *, socklen_t);
+int process_tos_opt(char *, int *);
+int process_tls_opt(char *, int *);
+#ifdef __OpenBSD__
+void save_peer_cert(struct tls *_tls_ctx, FILE *_fp);
+#endif
+void report_sock(const char *, const struct sockaddr *, socklen_t, char *);
+#ifdef __OpenBSD__
+void report_tls(struct tls *tls_ctx, char * host);
+#endif
void usage(int);
+#ifdef __OpenBSD__
+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 write_wrapper(int, const void *, size_t);
-ssize_t drainbuf(int, unsigned char *, size_t *, int);
-ssize_t fillbuf(int, unsigned char *, size_t *);
+ssize_t drainbuf(int, unsigned char *, size_t *, void *, int);
+ssize_t fillbuf(int, unsigned char *, size_t *, void *);
+#endif
#ifdef IPSEC
void add_ipsec_policy(int, int, char *);
@@ -154,38 +197,45 @@
int
main(int argc, char *argv[])
{
- int ch, s, ret, socksv, ipsec_count;
- int numfibs;
- size_t intsize = sizeof(int);
+ int ch, s = -1, ret, socksv;
char *host, *uport;
+ int numfibs, ipsec_count = 0;
+ size_t intsize = sizeof(int);
+ char ipaddr[NI_MAXHOST];
struct addrinfo hints;
- struct servent *sv;
socklen_t len;
struct sockaddr_storage cliaddr;
- char *proxy;
- const char *errstr, *proxyhost = "", *proxyport = NULL, *tundev = NULL;
+ char *proxy = NULL, *proxyport = NULL;
+ const char *errstr, *tundev = NULL;
struct addrinfo proxyhints;
char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE];
+#ifdef __OpenBSD__
+ struct tls_config *tls_cfg = NULL;
+ struct tls *tls_ctx = NULL;
+ uint32_t protocols;
+#endif
struct option longopts[] = {
{ "crlf", no_argument, &FreeBSD_crlf, 1 },
+ { "help", no_argument, NULL, 'h' },
{ "no-tcpopt", no_argument, &FreeBSD_Oflag, 1 },
{ "sctp", no_argument, &FreeBSD_sctp, 1 },
+ { "stats", no_argument, &FreeBSD_stats, 1 },
{ "tun", required_argument, NULL, FREEBSD_TUN },
{ NULL, 0, NULL, 0 }
};
ret = 1;
- ipsec_count = 0;
- s = 0;
socksv = 5;
host = NULL;
uport = NULL;
- sv = NULL;
+#ifdef __OpenBSD__
+ Rflag = tls_default_ca_cert_file();
+#endif
signal(SIGPIPE, SIG_IGN);
while ((ch = getopt_long(argc, argv,
- "46DdEe:FhI:i:klMNnoO:P:p:rSs:tT:UuV:vw:X:x:z",
+ "46DdEe:FhI:i:klM:m:NnO:P:p:rSs:T:tUuV:vW:w:X:x:z",
longopts, NULL)) != -1) {
switch (ch) {
case '4':
@@ -207,15 +257,27 @@
else
errx(1, "unsupported proxy protocol");
break;
+#ifdef __OpenBSD__
+ case 'C':
+ Cflag = optarg;
+ break;
+ case 'c':
+ usetls = 1;
+ break;
+#endif
case 'd':
dflag = 1;
break;
case 'e':
+#ifdef __OpenBSD__
+ tls_expectname = optarg;
+#else /* __OpenBSD__ */
#ifdef IPSEC
ipsec_policy[ipsec_count++ % 2] = optarg;
-#else
+#else /* IPSEC */
errx(1, "IPsec support unavailable.");
-#endif
+#endif /* IPSEC */
+#endif /* __OpenBSD__ */
break;
case 'E':
#ifdef IPSEC
@@ -228,6 +290,11 @@
case 'F':
Fflag = 1;
break;
+#ifdef __OpenBSD__
+ case 'H':
+ tls_expecthash = optarg;
+ break;
+#endif
case 'h':
help();
break;
@@ -236,6 +303,11 @@
if (errstr)
errx(1, "interval %s: %s", errstr, optarg);
break;
+#ifdef __OpenBSD__
+ case 'K':
+ Kflag = optarg;
+ break;
+#endif
case 'k':
kflag = 1;
break;
@@ -243,11 +315,14 @@
lflag = 1;
break;
case 'M':
-#ifndef WITH_STATS
- errx(1, "-M requires stats(3) support");
-#else
- FreeBSD_Mflag = 1;
-#endif
+ ttl = strtonum(optarg, 0, 255, &errstr);
+ if (errstr)
+ errx(1, "ttl is %s", errstr);
+ break;
+ case 'm':
+ minttl = strtonum(optarg, 0, 255, &errstr);
+ if (errstr)
+ errx(1, "minttl is %s", errstr);
break;
case 'N':
Nflag = 1;
@@ -255,15 +330,18 @@
case 'n':
nflag = 1;
break;
- case 'o':
- fprintf(stderr, "option -o is deprecated.\n");
- break;
case 'P':
Pflag = optarg;
break;
case 'p':
pflag = optarg;
break;
+#ifdef __OpenBSD__
+ case 'R':
+ tls_cachanged = 1;
+ Rflag = optarg;
+ break;
+#endif
case 'r':
rflag = 1;
break;
@@ -287,6 +365,11 @@
case 'v':
vflag = 1;
break;
+ case 'W':
+ recvlimit = strtonum(optarg, 1, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "receive limit %s: %s", errstr, optarg);
+ break;
case 'w':
timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr);
if (errstr)
@@ -298,6 +381,12 @@
if ((proxy = strdup(optarg)) == NULL)
err(1, NULL);
break;
+ case 'Z':
+ if (strcmp(optarg, "-") == 0)
+ Zflag = stderr;
+ else if ((Zflag = fopen(optarg, "w")) == NULL)
+ err(1, "can't open %s", optarg);
+ break;
case 'z':
zflag = 1;
break;
@@ -318,13 +407,22 @@
errstr, optarg);
}
break;
+#ifdef __OpenBSD__
+ case 'o':
+ oflag = optarg;
+ break;
+#endif
case 'S':
Sflag = 1;
break;
case 'T':
errstr = NULL;
errno = 0;
- if (map_tos(optarg, &Tflag))
+#ifdef __OpenBSD__
+ if (process_tls_opt(optarg, &TLSopt))
+ break;
+#endif
+ if (process_tos_opt(optarg, &Tflag))
break;
if (strlen(optarg) > 1 && optarg[0] == '0' &&
optarg[1] == 'x')
@@ -333,7 +431,7 @@
Tflag = (int)strtonum(optarg, 0, 255,
&errstr);
if (Tflag < 0 || Tflag > 255 || errstr || errno)
- errx(1, "illegal tos value %s", optarg);
+ errx(1, "illegal tos/tls value %s", optarg);
break;
case FREEBSD_TUN:
tundev = optarg;
@@ -348,21 +446,81 @@
argc -= optind;
argv += optind;
+#ifdef __OpenBSD__
+ if (rtableid >= 0)
+ if (setrtable(rtableid) == -1)
+ err(1, "setrtable");
+#endif
+
/* Cruft to make sure options are clean, and used properly. */
- if (argv[0] && !argv[1] && family == AF_UNIX) {
+ if (argc == 1 && family == AF_UNIX) {
host = argv[0];
- uport = NULL;
- } else if (argv[0] && !argv[1]) {
- if (!lflag)
- usage(1);
+ } else if (argc == 1 && lflag) {
uport = argv[0];
- host = NULL;
- } else if (argv[0] && argv[1]) {
+ } else if (argc == 2) {
host = argv[0];
uport = argv[1];
} else
usage(1);
+#ifdef __OpenBSD__
+ if (usetls) {
+ if (Cflag && unveil(Cflag, "r") == -1)
+ err(1, "unveil %s", Cflag);
+ if (unveil(Rflag, "r") == -1)
+ err(1, "unveil %s", Rflag);
+ if (Kflag && unveil(Kflag, "r") == -1)
+ err(1, "unveil %s", Kflag);
+ if (oflag && unveil(oflag, "r") == -1)
+ err(1, "unveil %s", oflag);
+ } else if (family == AF_UNIX && uflag && lflag && !kflag) {
+ /*
+ * After recvfrom(2) from client, the server connects
+ * to the client socket. As the client path is determined
+ * during runtime, we cannot unveil(2).
+ */
+ } else {
+ if (family == AF_UNIX) {
+ if (unveil(host, "rwc") == -1)
+ err(1, "unveil %s", host);
+ if (uflag && !kflag) {
+ if (sflag) {
+ if (unveil(sflag, "rwc") == -1)
+ err(1, "unveil %s", sflag);
+ } else {
+ if (unveil("/tmp", "rwc") == -1)
+ err(1, "unveil /tmp");
+ }
+ }
+ } else {
+ /* no filesystem visibility */
+ if (unveil("/", "") == -1)
+ err(1, "unveil /");
+ }
+ }
+
+ if (family == AF_UNIX) {
+ if (pledge("stdio rpath wpath cpath tmppath unix", NULL) == -1)
+ err(1, "pledge");
+ } else if (Fflag && Pflag) {
+ if (pledge("stdio inet dns sendfd tty", NULL) == -1)
+ err(1, "pledge");
+ } else if (Fflag) {
+ if (pledge("stdio inet dns sendfd", NULL) == -1)
+ err(1, "pledge");
+ } else if (Pflag && usetls) {
+ if (pledge("stdio rpath inet dns tty", NULL) == -1)
+ err(1, "pledge");
+ } else if (Pflag) {
+ if (pledge("stdio inet dns tty", NULL) == -1)
+ err(1, "pledge");
+ } else if (usetls) {
+ if (pledge("stdio rpath inet dns", NULL) == -1)
+ err(1, "pledge");
+ } else if (pledge("stdio inet dns", NULL) == -1)
+ err(1, "pledge");
+#endif
+
if (lflag && sflag)
errx(1, "cannot use -s and -l");
if (lflag && pflag)
@@ -384,6 +542,30 @@
if (tun_fd == -1)
errx(1, "unable to open tun device %s", tundev);
}
+ if (uflag && usetls)
+ errx(1, "cannot use -c and -u");
+ if ((family == AF_UNIX) && usetls)
+ errx(1, "cannot use -c and -U");
+ if ((family == AF_UNIX) && Fflag)
+ errx(1, "cannot use -F and -U");
+ if (Fflag && usetls)
+ errx(1, "cannot use -c and -F");
+ 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 (Zflag && !usetls)
+ errx(1, "you must specify -c to use -Z");
+ if (oflag && !Cflag)
+ errx(1, "you must specify -C to use -o");
+ 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 */
if ((family == AF_UNIX) && uflag && !lflag) {
@@ -391,7 +573,7 @@
unix_dg_tmp_socket = sflag;
} else {
strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
- UNIX_DG_TMP_SOCKET_SIZE);
+ UNIX_DG_TMP_SOCKET_SIZE);
if (mktemp(unix_dg_tmp_socket_buf) == NULL)
err(1, "mktemp");
unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
@@ -422,15 +604,29 @@
if (family == AF_UNIX)
errx(1, "no proxy support for unix sockets");
- /* XXX IPv6 transport to proxy would probably work */
- if (family == AF_INET6)
- errx(1, "no proxy support for IPv6");
-
if (sflag)
errx(1, "no proxy support for local source address");
- proxyhost = strsep(&proxy, ":");
- proxyport = proxy;
+ if (*proxy == '[') {
+ ++proxy;
+ proxyport = strchr(proxy, ']');
+ if (proxyport == NULL)
+ errx(1, "missing closing bracket in proxy");
+ *proxyport++ = '\0';
+ if (*proxyport == '\0')
+ /* Use default proxy port. */
+ proxyport = NULL;
+ else {
+ if (*proxyport == ':')
+ ++proxyport;
+ else
+ errx(1, "garbage proxy port delimiter");
+ }
+ } else {
+ proxyport = strrchr(proxy, ':');
+ if (proxyport != NULL)
+ *proxyport++ = '\0';
+ }
memset(&proxyhints, 0, sizeof(struct addrinfo));
proxyhints.ai_family = family;
@@ -440,75 +636,155 @@
proxyhints.ai_flags |= AI_NUMERICHOST;
}
+#ifdef __OpenBSD__
+ if (usetls) {
+ if ((tls_cfg = tls_config_new()) == NULL)
+ errx(1, "unable to allocate TLS config");
+ if (Rflag && tls_config_set_ca_file(tls_cfg, Rflag) == -1)
+ errx(1, "%s", tls_config_error(tls_cfg));
+ if (Cflag && tls_config_set_cert_file(tls_cfg, Cflag) == -1)
+ errx(1, "%s", tls_config_error(tls_cfg));
+ if (Kflag && tls_config_set_key_file(tls_cfg, Kflag) == -1)
+ errx(1, "%s", tls_config_error(tls_cfg));
+ if (oflag && tls_config_set_ocsp_staple_file(tls_cfg, oflag) == -1)
+ errx(1, "%s", tls_config_error(tls_cfg));
+ if (tls_config_parse_protocols(&protocols, tls_protocols) == -1)
+ errx(1, "invalid TLS protocols `%s'", tls_protocols);
+ if (tls_config_set_protocols(tls_cfg, protocols) == -1)
+ errx(1, "%s", tls_config_error(tls_cfg));
+ if (tls_config_set_ciphers(tls_cfg, tls_ciphers) == -1)
+ errx(1, "%s", tls_config_error(tls_cfg));
+ 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 (TLSopt & TLS_MUSTSTAPLE)
+ tls_config_ocsp_require_stapling(tls_cfg);
+
+ if (Pflag) {
+ if (pledge("stdio inet dns tty", NULL) == -1)
+ err(1, "pledge");
+ } else if (pledge("stdio inet dns", NULL) == -1)
+ err(1, "pledge");
+ }
+#endif
if (lflag) {
- int connfd;
ret = 0;
if (family == AF_UNIX) {
if (uflag)
- s = unix_bind(host);
+ s = unix_bind(host, 0);
else
s = unix_listen(host);
}
+#ifdef __OpenBSD__
+ 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));
+ }
+#endif
/* Allow only one connection at a time, but stay alive. */
for (;;) {
- if (family != AF_UNIX)
+ if (family != AF_UNIX) {
+ if (s != -1)
+ close(s);
s = local_listen(host, uport, hints);
- if (s < 0)
+ }
+ if (s == -1)
err(1, NULL);
- /*
- * For UDP and -k, don't connect the socket, let it
- * receive datagrams from multiple socket pairs.
- */
- if (uflag && kflag)
- readwrite(s);
- /*
- * For UDP and not -k, we will use recvfrom() initially
- * to wait for a caller, then use the regular functions
- * to talk to the caller.
- */
- else if (uflag && !kflag) {
- int rv, plen;
- char buf[16384];
+ if (uflag && kflag) {
+#ifdef __OpenBSD__
+ if (family == AF_UNIX) {
+ if (pledge("stdio unix", NULL) == -1)
+ err(1, "pledge");
+ }
+#endif
+ /*
+ * For UDP and -k, don't connect the socket,
+ * let it receive datagrams from multiple
+ * socket pairs.
+ */
+ readwrite(s, NULL);
+ } else if (uflag && !kflag) {
+ /*
+ * For UDP and not -k, we will use recvfrom()
+ * initially to wait for a caller, then use
+ * the regular functions to talk to the caller.
+ */
+ int rv;
+ char buf[2048];
struct sockaddr_storage z;
len = sizeof(z);
- plen = 2048;
- rv = recvfrom(s, buf, plen, MSG_PEEK,
+ rv = recvfrom(s, buf, sizeof(buf), MSG_PEEK,
(struct sockaddr *)&z, &len);
- if (rv < 0)
+ if (rv == -1)
err(1, "recvfrom");
rv = connect(s, (struct sockaddr *)&z, len);
- if (rv < 0)
+ if (rv == -1)
err(1, "connect");
+#ifdef __OpenBSD__
+ if (family == AF_UNIX) {
+ if (pledge("stdio unix", NULL) == -1)
+ err(1, "pledge");
+ }
+#endif
if (vflag)
- report_connect((struct sockaddr *)&z, len);
+ report_sock("Connection received",
+ (struct sockaddr *)&z, len,
+ family == AF_UNIX ? host : NULL);
- readwrite(s);
+ readwrite(s, NULL);
} else {
+#ifdef __OpenBSD__
+ struct tls *tls_cctx = NULL;
+#endif
+ int connfd;
+
len = sizeof(cliaddr);
- connfd = accept(s, (struct sockaddr *)&cliaddr,
- &len);
+ connfd = accept4(s, (struct sockaddr *)&cliaddr,
+ &len, SOCK_NONBLOCK);
if (connfd == -1) {
/* For now, all errnos are fatal */
err(1, "accept");
}
if (vflag)
- report_connect((struct sockaddr *)&cliaddr, len);
-
- if (FreeBSD_Mflag)
+ report_sock("Connection received",
+ (struct sockaddr *)&cliaddr, len,
+ family == AF_UNIX ? host : NULL);
+#ifdef __OpenBSD__
+ if ((usetls) &&
+ (tls_cctx = tls_setup_server(tls_ctx, connfd, host)))
+ readwrite(connfd, tls_cctx);
+ if (!usetls)
+ readwrite(connfd, NULL);
+ if (tls_cctx)
+ timeout_tls(s, tls_cctx, tls_close);
+#else
+ if (FreeBSD_stats)
FreeBSD_stats_setup(connfd);
- readwrite(connfd);
+ readwrite(connfd, NULL);
+#endif
close(connfd);
+#ifdef __OpenBSD__
+ tls_free(tls_cctx);
+#endif
}
-
- if (family != AF_UNIX)
- close(s);
- else if (uflag) {
- if (connect(s, NULL, 0) < 0)
+ if (family == AF_UNIX && uflag) {
+ if (connect(s, NULL, 0) == -1)
err(1, "connect");
}
@@ -518,16 +794,18 @@
} else if (family == AF_UNIX) {
ret = 0;
- if ((s = unix_connect(host)) > 0 && !zflag) {
- readwrite(s);
+ if ((s = unix_connect(host)) > 0) {
+ if (!zflag)
+ readwrite(s, NULL);
close(s);
- } else
+ } else {
+ warn("%s", host);
ret = 1;
+ }
if (uflag)
unlink(unix_dg_tmp_socket);
- exit(ret);
-
+ return ret;
} else {
int i = 0;
@@ -535,58 +813,76 @@
build_ports(uport);
/* Cycle through portlist, connecting to each port. */
- for (i = 0; portlist[i] != NULL; i++) {
- if (s)
+ for (s = -1, i = 0; portlist[i] != NULL; i++) {
+ if (s != -1)
close(s);
-
+#ifdef __OpenBSD__
+ tls_free(tls_ctx);
+ tls_ctx = NULL;
+
+ 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));
+ }
+#endif
if (xflag)
s = socks_connect(host, portlist[i], hints,
- proxyhost, proxyport, proxyhints, socksv,
+ proxy, proxyport, proxyhints, socksv,
Pflag);
else
- s = remote_connect(host, portlist[i], hints);
+ s = remote_connect(host, portlist[i], hints,
+ ipaddr);
- if (s < 0)
+ if (s == -1)
continue;
ret = 0;
if (vflag || zflag) {
+ int print_info = 1;
+
/* For UDP, make sure we are connected. */
if (uflag) {
- if (udptest(s) == -1) {
+ /* No info on failed or skipped test. */
+ if ((print_info = udptest(s)) == -1) {
ret = 1;
continue;
}
}
-
- /* Don't look up port if -n. */
- if (nflag)
- sv = NULL;
- else {
- sv = getservbyport(
- ntohs(atoi(portlist[i])),
- uflag ? "udp" : "tcp");
- }
-
- fprintf(stderr,
- "Connection to %s %s port [%s/%s] "
- "succeeded!\n", host, portlist[i],
- uflag ? "udp" : "tcp",
- sv ? sv->s_name : "*");
+ if (print_info == 1)
+ connection_info(host, portlist[i],
+ uflag ? "udp" : "tcp", ipaddr);
}
if (Fflag)
fdpass(s);
- else if (!zflag)
- readwrite(s);
+ else {
+#ifdef __OpenBSD__
+ if (usetls)
+ tls_setup_client(tls_ctx, s, host);
+ if (!zflag)
+ readwrite(s, tls_ctx);
+ if (tls_ctx)
+ timeout_tls(s, tls_ctx, tls_close);
+#else
+ if (!zflag)
+ readwrite(s, NULL);
+#endif
+ }
}
}
- if (s)
+ if (s != -1)
close(s);
if (tun_fd != -1)
close(tun_fd);
+#ifdef __OpenBSD__
+ tls_free(tls_ctx);
+ tls_config_free(tls_cfg);
+#endif
- exit(ret);
+ return ret;
}
/*
@@ -594,33 +890,128 @@
* Returns a unix socket bound to the given path
*/
int
-unix_bind(char *path)
+unix_bind(char *path, int flags)
{
- struct sockaddr_un sun;
- int s;
+ struct sockaddr_un s_un;
+ int s, save_errno;
/* Create unix domain socket. */
- if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM,
- 0)) < 0)
- return (-1);
+ if ((s = socket(AF_UNIX, flags | (uflag ? SOCK_DGRAM : SOCK_STREAM),
+ 0)) == -1)
+ return -1;
- memset(&sun, 0, sizeof(struct sockaddr_un));
- sun.sun_family = AF_UNIX;
+ memset(&s_un, 0, sizeof(struct sockaddr_un));
+ s_un.sun_family = AF_UNIX;
- if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
- sizeof(sun.sun_path)) {
+ if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
+ sizeof(s_un.sun_path)) {
close(s);
errno = ENAMETOOLONG;
- return (-1);
+ return -1;
}
- if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+ if (bind(s, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
+ save_errno = errno;
close(s);
- return (-1);
+ errno = save_errno;
+ return -1;
}
- return (s);
+ if (vflag)
+ report_sock("Bound", NULL, 0, path);
+
+ return s;
}
+#ifdef __OpenBSD__
+int
+timeout_tls(int s, struct tls *tls_ctx, int (*func)(struct tls *))
+{
+ struct pollfd pfd;
+ int ret;
+
+ while ((ret = (*func)(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)
+{
+ 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));
+ }
+ if (timeout_tls(s, tls_ctx, tls_handshake) == -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);
+ if (tls_expecthash && (tls_peer_cert_hash(tls_ctx) == NULL ||
+ strcmp(tls_expecthash, tls_peer_cert_hash(tls_ctx)) != 0))
+ errx(1, "peer certificate is not %s", tls_expecthash);
+ if (Zflag) {
+ save_peer_cert(tls_ctx, Zflag);
+ if (Zflag != stderr && (fclose(Zflag) != 0))
+ err(1, "fclose failed saving peer cert");
+ }
+}
+
+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));
+ } else if (timeout_tls(connfd, tls_cctx, tls_handshake) == -1) {
+ if ((errstr = tls_error(tls_cctx)) == NULL)
+ errstr = strerror(errno);
+ warnx("tls handshake failed (%s)", errstr);
+ } else {
+ int gotcert = tls_peer_cert_provided(tls_cctx);
+
+ if (vflag && gotcert)
+ report_tls(tls_cctx, host);
+ if ((TLSopt & TLS_CCERT) && !gotcert)
+ warnx("No client certificate provided");
+ else if (gotcert && tls_expecthash &&
+ (tls_peer_cert_hash(tls_cctx) == NULL ||
+ strcmp(tls_expecthash, tls_peer_cert_hash(tls_cctx)) != 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;
+}
+#endif
+
/*
* unix_connect()
* Returns a socket connected to a local unix socket. Returns -1 on failure.
@@ -628,33 +1019,33 @@
int
unix_connect(char *path)
{
- struct sockaddr_un sun;
- int s;
+ struct sockaddr_un s_un;
+ int s, save_errno;
if (uflag) {
- if ((s = unix_bind(unix_dg_tmp_socket)) < 0)
- return (-1);
+ if ((s = unix_bind(unix_dg_tmp_socket, SOCK_CLOEXEC)) == -1)
+ return -1;
} else {
- if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
- return (-1);
+ if ((s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1)
+ return -1;
}
- (void)fcntl(s, F_SETFD, FD_CLOEXEC);
- memset(&sun, 0, sizeof(struct sockaddr_un));
- sun.sun_family = AF_UNIX;
+ memset(&s_un, 0, sizeof(struct sockaddr_un));
+ s_un.sun_family = AF_UNIX;
- if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
- sizeof(sun.sun_path)) {
+ if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >=
+ sizeof(s_un.sun_path)) {
close(s);
errno = ENAMETOOLONG;
- return (-1);
+ return -1;
}
- if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
+ if (connect(s, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
+ save_errno = errno;
close(s);
- return (-1);
+ errno = save_errno;
+ return -1;
}
- return (s);
-
+ return s;
}
/*
@@ -665,14 +1056,17 @@
unix_listen(char *path)
{
int s;
- if ((s = unix_bind(path)) < 0)
- return (-1);
- if (listen(s, 5) < 0) {
+ if ((s = unix_bind(path, 0)) == -1)
+ return -1;
+ if (listen(s, 5) == -1) {
close(s);
- return (-1);
+ return -1;
}
- return (s);
+ if (vflag)
+ report_sock("Listening", NULL, 0, path);
+
+ return s;
}
/*
@@ -681,18 +1075,19 @@
* port or source address if needed. Returns -1 on failure.
*/
int
-remote_connect(const char *host, const char *port, struct addrinfo hints)
+remote_connect(const char *host, const char *port, struct addrinfo hints,
+ char *ipaddr)
{
struct addrinfo *res, *res0;
- int s, error, on = 1;
+ int s = -1, error, herr, on = 1, save_errno;
- if ((error = getaddrinfo(host, port, &hints, &res)))
- errx(1, "getaddrinfo: %s", gai_strerror(error));
+ if ((error = getaddrinfo(host, port, &hints, &res0)))
+ errx(1, "getaddrinfo for host \"%s\" port %s: %s", host,
+ port, gai_strerror(error));
- res0 = res;
- do {
- if ((s = socket(res0->ai_family, res0->ai_socktype,
- res0->ai_protocol)) < 0)
+ for (res = res0; res; res = res->ai_next) {
+ if ((s = socket(res->ai_family, res->ai_socktype |
+ SOCK_NONBLOCK, res->ai_protocol)) == -1)
continue;
if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB,
@@ -706,7 +1101,7 @@
/* try IP_BINDANY, but don't insist */
setsockopt(s, IPPROTO_IP, IP_BINDANY, &on, sizeof(on));
memset(&ahints, 0, sizeof(struct addrinfo));
- ahints.ai_family = res0->ai_family;
+ ahints.ai_family = res->ai_family;
ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM;
ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP;
ahints.ai_flags = AI_PASSIVE;
@@ -714,26 +1109,49 @@
errx(1, "getaddrinfo: %s", gai_strerror(error));
if (bind(s, (struct sockaddr *)ares->ai_addr,
- ares->ai_addrlen) < 0)
+ ares->ai_addrlen) == -1)
err(1, "bind failed");
freeaddrinfo(ares);
}
- set_common_sockopts(s, res0->ai_family);
+ set_common_sockopts(s, res->ai_family);
+
+ if (ipaddr != NULL) {
+ herr = getnameinfo(res->ai_addr, res->ai_addrlen,
+ ipaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ switch (herr) {
+ case 0:
+ break;
+ case EAI_SYSTEM:
+ err(1, "getnameinfo");
+ default:
+ errx(1, "getnameinfo: %s", gai_strerror(herr));
+ }
+ }
- if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
+ if (timeout_connect(s, res->ai_addr, res->ai_addrlen) == 0)
break;
- else if (vflag)
- warn("connect to %s port %s (%s) failed", host, port,
- uflag ? "udp" : "tcp");
+ if (vflag) {
+ /* only print IP if there is something to report */
+ if (nflag || ipaddr == NULL ||
+ (strncmp(host, ipaddr, NI_MAXHOST) == 0))
+ warn("connect to %s port %s (%s) failed", host,
+ port, uflag ? "udp" : "tcp");
+ else
+ warn("connect to %s (%s) port %s (%s) failed",
+ host, ipaddr, port, uflag ? "udp" : "tcp");
+ }
+
+ save_errno = errno;
close(s);
+ errno = save_errno;
s = -1;
- } while ((res0 = res0->ai_next) != NULL);
+ }
- freeaddrinfo(res);
+ freeaddrinfo(res0);
- return (s);
+ return s;
}
int
@@ -741,15 +1159,9 @@
{
struct pollfd pfd;
socklen_t optlen;
- int flags, optval;
+ int optval;
int ret;
- if (timeout != -1) {
- flags = fcntl(s, F_GETFL, 0);
- if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
- err(1, "set non-blocking mode");
- }
-
if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
pfd.fd = s;
pfd.events = POLLOUT;
@@ -767,10 +1179,7 @@
err(1, "poll failed");
}
- if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
- err(1, "restoring flags");
-
- return (ret);
+ return ret;
}
/*
@@ -779,10 +1188,10 @@
* address. Returns -1 on failure.
*/
int
-local_listen(char *host, char *port, struct addrinfo hints)
+local_listen(const char *host, const char *port, struct addrinfo hints)
{
struct addrinfo *res, *res0;
- int s, ret, x = 1;
+ int s = -1, ret, x = 1, save_errno;
int error;
/* Allow nodename to be null. */
@@ -795,13 +1204,12 @@
if (host == NULL && hints.ai_family == AF_UNSPEC)
hints.ai_family = AF_INET;
- if ((error = getaddrinfo(host, port, &hints, &res)))
+ if ((error = getaddrinfo(host, port, &hints, &res0)))
errx(1, "getaddrinfo: %s", gai_strerror(error));
- res0 = res;
- do {
- if ((s = socket(res0->ai_family, res0->ai_socktype,
- res0->ai_protocol)) < 0)
+ for (res = res0; res; res = res->ai_next) {
+ if ((s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol)) == -1)
continue;
if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_SETFIB,
@@ -818,24 +1226,36 @@
err(1, "disable TCP options");
}
- set_common_sockopts(s, res0->ai_family);
+ set_common_sockopts(s, res->ai_family);
- if (bind(s, (struct sockaddr *)res0->ai_addr,
- res0->ai_addrlen) == 0)
+ if (bind(s, (struct sockaddr *)res->ai_addr,
+ res->ai_addrlen) == 0)
break;
+ save_errno = errno;
close(s);
+ errno = save_errno;
s = -1;
- } while ((res0 = res0->ai_next) != NULL);
+ }
if (!uflag && s != -1) {
- if (listen(s, 1) < 0)
+ if (listen(s, 1) == -1)
err(1, "listen");
}
+ if (vflag && s != -1) {
+ struct sockaddr_storage ss;
+ socklen_t len;
+
+ len = sizeof(ss);
+ if (getsockname(s, (struct sockaddr *)&ss, &len) == -1)
+ err(1, "getsockname");
+ report_sock(uflag ? "Bound" : "Listening",
+ (struct sockaddr *)&ss, len, NULL);
+ }
- freeaddrinfo(res);
+ freeaddrinfo(res0);
- return (s);
+ return s;
}
/*
@@ -843,7 +1263,11 @@
* Loop that polls on the network file descriptor and stdin.
*/
void
-readwrite(int net_fd)
+#ifdef __OpenBSD__
+readwrite(int net_fd, struct tls *tls_ctx)
+#else
+readwrite(int net_fd, void *tls_ctx)
+#endif
{
struct pollfd pfd[4];
int stdin_fd = STDIN_FILENO;
@@ -878,29 +1302,25 @@
while (1) {
/* both inputs are gone, buffers are empty, we are done */
- if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1
- && stdinbufpos == 0 && netinbufpos == 0) {
- if (FreeBSD_Mflag && !stats_printed)
+ if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 &&
+ stdinbufpos == 0 && netinbufpos == 0) {
+ if (FreeBSD_stats && !stats_printed)
FreeBSD_stats_print(net_fd);
- close(net_fd);
return;
}
/* both outputs are gone, we can't continue */
if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) {
- if (FreeBSD_Mflag && !stats_printed)
+ if (FreeBSD_stats && !stats_printed)
FreeBSD_stats_print(net_fd);
- close(net_fd);
return;
}
/* listen and net in gone, queues empty, done */
- if (lflag && pfd[POLL_NETIN].fd == -1
- && stdinbufpos == 0 && netinbufpos == 0) {
- if (FreeBSD_Mflag && !stats_printed)
+ if (lflag && pfd[POLL_NETIN].fd == -1 &&
+ stdinbufpos == 0 && netinbufpos == 0) {
+ if (FreeBSD_stats && !stats_printed)
FreeBSD_stats_print(net_fd);
- close(net_fd);
return;
}
-
/* help says -i is for "wait between lines sent". We read and
* write arbitrary amounts of data, and we don't want to start
* scanning for newlines, so this is as good as it gets */
@@ -911,14 +1331,12 @@
num_fds = poll(pfd, 4, timeout);
/* treat poll errors */
- if (num_fds == -1) {
- close(net_fd);
+ if (num_fds == -1)
err(1, "polling error");
- }
/* timeout happened */
if (num_fds == 0) {
- if (FreeBSD_Mflag)
+ if (FreeBSD_stats)
FreeBSD_stats_print(net_fd);
return;
}
@@ -932,16 +1350,16 @@
/* reading is possible after HUP */
if (pfd[POLL_STDIN].events & POLLIN &&
pfd[POLL_STDIN].revents & POLLHUP &&
- ! (pfd[POLL_STDIN].revents & POLLIN))
- pfd[POLL_STDIN].fd = -1;
+ !(pfd[POLL_STDIN].revents & POLLIN))
+ pfd[POLL_STDIN].fd = -1;
if (pfd[POLL_NETIN].events & POLLIN &&
pfd[POLL_NETIN].revents & POLLHUP &&
- ! (pfd[POLL_NETIN].revents & POLLIN))
- pfd[POLL_NETIN].fd = -1;
+ !(pfd[POLL_NETIN].revents & POLLIN))
+ pfd[POLL_NETIN].fd = -1;
if (pfd[POLL_NETOUT].revents & POLLHUP) {
- if (Nflag)
+ if (pfd[POLL_NETOUT].fd != -1 && Nflag)
shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
pfd[POLL_NETOUT].fd = -1;
}
@@ -961,9 +1379,16 @@
/* try to read from stdin */
if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
- &stdinbufpos);
- /* error or eof on stdin - remove from pfd */
+ &stdinbufpos, NULL);
+#ifdef __OpenBSD__
+ 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
if (ret == 0 || ret == -1)
+#endif
pfd[POLL_STDIN].fd = -1;
/* read something - poll net out */
if (stdinbufpos > 0)
@@ -975,8 +1400,16 @@
/* try to write to network */
if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
- &stdinbufpos, FreeBSD_crlf);
+ &stdinbufpos, tls_ctx, FreeBSD_crlf);
+#ifdef __OpenBSD__
+ 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
if (ret == -1)
+#endif
pfd[POLL_NETOUT].fd = -1;
/* buffer empty - remove self from polling */
if (stdinbufpos == 0)
@@ -988,14 +1421,28 @@
/* try to read from network */
if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
- &netinbufpos);
+ &netinbufpos, tls_ctx);
+#ifdef __OpenBSD__
+ 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
if (ret == -1)
+#endif
pfd[POLL_NETIN].fd = -1;
/* eof on net in - remove from pfd */
if (ret == 0) {
shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
pfd[POLL_NETIN].fd = -1;
}
+ if (recvlimit > 0 && ++recvcount >= recvlimit) {
+ if (pfd[POLL_NETIN].fd != -1)
+ shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
+ pfd[POLL_NETIN].fd = -1;
+ pfd[POLL_STDIN].fd = -1;
+ }
/* read something - poll stdout */
if (netinbufpos > 0)
pfd[POLL_STDOUT].events = POLLOUT;
@@ -1003,15 +1450,23 @@
if (netinbufpos == BUFSIZE)
pfd[POLL_NETIN].events = 0;
/* handle telnet */
- if (tflag)
+ if (pfd[POLL_NETIN].fd != -1 && tflag)
atelnet(pfd[POLL_NETIN].fd, netinbuf,
netinbufpos);
}
/* try to write to stdout */
if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
- &netinbufpos, 0);
+ &netinbufpos, NULL, 0);
+#ifdef __OpenBSD__
+ 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
if (ret == -1)
+#endif
pfd[POLL_STDOUT].fd = -1;
/* buffer empty - remove self from polling */
if (netinbufpos == 0)
@@ -1024,7 +1479,7 @@
/* stdin gone and queue empty? */
if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) {
if (pfd[POLL_NETOUT].fd != -1 && Nflag) {
- if (FreeBSD_Mflag) {
+ if (FreeBSD_stats) {
FreeBSD_stats_print(net_fd);
stats_printed = 1;
}
@@ -1048,12 +1503,19 @@
}
ssize_t
-drainbuf(int fd, unsigned char *buf, size_t *bufpos, int crlf)
+#ifdef __OpenBSD__
+drainbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
+#else
+drainbuf(int fd, unsigned char *buf, size_t *bufpos, void *tls __unused, int crlf)
+#endif
{
ssize_t n = *bufpos, n2 = 0;
ssize_t adjust;
unsigned char *lf = NULL;
+ if (fd == -1)
+ return -1;
+
if (crlf) {
lf = memchr(buf, '\n', *bufpos);
if (lf && (lf == buf || *(lf - 1) != '\r'))
@@ -1062,6 +1524,20 @@
lf = NULL;
}
+#ifdef __OpenBSD__
+ if (tls) {
+ n = tls_write(tls, buf, *bufpos);
+ if (n == -1)
+ errx(1, "tls write failed (%s)", tls_error(tls));
+ } else {
+ 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)
+ return n;
+#else
if (n != 0) {
n = write_wrapper(fd, buf, n);
if (n <= 0)
@@ -1074,7 +1550,7 @@
return n2;
n += 1;
}
-
+#endif
/* adjust buffer */
adjust = *bufpos - n;
if (adjust > 0)
@@ -1083,17 +1559,36 @@
return n;
}
-
ssize_t
-fillbuf(int fd, unsigned char *buf, size_t *bufpos)
+#ifdef __OpenBSD__
+fillbuf(int fd, unsigned char *buf, size_t *bufpos, struct tls *tls)
+#else
+fillbuf(int fd, unsigned char *buf, size_t *bufpos, void *tls __unused)
+#endif
{
size_t num = BUFSIZE - *bufpos;
ssize_t n;
+ if (fd == -1)
+ return -1;
+
+#ifdef __OpenBSD__
+ if (tls) {
+ n = tls_read(tls, buf + *bufpos, num);
+ if (n == -1)
+ errx(1, "tls read failed (%s)", tls_error(tls));
+ } else {
+ n = read(fd, buf + *bufpos, num);
+ /* don't treat EAGAIN, EINTR as error */
+ if (n == -1 && (errno == EAGAIN || errno == EINTR))
+ n = TLS_WANT_POLLIN;
+ }
+#else
n = read(fd, buf + *bufpos, num);
/* don't treat EAGAIN, EINTR as error */
if (n == -1 && (errno == EAGAIN || errno == EINTR))
n = -2;
+#endif
if (n <= 0)
return n;
*bufpos += n;
@@ -1122,9 +1617,9 @@
if (isatty(STDOUT_FILENO))
errx(1, "Cannot pass file descriptor to tty");
- bzero(&mh, sizeof(mh));
- bzero(&cmsgbuf, sizeof(cmsgbuf));
- bzero(&iov, sizeof(iov));
+ memset(&mh, 0, sizeof(mh));
+ memset(&cmsgbuf, 0, sizeof(cmsgbuf));
+ memset(&iov, 0, sizeof(iov));
mh.msg_control = (caddr_t)&cmsgbuf.buf;
mh.msg_controllen = sizeof(cmsgbuf.buf);
@@ -1139,7 +1634,7 @@
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
- bzero(&pfd, sizeof(pfd));
+ memset(&pfd, 0, sizeof(pfd));
pfd.fd = STDOUT_FILENO;
pfd.events = POLLOUT;
for (;;) {
@@ -1190,6 +1685,26 @@
}
}
+int
+strtoport(char *portstr, int udp)
+{
+ struct servent *entry;
+ const char *errstr;
+ char *proto;
+ int port = -1;
+
+ proto = udp ? "udp" : "tcp";
+
+ port = strtonum(portstr, 1, PORT_MAX, &errstr);
+ if (errstr == NULL)
+ return port;
+ if (errno != EINVAL)
+ errx(1, "port number %s: %s", errstr, portstr);
+ if ((entry = getservbyname(portstr, proto)) == NULL)
+ errx(1, "service \"%s\" unknown", portstr);
+ return ntohs(entry->s_port);
+}
+
/*
* build_ports()
* Build an array of ports in portlist[], listing each port
@@ -1198,56 +1713,48 @@
void
build_ports(char *p)
{
- const char *errstr;
char *n;
int hi, lo, cp;
int x = 0;
- if ((n = strchr(p, '-')) != NULL) {
+ if (isdigit((unsigned char)*p) && (n = strchr(p, '-')) != NULL) {
*n = '\0';
n++;
/* Make sure the ports are in order: lowest->highest. */
- hi = strtonum(n, 1, PORT_MAX, &errstr);
- if (errstr)
- errx(1, "port number %s: %s", errstr, n);
- lo = strtonum(p, 1, PORT_MAX, &errstr);
- if (errstr)
- errx(1, "port number %s: %s", errstr, p);
-
+ hi = strtoport(n, uflag);
+ lo = strtoport(p, uflag);
if (lo > hi) {
cp = hi;
hi = lo;
lo = cp;
}
- /* Load ports sequentially. */
- for (cp = lo; cp <= hi; cp++) {
- portlist[x] = calloc(1, PORT_MAX_LEN);
- if (portlist[x] == NULL)
- err(1, NULL);
- snprintf(portlist[x], PORT_MAX_LEN, "%d", cp);
- x++;
- }
-
- /* Randomly swap ports. */
+ /*
+ * Initialize portlist with a random permutation. Based on
+ * Knuth, as in ip_randomid() in sys/netinet/ip_id.c.
+ */
if (rflag) {
- int y;
- char *c;
-
- for (x = 0; x <= (hi - lo); x++) {
- y = (arc4random() & 0xFFFF) % (hi - lo);
- c = portlist[x];
- portlist[x] = portlist[y];
- portlist[y] = c;
+ for (x = 0; x <= hi - lo; x++) {
+ cp = arc4random_uniform(x + 1);
+ portlist[x] = portlist[cp];
+ if (asprintf(&portlist[cp], "%d", x + lo) == -1)
+ err(1, "asprintf");
+ }
+ } else { /* Load ports sequentially. */
+ for (cp = lo; cp <= hi; cp++) {
+ if (asprintf(&portlist[x], "%d", cp) == -1)
+ err(1, "asprintf");
+ x++;
}
}
} else {
- hi = strtonum(p, 1, PORT_MAX, &errstr);
- if (errstr)
- errx(1, "port number %s: %s", errstr, p);
- portlist[0] = strdup(p);
- if (portlist[0] == NULL)
+ char *tmp;
+
+ hi = strtoport(p, uflag);
+ if (asprintf(&tmp, "%d", hi) != -1)
+ portlist[0] = tmp;
+ else
err(1, NULL);
}
}
@@ -1262,13 +1769,43 @@
{
int i, ret;
+ /* Only write to the socket in scan mode or interactive mode. */
+ if (!zflag && !isatty(STDIN_FILENO))
+ return 0;
+
for (i = 0; i <= 3; i++) {
if (write(s, "X", 1) == 1)
ret = 1;
else
ret = -1;
}
- return (ret);
+ return ret;
+}
+
+void
+connection_info(const char *host, const char *port, const char *proto,
+ const char *ipaddr)
+{
+ struct servent *sv;
+ char *service = "*";
+
+ /* Look up service name unless -n. */
+ if (!nflag) {
+ sv = getservbyport(ntohs(atoi(port)), proto);
+ if (sv != NULL)
+ service = sv->s_name;
+ }
+
+ fprintf(stderr, "Connection to %s", host);
+
+ /*
+ * if we aren't connecting thru a proxy and
+ * there is something to report, print IP
+ */
+ if (!nflag && !xflag && strcmp(host, ipaddr) != 0)
+ fprintf(stderr, " (%s)", ipaddr);
+
+ fprintf(stderr, " %s port [%s/%s] succeeded!\n", port, proto, service);
}
void
@@ -1276,7 +1813,7 @@
{
if (setsockopt(s, IPPROTO_TCP, TCP_STATS,
- &FreeBSD_Mflag, sizeof(FreeBSD_Mflag)) == -1) {
+ &FreeBSD_stats, sizeof(FreeBSD_stats)) == -1) {
if (errno == EOPNOTSUPP) {
warnx("getsockopt(TCP_STATS) failed; "
"kernel built without \"options STATS\"?");
@@ -1339,27 +1876,22 @@
if (Sflag) {
if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG,
- &x, sizeof(x)) == -1)
+ &x, sizeof(x)) == -1)
err(1, NULL);
}
if (Dflag) {
if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
- &x, sizeof(x)) == -1)
+ &x, sizeof(x)) == -1)
err(1, NULL);
}
if (Tflag != -1) {
- int proto, option;
-
- if (af == AF_INET6) {
- proto = IPPROTO_IPV6;
- option = IPV6_TCLASS;
- } else {
- proto = IPPROTO_IP;
- option = IP_TOS;
- }
-
- if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1)
+ if (af == AF_INET && setsockopt(s, IPPROTO_IP,
+ IP_TOS, &Tflag, sizeof(Tflag)) == -1)
err(1, "set IP ToS");
+
+ else if (af == AF_INET6 && setsockopt(s, IPPROTO_IPV6,
+ IPV6_TCLASS, &Tflag, sizeof(Tflag)) == -1)
+ err(1, "set IPv6 traffic class");
}
if (Iflag) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
@@ -1376,7 +1908,7 @@
&FreeBSD_Oflag, sizeof(FreeBSD_Oflag)) == -1)
err(1, "disable TCP options");
}
- if (FreeBSD_Mflag)
+ if (FreeBSD_stats)
FreeBSD_stats_setup(s);
#ifdef IPSEC
if (ipsec_policy[0] != NULL)
@@ -1384,10 +1916,35 @@
if (ipsec_policy[1] != NULL)
add_ipsec_policy(s, af, ipsec_policy[1]);
#endif
+
+ if (ttl != -1) {
+ if (af == AF_INET && setsockopt(s, IPPROTO_IP,
+ IP_TTL, &ttl, sizeof(ttl)))
+ err(1, "set IP TTL");
+
+ else if (af == AF_INET6 && setsockopt(s, IPPROTO_IPV6,
+ IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)))
+ err(1, "set IPv6 unicast hops");
+ }
+
+ if (minttl != -1) {
+ if (af == AF_INET && setsockopt(s, IPPROTO_IP,
+ IP_MINTTL, &minttl, sizeof(minttl)))
+ err(1, "set IP min TTL");
+
+#ifdef __OpenBSD__
+ else if (af == AF_INET6 && setsockopt(s, IPPROTO_IPV6,
+ IPV6_MINHOPCOUNT, &minttl, sizeof(minttl)))
+ err(1, "set IPv6 min hop count");
+#else
+ else if (af == AF_INET6)
+ warn("Unable to set IPv6 min hop count");
+#endif
+ }
}
int
-map_tos(char *s, int *val)
+process_tos_opt(char *s, int *val)
{
/* DiffServ Codepoints and other TOS mappings */
const struct toskeywords {
@@ -1421,43 +1978,163 @@
{ "netcontrol", IPTOS_PREC_NETCONTROL },
{ "reliability", IPTOS_RELIABILITY },
{ "throughput", IPTOS_THROUGHPUT },
- { NULL, -1 },
+ { NULL, -1 },
};
for (t = toskeywords; t->keyword != NULL; t++) {
if (strcmp(s, t->keyword) == 0) {
*val = t->val;
- return (1);
+ return 1;
}
}
- return (0);
+ return 0;
+}
+
+#ifdef __OpenBSD__
+int
+process_tls_opt(char *s, int *flags)
+{
+ size_t len;
+ char *v;
+
+ const struct tlskeywords {
+ const char *keyword;
+ int flag;
+ char **value;
+ } *t, tlskeywords[] = {
+ { "ciphers", -1, &tls_ciphers },
+ { "clientcert", TLS_CCERT, NULL },
+ { "muststaple", TLS_MUSTSTAPLE, NULL },
+ { "noverify", TLS_NOVERIFY, NULL },
+ { "noname", TLS_NONAME, NULL },
+ { "protocols", -1, &tls_protocols },
+ { NULL, -1, NULL },
+ };
+
+ len = strlen(s);
+ if ((v = strchr(s, '=')) != NULL) {
+ len = v - s;
+ v++;
+ }
+
+ for (t = tlskeywords; t->keyword != NULL; t++) {
+ if (strlen(t->keyword) == len &&
+ strncmp(s, t->keyword, len) == 0) {
+ if (t->value != NULL) {
+ if (v == NULL)
+ errx(1, "invalid tls value `%s'", s);
+ *t->value = v;
+ } else {
+ *flags |= t->flag;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+save_peer_cert(struct tls *tls_ctx, FILE *fp)
+{
+ const char *pem;
+ size_t plen;
+
+ if ((pem = tls_peer_cert_chain_pem(tls_ctx, &plen)) == NULL)
+ errx(1, "Can't get peer certificate");
+ if (fprintf(fp, "%.*s", (int)plen, pem) < 0)
+ err(1, "unable to save peer cert");
+ if (fflush(fp) != 0)
+ err(1, "unable to flush peer cert");
}
void
-report_connect(const struct sockaddr *sa, socklen_t salen)
+report_tls(struct tls *tls_ctx, char *host)
{
- char remote_host[NI_MAXHOST];
- char remote_port[NI_MAXSERV];
+ time_t t;
+ const char *ocsp_url;
+
+ fprintf(stderr, "TLS handshake negotiated %s/%s with host %s\n",
+ tls_conn_version(tls_ctx), tls_conn_cipher(tls_ctx), host);
+ fprintf(stderr, "Peer name: %s\n",
+ tls_expectname ? tls_expectname : host);
+ if (tls_peer_cert_subject(tls_ctx))
+ fprintf(stderr, "Subject: %s\n",
+ tls_peer_cert_subject(tls_ctx));
+ if (tls_peer_cert_issuer(tls_ctx))
+ fprintf(stderr, "Issuer: %s\n",
+ tls_peer_cert_issuer(tls_ctx));
+ if ((t = tls_peer_cert_notbefore(tls_ctx)) != -1)
+ fprintf(stderr, "Valid From: %s", ctime(&t));
+ if ((t = tls_peer_cert_notafter(tls_ctx)) != -1)
+ fprintf(stderr, "Valid Until: %s", ctime(&t));
+ if (tls_peer_cert_hash(tls_ctx))
+ fprintf(stderr, "Cert Hash: %s\n",
+ tls_peer_cert_hash(tls_ctx));
+ ocsp_url = tls_peer_ocsp_url(tls_ctx);
+ if (ocsp_url != NULL)
+ fprintf(stderr, "OCSP URL: %s\n", ocsp_url);
+ switch (tls_peer_ocsp_response_status(tls_ctx)) {
+ case TLS_OCSP_RESPONSE_SUCCESSFUL:
+ fprintf(stderr, "OCSP Stapling: %s\n",
+ tls_peer_ocsp_result(tls_ctx) == NULL ? "" :
+ tls_peer_ocsp_result(tls_ctx));
+ fprintf(stderr,
+ " response_status=%d cert_status=%d crl_reason=%d\n",
+ tls_peer_ocsp_response_status(tls_ctx),
+ tls_peer_ocsp_cert_status(tls_ctx),
+ tls_peer_ocsp_crl_reason(tls_ctx));
+ t = tls_peer_ocsp_this_update(tls_ctx);
+ fprintf(stderr, " this update: %s",
+ t != -1 ? ctime(&t) : "\n");
+ t = tls_peer_ocsp_next_update(tls_ctx);
+ fprintf(stderr, " next update: %s",
+ t != -1 ? ctime(&t) : "\n");
+ t = tls_peer_ocsp_revocation_time(tls_ctx);
+ fprintf(stderr, " revocation: %s",
+ t != -1 ? ctime(&t) : "\n");
+ break;
+ case -1:
+ break;
+ default:
+ fprintf(stderr,
+ "OCSP Stapling: failure - response_status %d (%s)\n",
+ tls_peer_ocsp_response_status(tls_ctx),
+ tls_peer_ocsp_result(tls_ctx) == NULL ? "" :
+ tls_peer_ocsp_result(tls_ctx));
+ break;
+ }
+}
+#endif
+
+void
+report_sock(const char *msg, const struct sockaddr *sa, socklen_t salen,
+ char *path)
+{
+ char host[NI_MAXHOST], port[NI_MAXSERV];
int herr;
int flags = NI_NUMERICSERV;
-
+
+ if (path != NULL) {
+ fprintf(stderr, "%s on %s\n", msg, path);
+ return;
+ }
+
if (nflag)
flags |= NI_NUMERICHOST;
-
- if ((herr = getnameinfo(sa, salen,
- remote_host, sizeof(remote_host),
- remote_port, sizeof(remote_port),
- flags)) != 0) {
- if (herr == EAI_SYSTEM)
- err(1, "getnameinfo");
- else
- errx(1, "getnameinfo: %s", gai_strerror(herr));
+
+ herr = getnameinfo(sa, salen, host, sizeof(host), port, sizeof(port),
+ flags);
+ switch (herr) {
+ case 0:
+ break;
+ case EAI_SYSTEM:
+ err(1, "getnameinfo");
+ default:
+ errx(1, "getnameinfo: %s", gai_strerror(herr));
}
-
- fprintf(stderr,
- "Connection from %s %s "
- "received!\n", remote_host, remote_port);
+
+ fprintf(stderr, "%s on %s %s\n", msg, host, port);
}
void
@@ -1467,7 +2144,7 @@
fprintf(stderr, "\tCommand Summary:\n\
\t-4 Use IPv4\n\
\t-6 Use IPv6\n\
- \t--crlf Convert LF into CRLF when sending data over the network\n\
+ \t--crlf\t Convert LF into CRLF when sending data over the network\n\
\t-D Enable the debug socket option\n\
\t-d Detach from stdin\n");
#ifdef IPSEC
@@ -1479,27 +2156,31 @@
\t-F Pass socket fd\n\
\t-h This help text\n\
\t-I length TCP receive buffer length\n\
- \t-i secs\t Delay interval for lines sent, ports scanned\n\
+ \t-i interval Delay interval for lines sent, ports scanned\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\
+ \t-m minttl Minimum incoming TTL / Hop Limit\n\
\t-N Shutdown the network socket after EOF on stdin\n\
\t-n Suppress name/port resolutions\n\
\t--no-tcpopt Disable TCP options\n\
- \t--sctp\t SCTP mode\n\
- \t--tun tundev Use tun device rather than stdio\n\
\t-O length TCP send buffer length\n\
\t-P proxyuser\tUsername for proxy authentication\n\
\t-p port\t Specify local port for remote connects\n\
\t-r Randomize remote ports\n\
\t-S Enable the TCP MD5 signature option\n\
- \t-s addr\t Local source address\n\
- \t-T toskeyword\tSet IP Type of Service\n\
+ \t-s sourceaddr Local source address\n\
+ \t--sctp\t SCTP mode\n\
+ \t--stats\t Report TCP_STATS via the stats(3) interface\n\
+ \t-T keyword TOS value or TLS options\n\
\t-t Answer TELNET negotiation\n\
+ \t--tun tundev Use tun device rather than stdio\n\
\t-U Use UNIX domain socket\n\
\t-u UDP mode\n\
- \t-V rtable Specify alternate routing table\n\
+ \t-V FIB\t Specify alternate routing table\n\
\t-v Verbose\n\
- \t-w secs\t Timeout for connects and final net reads\n\
+ \t-W recvlimit Terminate after receiving a number of packets\n\
+ \t-w timeout Timeout for connects and final net reads\n\
\t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\
\t-x addr[:port]\tSpecify proxy address and port\n\
\t-z Zero-I/O mode [used for scanning]\n\
@@ -1541,14 +2222,14 @@
{
fprintf(stderr,
#ifdef IPSEC
- "usage: nc [-46DdEFhklNnrStUuvz] [-e policy] [-I length] [-i interval] [-O length]\n"
+ "usage: nc [-46DdEFhklNnrStUuvz] [--crlf] [-e policy] [-I length] [-i interval]\n"
#else
- "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n"
+ "usage: nc [-46DdFhklNnrStUuvz] [--crlf] [-I length] [-i interval]\n"
#endif
- "\t [--no-tcpopt] [--sctp]\n"
- "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n"
- "\t [--tun tundev] [-V rtable] [-w timeout] [-X proxy_protocol]\n"
- "\t [-x proxy_address[:port]] [destination] [port]\n");
+ "\t [-M ttl] [-m minttl] [--no-tcpopt] [-O length] [-P proxy_username]\n"
+ "\t [-p source_port] [-s sourceaddr] [--sctp] [--stats] [-T ToS]\n"
+ "\t [--tun tundev] [-V FIB] [-W recvlimit] [-w timeout]\n"
+ "\t [-X proxy_protocol] [-x proxy_address[:port]] [destination] [port]\n");
if (ret)
exit(1);
}
diff --git a/contrib/netcat/socks.c b/contrib/netcat/socks.c
--- a/contrib/netcat/socks.c
+++ b/contrib/netcat/socks.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: socks.c,v 1.21 2015/03/26 21:19:51 tobias Exp $ */
+/* $OpenBSD: socks.c,v 1.31 2022/06/08 20:20:26 djm Exp $ */
/*
* Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
@@ -53,7 +53,7 @@
#define SOCKS_DOMAIN 3
#define SOCKS_IPV6 4
-int remote_connect(const char *, const char *, struct addrinfo);
+int remote_connect(const char *, const char *, struct addrinfo, char *);
int socks_connect(const char *, const char *, struct addrinfo,
const char *, const char *, struct addrinfo, int,
const char *);
@@ -65,7 +65,7 @@
int r;
struct addrinfo hints, *res;
- bzero(&hints, sizeof(hints));
+ memset(&hints, 0, sizeof(hints));
hints.ai_family = v4only ? PF_INET : PF_UNSPEC;
hints.ai_flags = numeric ? AI_NUMERICHOST : 0;
hints.ai_socktype = SOCK_STREAM;
@@ -109,17 +109,68 @@
return (off);
}
-static const char *
-getproxypass(const char *proxyuser, const char *proxyhost)
+static void
+getproxypass(const char *proxyuser, const char *proxyhost,
+ char *pw, size_t pwlen)
{
char prompt[512];
- static char pw[256];
snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ",
proxyuser, proxyhost);
- if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL)
+ if (readpassphrase(prompt, pw, pwlen, RPP_REQUIRE_TTY) == NULL)
errx(1, "Unable to read proxy passphrase");
- return (pw);
+}
+
+/*
+ * Error strings adapted from the generally accepted SOCKSv4 spec:
+ *
+ * http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol
+ */
+static const char *
+socks4_strerror(int e)
+{
+ switch (e) {
+ case 90:
+ return "Succeeded";
+ case 91:
+ return "Request rejected or failed";
+ case 92:
+ return "SOCKS server cannot connect to identd on the client";
+ case 93:
+ return "Client program and identd report different user-ids";
+ default:
+ return "Unknown error";
+ }
+}
+
+/*
+ * Error strings taken almost directly from RFC 1928.
+ */
+static const char *
+socks5_strerror(int e)
+{
+ switch (e) {
+ case 0:
+ return "Succeeded";
+ case 1:
+ return "General SOCKS server failure";
+ case 2:
+ return "Connection not allowed by ruleset";
+ case 3:
+ return "Network unreachable";
+ case 4:
+ return "Host unreachable";
+ case 5:
+ return "Connection refused";
+ case 6:
+ return "TTL expired";
+ case 7:
+ return "Command not supported";
+ case 8:
+ return "Address type not supported";
+ default:
+ return "Unknown error";
+ }
}
int
@@ -136,7 +187,6 @@
struct sockaddr_in *in4 = (struct sockaddr_in *)&addr;
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
in_port_t serverport;
- const char *proxypass = NULL;
if (proxyport == NULL)
proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT;
@@ -151,7 +201,7 @@
if (authretry++ > 3)
errx(1, "Too many authentication failures");
- proxyfd = remote_connect(proxyhost, proxyport, proxyhints);
+ proxyfd = remote_connect(proxyhost, proxyport, proxyhints, NULL);
if (proxyfd < 0)
return (-1);
@@ -189,7 +239,7 @@
buf[2] = 0;
buf[3] = SOCKS_DOMAIN;
buf[4] = hlen;
- memcpy(buf + 5, host, hlen);
+ memcpy(buf + 5, host, hlen);
memcpy(buf + 5 + hlen, &serverport, sizeof serverport);
wlen = 7 + hlen;
break;
@@ -225,8 +275,10 @@
cnt = atomicio(read, proxyfd, buf, 4);
if (cnt != 4)
err(1, "read failed (%zu/4)", cnt);
- if (buf[1] != 0)
- errx(1, "connection failed, SOCKS error %d", buf[1]);
+ if (buf[1] != 0) {
+ errx(1, "connection failed, SOCKSv5 error: %s",
+ socks5_strerror(buf[1]));
+ }
switch (buf[3]) {
case SOCKS_IPV4:
cnt = atomicio(read, proxyfd, buf + 4, 6);
@@ -261,13 +313,15 @@
cnt = atomicio(read, proxyfd, buf, 8);
if (cnt != 8)
err(1, "read failed (%zu/8)", cnt);
- if (buf[1] != 90)
- errx(1, "connection failed, SOCKS error %d", buf[1]);
+ if (buf[1] != 90) {
+ errx(1, "connection failed, SOCKSv4 error: %s",
+ socks4_strerror(buf[1]));
+ }
} else if (socksv == -1) {
/* HTTP proxy CONNECT */
/* Disallow bad chars in hostname */
- if (strcspn(host, "\r\n\t []:") != strlen(host))
+ if (strcspn(host, "\r\n\t []") != strlen(host))
errx(1, "Invalid hostname");
/* Try to be sane about numeric IPv6 addresses */
@@ -280,7 +334,7 @@
"CONNECT %s:%d HTTP/1.0\r\n",
host, ntohs(serverport));
}
- if (r == -1 || (size_t)r >= sizeof(buf))
+ if (r < 0 || (size_t)r >= sizeof(buf))
errx(1, "hostname too long");
r = strlen(buf);
@@ -289,22 +343,27 @@
err(1, "write failed (%zu/%d)", cnt, r);
if (authretry > 1) {
+ char proxypass[256];
char resp[1024];
- proxypass = getproxypass(proxyuser, proxyhost);
+ getproxypass(proxyuser, proxyhost,
+ proxypass, sizeof proxypass);
r = snprintf(buf, sizeof(buf), "%s:%s",
proxyuser, proxypass);
+ explicit_bzero(proxypass, sizeof proxypass);
if (r == -1 || (size_t)r >= sizeof(buf) ||
b64_ntop(buf, strlen(buf), resp,
sizeof(resp)) == -1)
errx(1, "Proxy username/password too long");
r = snprintf(buf, sizeof(buf), "Proxy-Authorization: "
"Basic %s\r\n", resp);
- if (r == -1 || (size_t)r >= sizeof(buf))
+ if (r < 0 || (size_t)r >= sizeof(buf))
errx(1, "Proxy auth response too long");
r = strlen(buf);
if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != r)
err(1, "write failed (%zu/%d)", cnt, r);
+ explicit_bzero(proxypass, sizeof proxypass);
+ explicit_bzero(buf, sizeof buf);
}
/* Terminate headers */
@@ -314,7 +373,8 @@
/* Read status reply */
proxy_read_line(proxyfd, buf, sizeof(buf));
if (proxyuser != NULL &&
- strncmp(buf, "HTTP/1.0 407 ", 12) == 0) {
+ (strncmp(buf, "HTTP/1.0 407 ", 12) == 0 ||
+ strncmp(buf, "HTTP/1.1 407 ", 12) == 0)) {
if (authretry > 1) {
fprintf(stderr, "Proxy authentication "
"failed\n");

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 22, 8:53 AM (1 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24051712
Default Alt Text
D45537.diff (69 KB)

Event Timeline