summaryrefslogtreecommitdiff
path: root/usr.bin/nc/netcat.c
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2013-08-20 16:22:10 +0000
committerDamien Miller <djm@cvs.openbsd.org>2013-08-20 16:22:10 +0000
commit69d2e016ace20c156c976ceedd9a7850dc1879a0 (patch)
treed005e8e23eea28567f70a0e5810bd4775815abcc /usr.bin/nc/netcat.c
parent19a8bd2bcf33c64ad48d54b6138760a0eb180e6b (diff)
add -F flag to enabled fd-pass mode: establish connection and pass
connected socket to stdout. This is useful in proxy mode to establish a connection for use by ssh in conjunction with its new ProxyUseFDPass option; ok markus@
Diffstat (limited to 'usr.bin/nc/netcat.c')
-rw-r--r--usr.bin/nc/netcat.c74
1 files changed, 71 insertions, 3 deletions
diff --git a/usr.bin/nc/netcat.c b/usr.bin/nc/netcat.c
index 571de9a7666..6997b321db2 100644
--- a/usr.bin/nc/netcat.c
+++ b/usr.bin/nc/netcat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: netcat.c,v 1.112 2013/04/29 00:28:23 okan Exp $ */
+/* $OpenBSD: netcat.c,v 1.113 2013/08/20 16:22:09 djm Exp $ */
/*
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
*
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
+#include <sys/uio.h>
#include <sys/un.h>
#include <netinet/in.h>
@@ -66,6 +67,7 @@
/* Command Line Options */
int dflag; /* detached, no stdin */
+int Fflag; /* fdpass sock to stdout */
unsigned int iflag; /* Interval Flag */
int kflag; /* More than one connect */
int lflag; /* Bind to local port */
@@ -97,6 +99,7 @@ void build_ports(char *);
void help(void);
int local_listen(char *, char *, struct addrinfo);
void readwrite(int);
+void fdpass(int nfd) __attribute__((noreturn));
int remote_connect(const char *, const char *, struct addrinfo);
int timeout_connect(int, const struct sockaddr *, socklen_t);
int socks_connect(const char *, const char *, struct addrinfo,
@@ -132,7 +135,7 @@ main(int argc, char *argv[])
sv = NULL;
while ((ch = getopt(argc, argv,
- "46DdhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
+ "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
switch (ch) {
case '4':
family = AF_INET;
@@ -156,6 +159,9 @@ main(int argc, char *argv[])
case 'd':
dflag = 1;
break;
+ case 'F':
+ Fflag = 1;
+ break;
case 'h':
help();
break;
@@ -463,7 +469,9 @@ main(int argc, char *argv[])
uflag ? "udp" : "tcp",
sv ? sv->s_name : "*");
}
- if (!zflag)
+ if (Fflag)
+ fdpass(s);
+ else if (!zflag)
readwrite(s);
}
}
@@ -787,6 +795,66 @@ readwrite(int nfd)
}
}
+/*
+ * fdpass()
+ * Pass the connected file descriptor to stdout and exit.
+ */
+void
+fdpass(int nfd)
+{
+ struct msghdr mh;
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof(int))];
+ } cmsgbuf;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ char c = '\0';
+ ssize_t r;
+ struct pollfd pfd;
+
+ /* Avoid obvious stupidity */
+ if (isatty(STDOUT_FILENO))
+ errx(1, "Cannot pass file descriptor to tty");
+
+ bzero(&mh, sizeof(mh));
+ bzero(&cmsgbuf, sizeof(cmsgbuf));
+ bzero(&iov, sizeof(iov));
+ bzero(&pfd, sizeof(pfd));
+
+ mh.msg_control = (caddr_t)&cmsgbuf.buf;
+ mh.msg_controllen = sizeof(cmsgbuf.buf);
+ cmsg = CMSG_FIRSTHDR(&mh);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *(int *)CMSG_DATA(cmsg) = nfd;
+
+ iov.iov_base = &c;
+ iov.iov_len = 1;
+ mh.msg_iov = &iov;
+ mh.msg_iovlen = 1;
+
+ bzero(&pfd, sizeof(pfd));
+ pfd.fd = STDOUT_FILENO;
+ for (;;) {
+ r = sendmsg(STDOUT_FILENO, &mh, 0);
+ if (r == -1) {
+ if (errno == EAGAIN || errno == EINTR) {
+ pfd.events = POLLOUT;
+ if (poll(&pfd, 1, -1) == -1)
+ err(1, "poll");
+ continue;
+ }
+ err(1, "sendmsg");
+ } else if (r == -1)
+ errx(1, "sendmsg: unexpected return value %zd", r);
+ else
+ break;
+ }
+ exit(0);
+}
+
/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */
void
atelnet(int nfd, unsigned char *buf, unsigned int size)