Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F132941500
D45537.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
69 KB
Referenced Files
None
Subscribers
None
D45537.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D45537: netcat: Update to OpenBSD 7.5
Attached
Detach File
Event Timeline
Log In to Comment