diff --git a/CHANGELOG b/CHANGELOG index 620ad0085..6bd67fc1d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ #Nmap Changelog ($Id$); -*-text-*- +o [Nsock][Ncat][GH#1075] Add AF_VSOCK (Linux VM sockets) functionality to Nsock + and Ncat. VM sockets are used for communication between virtual machines and + the hypervisor. [Stefan Hajnoczi] + o [NSE][GH#1467] Avoid clobbering the "severity" and "ignore_404" values of fingerprints in http-enum. None of the standard fingerprints uses these fields. [Kostas Milonas] diff --git a/ncat/config.h.in b/ncat/config.h.in index 76df805d3..fdb874c44 100644 --- a/ncat/config.h.in +++ b/ncat/config.h.in @@ -125,6 +125,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_VM_SOCKETS_H + /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF diff --git a/ncat/configure b/ncat/configure index b6181baa4..eeb20d796 100755 --- a/ncat/configure +++ b/ncat/configure @@ -3813,6 +3813,19 @@ fi done +for ac_header in linux/vm_sockets.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "#include +" +if test "x$ac_cv_header_linux_vm_sockets_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_VM_SOCKETS_H 1 +_ACEOF + +fi + +done + # Checks for typedefs, structures, and compiler characteristics. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5 diff --git a/ncat/configure.ac b/ncat/configure.ac index 8e2234cf0..10277857c 100644 --- a/ncat/configure.ac +++ b/ncat/configure.ac @@ -40,6 +40,7 @@ AC_PATH_TOOL([STRIP], [strip], [/bin/true]) AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([fcntl.h limits.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/param.h sys/socket.h sys/time.h sys/timeb.h unistd.h sys/un.h]) +AC_CHECK_HEADERS([linux/vm_sockets.h], , , [#include ]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STAT diff --git a/ncat/docs/ncat.1 b/ncat/docs/ncat.1 index 0a3d3c2de..076c1b438 100644 --- a/ncat/docs/ncat.1 +++ b/ncat/docs/ncat.1 @@ -2,12 +2,12 @@ .\" Title: Ncat .\" Author: [see the "Authors" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 09/28/2018 +.\" Date: 05/20/2019 .\" Manual: Ncat Reference Guide .\" Source: Ncat .\" Language: English .\" -.TH "NCAT" "1" "09/28/2018" "Ncat" "Ncat Reference Guide" +.TH "NCAT" "1" "05/20/2019" "Ncat" "Ncat Reference Guide" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -51,6 +51,7 @@ Options taking a time assume seconds\&. Append \*(Aqms\*(Aq for milliseconds, \-4 Use IPv4 only \-6 Use IPv6 only \-U, \-\-unixsock Use Unix domain sockets only + \-\-vsock Use vsock sockets only \-C, \-\-crlf Use CRLF for EOL sequence \-c, \-\-sh\-exec Executes the given command via /bin/sh \-e, \-\-exec Executes the given command @@ -85,8 +86,9 @@ Options taking a time assume seconds\&. Append \*(Aqms\*(Aq for milliseconds, \-\-broker Enable Ncat\*(Aqs connection brokering mode \-\-chat Start a simple Ncat chat server \-\-proxy Specify address of host to proxy through - \-\-proxy\-type Specify proxy type ("http" or "socks4" or "socks5") + \-\-proxy\-type Specify proxy type ("http", "socks4", "socks5") \-\-proxy\-auth Authenticate with HTTP or SOCKS proxy server + \-\-proxy\-dns Specify where to resolve proxy destination \-\-ssl Connect or listen with SSL \-\-ssl\-cert Specify SSL certificate file (PEM) for listening \-\-ssl\-key Specify SSL private key (PEM) for listening @@ -156,6 +158,16 @@ Use UDP for the connection (the default is TCP)\&. .RS 4 Use SCTP for the connection (the default is TCP)\&. SCTP support is implemented in TCP\-compatible mode\&. .RE +.PP +\fB\-\-vsock\fR (Use AF_VSOCK sockets) +.RS 4 +Use AF_VSOCK sockets rather than the default TCP sockets (Linux only)\&. This option may be used on its own for stream sockets or combined with +\fB\-\-udp\fR +for datagram sockets\&. A description of +\fB\-\-vsock\fR +mode is in +the section called \(lqAF_VSOCK SOCKETS\(rq\&. +.RE .SH "CONNECT MODE OPTIONS" .PP \fB\-g \fR\fB\fIhop1\fR\fR\fB[,\fIhop2\fR,\&.\&.\&.]\fR (Loose source routing) @@ -280,13 +292,13 @@ This option allows you to specify a comma\-separated list of protocols to send v .RE .SH "PROXY OPTIONS" .PP -\fB\-\-proxy \fR\fB\fIhost\fR\fR\fB[:\fR\fB\fIport\fR\fR\fB]\fR (Specify proxy address) +\fB\-\-proxy \fR\fB\fIhost\fR\fR\fB[:\fIport\fR]\fR (Specify proxy address) .RS 4 Requests proxying through \fIhost\fR:\fIport\fR, using the protocol specified by \fB\-\-proxy\-type\fR\&. .sp -If no port is specified, the proxy protocol\*(Aqs well\-known port is used (1080 for SOCKS and 3128 for HTTP)\&. However, when specifying an IPv6 HTTP proxy server using the IP address rather than the hostname, the port number MUST be specified as well\&. If the proxy requires authentication, use +If no port is specified, the proxy protocol\*(Aqs well\-known port is used (1080 for SOCKS and 3128 for HTTP)\&. When specifying an IPv6 HTTP proxy server using the IP address rather than the hostname, the square\-bracket notation (for example [2001:db8::1]:8080) MUST be used to separate the port from the IPv6 address\&. If the proxy requires authentication, use \fB\-\-proxy\-auth\fR\&. .RE .PP @@ -316,6 +328,30 @@ or \fB\-\-proxy\-type socks5\fR, the form should be username:password\&. For \fB\-\-proxy\-type socks4\fR, it should be a username only\&. .RE +.PP +\fB\-\-proxy\-dns \fR\fB\fItype\fR\fR (Specify where to resolve proxy destination) +.RS 4 +In connect mode, it provides control over whether proxy destination hostnames are resolved by the remote proxy server or locally, by Ncat itself\&. Possible values for +\fItype\fR +are: +.sp +local +\- Hostnames are resolved locally on the Ncat host\&. Ncat exits with error if the hostname cannot be resolved\&. +.sp +remote +\- Hostnames are passed directly onto the remote proxy server\&. This is the default behavior\&. +.sp +both +\- Hostname resolution is first attempted on the Ncat host\&. Unresolvable hostnames are passed onto the remote proxy server\&. +.sp +none +\- Hostname resolution is completely disabled\&. Only a literal IPv4 or IPv6 address can be used as the proxy destination\&. +.sp +Local hostname resolution generally respects IP version specified with options +\fB\-4\fR +or +\fB\-6\fR, except for SOCKS4, which is incompatible with IPv6\&. +.RE .SH "COMMAND EXECUTION OPTIONS" .PP \fB\-e \fR\fB\fIcommand\fR\fR, \fB\-\-exec \fR\fB\fIcommand\fR\fR (Execute command) @@ -477,6 +513,12 @@ If this option is passed, then Ncat will only send data and will ignore anything If this option is passed, Ncat will not invoke shutdown on a socket after seeing EOF on stdin\&. This is provided for backward\-compatibility with OpenBSD netcat, which exhibits this behavior when executed with its \*(Aq\-d\*(Aq option\&. .RE .PP +\fB\-n\fR, \fB\-\-nodns\fR (Do not resolve hostnames) +.RS 4 +Completely disable hostname resolution across all Ncat options, such as the destination, source address, source routing hops, and the proxy\&. All addresses must be specified numerically\&. (Note that resolution of proxy destinations is controlled separately via option +\fB\-\-proxy\-dns\fR\&.) +.RE +.PP \fB\-t\fR, \fB\-\-telnet\fR (Answer Telnet negotiations) .RS 4 Handle DO/DONT WILL/WONT Telnet negotiations\&. This makes it possible to script Telnet sessions with Ncat\&. @@ -508,6 +550,23 @@ on its own for stream sockets, or combine it with for datagram sockets\&. Datagram sockets require a source socket to connect from\&. By default, a source socket with a random filename will be created as needed, and deleted when the program ends\&. Use the \fB\-\-source\fR with a path to use a source socket with a specific name\&. +.SH "AF_VSOCK SOCKETS" +.PP +The +\fB\-\-vsock\fR +option causes Ncat to use AF_VSOCK sockets rather than network sockets\&. A CID must be given instead of a hostname or IP address\&. For example, to make a connection to the host, +.PP +\fBncat \-\-vsock 2 1234\fR +.PP +To listen on a socket: +.PP +\fBncat \-l \-\-vsock 1234\fR +.PP +Both stream and datagram domain sockets are supported, but socket type availability depends on the hypervisor\&. Use +\fB\-\-vsock\fR +on its own for stream sockets, or combine it with +\fB\-\-udp\fR +for datagram sockets\&. .SH "EXAMPLES" .PP Connect to example\&.org on TCP port 8080\&. @@ -646,13 +705,13 @@ Netcat (or any other implementation), Ncat is most definitely based on Netcat in .SH "LEGAL NOTICES" .SS "Ncat Copyright and Licensing" .PP -Ncat is (C) 2005\(en2012 Insecure\&.Com LLC\&. It is distributed as free and open source software under the same license terms as our Nmap software\&. Precise terms and further details are available +Ncat is (C) 2005\(en2018 Insecure\&.Com LLC\&. It is distributed as free and open source software under the same license terms as our Nmap software\&. Precise terms and further details are available from \m[blue]\fB\%https://nmap.org/man/man-legal.html\fR\m[]\&. .SS "Creative Commons License for this Ncat Guide" .PP This Ncat Reference Guide -is (C) 2005\(en2012 Insecure\&.Com LLC\&. It is hereby placed under version 3\&.0 of the +is (C) 2005\(en2018 Insecure\&.Com LLC\&. It is hereby placed under version 3\&.0 of the \m[blue]\fBCreative Commons Attribution License\fR\m[]\&\s-2\u[1]\d\s+2\&. This allows you redistribute and modify the work as you desire, as long as you credit the original source\&. Alternatively, you may choose to treat this document as falling under the same license as Ncap itself (discussed previously)\&. .SS "Source Code Availability and Community Contributions" .PP diff --git a/ncat/docs/ncat.usage.txt b/ncat/docs/ncat.usage.txt index 73f4b55e3..ea71324e1 100644 --- a/ncat/docs/ncat.usage.txt +++ b/ncat/docs/ncat.usage.txt @@ -6,6 +6,7 @@ Options taking a time assume seconds. Append 'ms' for milliseconds, -4 Use IPv4 only -6 Use IPv6 only -U, --unixsock Use Unix domain sockets only + --vsock Use vsock sockets only -C, --crlf Use CRLF for EOL sequence -c, --sh-exec Executes the given command via /bin/sh -e, --exec Executes the given command diff --git a/ncat/docs/ncat.xml b/ncat/docs/ncat.xml index a4713aaf1..23bb009bf 100644 --- a/ncat/docs/ncat.xml +++ b/ncat/docs/ncat.xml @@ -153,6 +153,19 @@ SCTP support is implemented in TCP-compatible mode. + + + + (Use AF_VSOCK sockets) + (Ncat option) + + + Use AF_VSOCK sockets rather than the default TCP sockets (Linux only). + This option may be used on its own for stream sockets or combined with for datagram sockets. + A description of mode is in + . + + @@ -916,6 +929,26 @@ + + AF_VSOCK Sockets + + + The option causes Ncat to use AF_VSOCK + sockets rather than network sockets. A CID must be given instead of a + hostname or IP address. For example, to make a connection to the host, + + ncat --vsock 2 1234 + + To listen on a socket: + + ncat -l --vsock 1234 + + Both stream and datagram domain sockets are supported, but socket type + availability depends on the hypervisor. Use + on its own for stream sockets, or + combine it with for datagram sockets. + + Examples diff --git a/ncat/ncat_connect.c b/ncat/ncat_connect.c index facd803de..b2dd4ab65 100644 --- a/ncat/ncat_connect.c +++ b/ncat/ncat_connect.c @@ -1163,6 +1163,21 @@ static void try_nsock_connect(nsock_pool nsp, struct sockaddr_list *conn_addr) NULL); } else +#endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + if (o.af == AF_VSOCK) { + if (o.proto == IPPROTO_UDP) { + nsock_connect_vsock_datagram(nsp, cs.sock_nsi, connect_handler, + (void *)conn_addr->next, &conn_addr->addr.sockaddr, + conn_addr->addrlen, conn_addr->addr.vm.svm_port); + } else { + nsock_connect_vsock_stream(nsp, cs.sock_nsi, connect_handler, + o.conntimeout, (void *)conn_addr->next, + &conn_addr->addr.sockaddr, conn_addr->addrlen, + conn_addr->addr.vm.svm_port); + } + } + else #endif if (o.proto == IPPROTO_UDP) { nsock_connect_udp(nsp, cs.sock_nsi, connect_handler, (void *)conn_addr->next, diff --git a/ncat/ncat_core.c b/ncat/ncat_core.c index 982fda0d5..cba15bce4 100644 --- a/ncat/ncat_core.c +++ b/ncat/ncat_core.c @@ -685,6 +685,17 @@ void setup_environment(struct fdinfo *info) setenv_portable("NCAT_REMOTE_ADDR", "localhost"); setenv_portable("NCAT_REMOTE_PORT", ""); } else +#endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + if (su.sockaddr.sa_family == AF_VSOCK) { + char char_u32[11]; + + snprintf(char_u32, sizeof(char_u32), "%u", su.vm.svm_cid); + setenv_portable("NCAT_REMOTE_ADDR", char_u32); + + snprintf(char_u32, sizeof(char_u32), "%u", su.vm.svm_port); + setenv_portable("NCAT_REMOTE_PORT", char_u32); + } else #endif if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { @@ -703,6 +714,17 @@ void setup_environment(struct fdinfo *info) setenv_portable("NCAT_LOCAL_ADDR", "localhost"); setenv_portable("NCAT_LOCAL_PORT", ""); } else +#endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + if (su.sockaddr.sa_family == AF_VSOCK) { + char char_u32[11]; + + snprintf(char_u32, sizeof(char_u32), "%u", su.vm.svm_cid); + setenv_portable("NCAT_LOCAL_ADDR", char_u32); + + snprintf(char_u32, sizeof(char_u32), "%u", su.vm.svm_port); + setenv_portable("NCAT_LOCAL_PORT", char_u32); + } else #endif if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { diff --git a/ncat/ncat_core.h b/ncat/ncat_core.h index b8ce93746..804ac9475 100644 --- a/ncat/ncat_core.h +++ b/ncat/ncat_core.h @@ -165,7 +165,7 @@ enum exec_mode { #define PROXYDNS_REMOTE 2 struct options { - unsigned short portno; + unsigned int portno; int verbose; int debug; diff --git a/ncat/ncat_listen.c b/ncat/ncat_listen.c index dbb25e5b8..07704eaf7 100644 --- a/ncat/ncat_listen.c +++ b/ncat/ncat_listen.c @@ -992,6 +992,14 @@ int ncat_listen() else return ncat_listen_stream(0); else +#endif +#if HAVE_LINUX_VM_SOCKETS_H + if (o.af == AF_VSOCK) { + if (o.proto == IPPROTO_UDP) + return ncat_listen_dgram(0); + else + return ncat_listen_stream(0); + } else #endif if (o.httpserver) return ncat_http_server(); diff --git a/ncat/ncat_main.c b/ncat/ncat_main.c index 0283a52f3..3666f50a5 100644 --- a/ncat/ncat_main.c +++ b/ncat/ncat_main.c @@ -287,7 +287,8 @@ int main(int argc, char *argv[]) struct host_list_node *deny_host_list = NULL; unsigned short proxyport; - int srcport = -1; + long max_port = 65535; + long srcport = -1; char *source = NULL; struct option long_options[] = { @@ -295,6 +296,9 @@ int main(int argc, char *argv[]) {"6", no_argument, NULL, '6'}, #if HAVE_SYS_UN_H {"unixsock", no_argument, NULL, 'U'}, +#endif +#if HAVE_LINUX_VM_SOCKETS_H + {"vsock", no_argument, NULL, 0}, #endif {"crlf", no_argument, NULL, 'C'}, {"g", required_argument, NULL, 'g'}, @@ -449,9 +453,10 @@ int main(int argc, char *argv[]) o.hexlog = optarg; break; case 'p': - srcport = atoi(optarg); - if (srcport < 0 || srcport > 0xffff) - bye("Invalid source port %d.", srcport); + errno = 0; + srcport = strtol(optarg, NULL, 10); + if (errno != 0 || srcport < 0) + bye("Invalid source port %ld.", srcport); break; case 'i': o.idletimeout = parse_timespec(optarg, "-i timeout"); @@ -616,6 +621,11 @@ int main(int argc, char *argv[]) lua_setup(); lua_run(); } +#endif +#if HAVE_LINUX_VM_SOCKETS_H + else if (strcmp(long_options[option_index].name, "vsock") == 0) { + o.af = AF_VSOCK; + } #endif break; case 'h': @@ -630,6 +640,9 @@ int main(int argc, char *argv[]) #if HAVE_SYS_UN_H " -U, --unixsock Use Unix domain sockets only\n" #endif +#if HAVE_LINUX_VM_SOCKETS_H +" --vsock Use vsock sockets only\n" +#endif " -C, --crlf Use CRLF for EOL sequence\n" " -c, --sh-exec Executes the given command via /bin/sh\n" " -e, --exec Executes the given command\n" @@ -693,6 +706,14 @@ int main(int argc, char *argv[]) } } +#if HAVE_LINUX_VM_SOCKETS_H + if (o.af == AF_VSOCK) + max_port = UINT32_MAX; +#endif + + if (srcport > max_port) + bye("Invalid source port %ld.", srcport); + #ifndef HAVE_OPENSSL if (o.ssl) bye("OpenSSL isn't compiled in. The --ssl option cannot be chosen."); @@ -729,6 +750,21 @@ int main(int argc, char *argv[]) } #endif /* HAVE_SYS_UN_H */ +#if HAVE_LINUX_VM_SOCKETS_H + if (o.af == AF_VSOCK) { + if (o.proxyaddr || o.proxytype) + bye("Proxy option not supported when using vsock sockets."); +#ifdef HAVE_OPENSSL + if (o.ssl) + bye("SSL option not supported when using vsock sockets."); +#endif + if (o.broker) + bye("Connection brokering not supported when using vsock sockets."); + if (o.numsrcrtes > 0) + bye("Loose source routing not allowed when using vsock sockets."); + } +#endif /* HAVE_LINUX_VM_SOCKETS_H */ + /* Create a static target address, because at least one target address must be always allocated */ targetaddrs = (struct sockaddr_list *)safe_zalloc(sizeof(struct sockaddr_list)); @@ -818,6 +854,21 @@ int main(int argc, char *argv[]) if (o.verbose) loguser("Specifying source socket for other than DATAGRAM Unix domain sockets have no effect.\n"); } else +#endif +#if HAVE_LINUX_VM_SOCKETS_H + if (o.af == AF_VSOCK) { + long long_cid; + + srcaddr.vm.svm_family = AF_VSOCK; + + errno = 0; + long_cid = strtol(source, NULL, 10); + if (errno != 0 || long_cid <= 0 || long_cid > UINT32_MAX) + bye("Invalid source address CID \"%s\".", source); + srcaddr.vm.svm_cid = long_cid; + + srcaddrlen = sizeof(srcaddr.vm); + } else #endif rc = resolve(source, 0, &srcaddr.storage, &srcaddrlen, o.af); if (rc != 0) @@ -851,6 +902,26 @@ int main(int argc, char *argv[]) o.target = argv[optind]; optind++; } else +#endif +#if HAVE_LINUX_VM_SOCKETS_H + if (o.af == AF_VSOCK) { + if (!o.listen || optind + 1 < argc) { + long long_cid; + + memset(&targetaddrs->addr.storage, 0, sizeof(struct sockaddr_vm)); + targetaddrs->addr.vm.svm_family = AF_VSOCK; + + errno = 0; + long_cid = strtol(argv[optind], NULL, 10); + if (errno != 0 || long_cid <= 0 || long_cid > UINT32_MAX) + bye("Invalid CID \"%s\".", argv[optind]); + targetaddrs->addr.vm.svm_cid = long_cid; + + targetaddrs->addrlen = sizeof(targetaddrs->addr.vm); + o.target = argv[optind]; + optind++; + } + } else #endif /* Resolve hostname if we're given one */ if (strspn(argv[optind], "0123456789") != strlen(argv[optind])) { @@ -881,7 +952,7 @@ int main(int argc, char *argv[]) if (optind + 1 < argc || (o.listen && srcport != -1 && optind + 1 == argc)) { loguser("Got more than one port specification:"); if (o.listen && srcport != -1) - loguser_noprefix(" %d", srcport); + loguser_noprefix(" %ld", srcport); for (; optind < argc; optind++) loguser_noprefix(" %s", argv[optind]); loguser_noprefix(". QUITTING.\n"); @@ -891,10 +962,10 @@ int main(int argc, char *argv[]) errno = 0; long_port = strtol(argv[optind], NULL, 10); - if (errno != 0 || long_port < 0 || long_port > 65535) + if (errno != 0 || long_port < 0 || long_port > max_port) bye("Invalid port number \"%s\".", argv[optind]); - o.portno = (unsigned short) long_port; + o.portno = (unsigned int) long_port; } if (o.proxytype && !o.listen) @@ -913,6 +984,10 @@ int main(int argc, char *argv[]) /* If we use Unix domain sockets, we have to count with them. */ else if (targetaddrs_item->addr.storage.ss_family == AF_UNIX) ; /* Do nothing. */ +#endif +#if HAVE_LINUX_VM_SOCKETS_H + else if (targetaddrs_item->addr.storage.ss_family == AF_VSOCK) + targetaddrs_item->addr.vm.svm_port = o.portno; #endif else if (targetaddrs_item->addr.storage.ss_family == AF_UNSPEC) ; /* Leave unspecified. */ @@ -941,8 +1016,12 @@ int main(int argc, char *argv[]) if (srcaddr.storage.ss_family == AF_INET) srcaddr.in.sin_port = htons(srcport); #ifdef HAVE_IPV6 - else + else if (srcaddr.storage.ss_family == AF_INET6) srcaddr.in6.sin6_port = htons(srcport); +#endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + else if (srcaddr.storage.ss_family == AF_VSOCK) + srcaddr.vm.svm_port = srcport; #endif } } @@ -1052,6 +1131,14 @@ static int ncat_listen_mode(void) bye("Failed to resolve default IPv4 address: %s.", gai_strerror(rc)); num_listenaddrs++; } +#ifdef HAVE_LINUX_VM_SOCKETS_H + if (o.af == AF_VSOCK) { + listenaddrs[num_listenaddrs].vm.svm_family = AF_VSOCK; + listenaddrs[num_listenaddrs].vm.svm_cid = VMADDR_CID_ANY; + listenaddrs[num_listenaddrs].vm.svm_port = o.portno; + num_listenaddrs++; + } +#endif } if (o.proxytype) { diff --git a/ncat/sockaddr_u.h b/ncat/sockaddr_u.h index 3b0357b95..b8f8209e6 100644 --- a/ncat/sockaddr_u.h +++ b/ncat/sockaddr_u.h @@ -133,10 +133,17 @@ #ifndef SOCKADDR_U_H_ #define SOCKADDR_U_H_ +#if HAVE_LINUX_VM_SOCKETS_H +#include +#endif + union sockaddr_u { struct sockaddr_storage storage; #ifdef HAVE_SYS_UN_H struct sockaddr_un un; +#endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + struct sockaddr_vm vm; #endif struct sockaddr_in in; struct sockaddr_in6 in6; diff --git a/ncat/util.c b/ncat/util.c index b41ad8db5..0cdacee6d 100644 --- a/ncat/util.c +++ b/ncat/util.c @@ -151,6 +151,10 @@ #include #endif +#if HAVE_LINUX_VM_SOCKETS_H +#include +#endif + /* safely add 2 size_t */ size_t sadd(size_t l, size_t r) { @@ -464,6 +468,11 @@ int do_listen(int type, int proto, const union sockaddr_u *srcaddr_u) sa_len = SUN_LEN(&srcaddr_u->un); break; #endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + case AF_VSOCK: + sa_len = sizeof (struct sockaddr_vm); + break; +#endif #ifdef HAVE_SOCKADDR_SA_LEN default: sa_len = srcaddr_u->sockaddr.sa_len; @@ -489,6 +498,14 @@ int do_listen(int type, int proto, const union sockaddr_u *srcaddr_u) bye("bind to %s: %s.", srcaddr_u->un.sun_path, socket_strerror(socket_errno())); else +#endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + if (srcaddr_u->storage.ss_family == AF_VSOCK) + bye("bind to %u:%u: %s.", + srcaddr_u->vm.svm_cid, + srcaddr_u->vm.svm_port, + socket_strerror(socket_errno())); + else #endif bye("bind to %s:%hu: %s.", inet_socktop(srcaddr_u), inet_port(srcaddr_u), socket_strerror(socket_errno())); @@ -502,6 +519,13 @@ int do_listen(int type, int proto, const union sockaddr_u *srcaddr_u) if (srcaddr_u->storage.ss_family == AF_UNIX) loguser("Listening on %s\n", srcaddr_u->un.sun_path); else +#endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + if (srcaddr_u->storage.ss_family == AF_VSOCK) + loguser("Listening on %u:%u\n", + srcaddr_u->vm.svm_cid, + srcaddr_u->vm.svm_port); + else #endif loguser("Listening on %s:%hu\n", inet_socktop(srcaddr_u), inet_port(srcaddr_u)); } diff --git a/nsock/include/nsock.h b/nsock/include/nsock.h index 710bbc537..82ab5fd71 100644 --- a/nsock/include/nsock.h +++ b/nsock/include/nsock.h @@ -88,6 +88,10 @@ #endif #endif /* HAVE_SYS_UN_H */ +#if HAVE_LINUX_VM_SOCKETS_H +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -530,6 +534,37 @@ nsock_event_id nsock_connect_unixsock_datagram(nsock_pool nsp, nsock_iod nsiod, void *userdata, struct sockaddr *ss, size_t sslen); #endif /* HAVE_SYS_UN_H */ +#if HAVE_LINUX_VM_SOCKETS_H +/* Request a vsock stream connection to another system. ss should be a + * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would + * pass to connect). sslen should be the sizeof the structure you are passing + * in. */ +nsock_event_id nsock_connect_vsock_stream(nsock_pool nsp, nsock_iod ms_iod, + nsock_ev_handler handler, + int timeout_msecs, void *userdata, + struct sockaddr *saddr, size_t sslen, + unsigned int port); + +/* Request a vsock datagram "connection" to another system. Since this is a + * datagram socket, no packets are actually sent. The destination CID and port + * are just associated with the nsiod (an actual OS connect() call is made). + * You can then use the normal nsock write calls on the socket. There is no + * timeout since this call always calls your callback at the next opportunity. + * The advantages to having a connected datagram socket (as opposed to just + * specifying an address with sendto() are that we can now use a consistent set + * of write/read calls for stream and datagram sockets, received packets from + * the non-partner are automatically dropped by the OS, and the OS can provide + * asynchronous errors (see Unix Network Programming pp224). ss should be a + * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would + * pass to connect). sslen should be the sizeof the structure you are passing + * in. */ +nsock_event_id nsock_connect_vsock_datagram(nsock_pool nsp, nsock_iod nsiod, + nsock_ev_handler handler, + void *userdata, + struct sockaddr *saddr, + size_t sslen, unsigned int port); +#endif /* HAVE_LINUX_VM_SOCKETS_H */ + /* Request a TCP connection to another system (by IP address). The in_addr is * normal network byte order, but the port number should be given in HOST BYTE * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as diff --git a/nsock/include/nsock_config.h.in b/nsock/include/nsock_config.h.in index 33883488d..64754ae28 100644 --- a/nsock/include/nsock_config.h.in +++ b/nsock/include/nsock_config.h.in @@ -78,6 +78,8 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H +#undef HAVE_LINUX_VM_SOCKETS_H + #undef HAVE_NETDB_H #undef HAVE_OPENSSL diff --git a/nsock/src/configure b/nsock/src/configure index 9be2e6a5e..2bf719424 100755 --- a/nsock/src/configure +++ b/nsock/src/configure @@ -4694,6 +4694,19 @@ fi done +for ac_header in linux/vm_sockets.h +do : + ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "#include +" +if test "x$ac_cv_header_linux_vm_sockets_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_VM_SOCKETS_H 1 +_ACEOF + +fi + +done + # We test whether they specified openssl desires explicitly use_openssl="yes" diff --git a/nsock/src/configure.ac b/nsock/src/configure.ac index 09dfb0849..1f035cff7 100644 --- a/nsock/src/configure.ac +++ b/nsock/src/configure.ac @@ -206,6 +206,7 @@ AC_CHECK_FUNC(nanosleep, , AC_CHECK_LIB(posix4, nanosleep)) dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(net/bpf.h sys/ioctl.h sys/un.h netdb.h) +AC_CHECK_HEADERS([linux/vm_sockets.h], , , [#include ]) # We test whether they specified openssl desires explicitly use_openssl="yes" diff --git a/nsock/src/nsock_connect.c b/nsock/src/nsock_connect.c index d3e69fa8b..ab425a890 100644 --- a/nsock/src/nsock_connect.c +++ b/nsock/src/nsock_connect.c @@ -187,7 +187,7 @@ int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) { /* This does the actual logistics of requesting a connection. It is shared * by nsock_connect_tcp and nsock_connect_ssl, among others */ void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, - unsigned short port) { + unsigned int port) { struct sockaddr_in *sin; #if HAVE_IPV6 @@ -243,6 +243,13 @@ void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int #if HAVE_SYS_UN_H else if (ss->ss_family == AF_UNIX) { } +#endif +#if HAVE_LINUX_VM_SOCKETS_H + else if (ss->ss_family == AF_VSOCK) { + struct sockaddr_vm *svm = (struct sockaddr_vm *)ss; + + svm->svm_port = port; + } #endif else { fatal("Unknown address family %d\n", ss->ss_family); @@ -321,6 +328,76 @@ nsock_event_id nsock_connect_unixsock_datagram(nsock_pool nsp, nsock_iod nsiod, #endif /* HAVE_SYS_UN_H */ +#if HAVE_LINUX_VM_SOCKETS_H +/* Request a vsock stream connection to another system. ss should be a + * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would + * pass to connect). sslen should be the sizeof the structure you are passing + * in. */ +nsock_event_id nsock_connect_vsock_stream(nsock_pool nsp, nsock_iod ms_iod, + nsock_ev_handler handler, + int timeout_msecs, void *userdata, + struct sockaddr *saddr, size_t sslen, + unsigned int port) { + struct niod *nsi = (struct niod *)ms_iod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + struct sockaddr_vm *svm = (struct sockaddr_vm *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, timeout_msecs, handler, userdata); + assert(nse); + + nsock_log_info("vsock stream connection requested to %u:%u (IOD #%li) EID %li", + svm->svm_cid, port, nsi->id, nse->id); + + /* Do the actual connect() */ + nsock_connect_internal(ms, nse, SOCK_STREAM, 0, ss, sslen, port); + nsock_pool_add_event(ms, nse); + + return nse->id; +} + +/* Request a vsock datagram "connection" to another system. Since this is a + * datagram socket, no packets are actually sent. The destination CID and port + * are just associated with the nsiod (an actual OS connect() call is made). + * You can then use the normal nsock write calls on the socket. There is no + * timeout since this call always calls your callback at the next opportunity. + * The advantages to having a connected datagram socket (as opposed to just + * specifying an address with sendto() are that we can now use a consistent set + * of write/read calls for stream and datagram sockets, received packets from + * the non-partner are automatically dropped by the OS, and the OS can provide + * asynchronous errors (see Unix Network Programming pp224). ss should be a + * sockaddr_storage or sockaddr_vm, as appropriate (just like what you would + * pass to connect). sslen should be the sizeof the structure you are passing + * in. */ +nsock_event_id nsock_connect_vsock_datagram(nsock_pool nsp, nsock_iod nsiod, + nsock_ev_handler handler, + void *userdata, + struct sockaddr *saddr, + size_t sslen, unsigned int port) { + struct niod *nsi = (struct niod *)nsiod; + struct npool *ms = (struct npool *)nsp; + struct nevent *nse; + struct sockaddr_storage *ss = (struct sockaddr_storage *)saddr; + struct sockaddr_vm *svm = (struct sockaddr_vm *)saddr; + + assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); + + nse = event_new(ms, NSE_TYPE_CONNECT, nsi, -1, handler, userdata); + assert(nse); + + nsock_log_info("vsock dgram connection requested to %u:%u (IOD #%li) EID %li", + svm->svm_cid, port, nsi->id, nse->id); + + nsock_connect_internal(ms, nse, SOCK_DGRAM, 0, ss, sslen, port); + nsock_pool_add_event(ms, nse); + + return nse->id; +} +#endif /* HAVE_LINUX_VM_SOCKETS_H */ + /* Request a TCP connection to another system (by IP address). The in_addr is * normal network byte order, but the port number should be given in HOST BYTE * ORDER. ss should be a sockaddr_storage, sockaddr_in6, or sockaddr_in as diff --git a/nsock/src/nsock_internal.h b/nsock/src/nsock_internal.h index 28a66ad89..3c06e7ba7 100644 --- a/nsock/src/nsock_internal.h +++ b/nsock/src/nsock_internal.h @@ -473,7 +473,7 @@ void event_delete(struct npool *nsp, struct nevent *nse); * etc. */ void nsock_pool_add_event(struct npool *nsp, struct nevent *nse); -void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, unsigned short port); +void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, unsigned int port); /* Comments on using the following handle_*_result functions are available in nsock_core.c */