mirror of
https://github.com/nmap/nmap.git
synced 2026-01-05 06:09:00 +00:00
Enable multiple UDP connections in listen mode. Fixes #1223
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
#Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [Ncat] Ncat in listen mode with --udp --ssl will use DTLS to secure incoming
|
||||
connections. [Daniel Miller]
|
||||
|
||||
o [Ncat][GH#1223] Ncat can now accept "connections" from multiple UDP hosts in
|
||||
listen mode with the --keep-open option. This also enables --broker and
|
||||
--chat via UDP. [Daniel Miller]
|
||||
|
||||
o [GH#2507] Updates to the Japanese manpage translation by Taichi Kotake.
|
||||
|
||||
o [NSE][GH#548] New script tftp-version requests a nonexistent file from a TFTP
|
||||
|
||||
@@ -327,8 +327,8 @@
|
||||
particularly handy for talking to SSL enabled HTTP servers, etc.</para>
|
||||
<para>In server mode, this option listens for incoming SSL connections,
|
||||
rather than plain untunneled traffic.</para>
|
||||
<para>In UDP connect mode, this option enables Datagram TLS (DTLS).
|
||||
This is not supported in server mode.</para>
|
||||
<para>In UDP mode, this option enables Datagram TLS (DTLS).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@@ -131,9 +131,7 @@ the tool? Many of these examples suppose a Unix environment. -->
|
||||
to the connection limit. With <option>--keep-open</option> (or
|
||||
<option>-k</option> for short), the server receives everything sent by
|
||||
any of its clients, and anything the server sends is sent to all of
|
||||
them. A UDP server will communicate with only one client (the first
|
||||
one to send it data), because in UDP there is no list of
|
||||
<quote>connected</quote> clients.
|
||||
them.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -304,12 +302,9 @@ Content-Type: text/html; charset=UTF-8
|
||||
the User Datagram Protocol, is an unreliable protocol often used by
|
||||
applications that can't afford the overhead of TCP. Use the
|
||||
<option>--udp</option><indexterm><primary><option>--udp</option> (Ncat option)</primary></indexterm>
|
||||
option to make Ncat use UDP. In listen mode, Ncat will communicate
|
||||
with only one client, and the
|
||||
<option>--keep-open</option><indexterm><primary><option>--keep-open</option> (Ncat option)</primary><secondary>not supported with UDP</secondary></indexterm>
|
||||
option doesn't work, the reason for this being that UDP has no notion
|
||||
of a connection. UDP may be secured by a form of SSL called Datagram TLS (DTLS)<indexterm><primary>DTLS</primary><secondary>Datagram TLS</secondary></indexterm>.
|
||||
This is currently only supported in connect (client) mode.<indexterm><primary>SSL</primary><secondary>not supported with UDP in server mode</secondary></indexterm>
|
||||
option to make Ncat use UDP.
|
||||
UDP may be secured using the <option>--ssl</option> option, which enables
|
||||
Datagram TLS (DTLS)<indexterm><primary>DTLS</primary><secondary>Datagram TLS</secondary></indexterm>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -646,8 +641,8 @@ print("Hello, world!")
|
||||
combined with
|
||||
<option>--keep-open</option>,<indexterm><primary><option>--keep-open (Ncat option)</option></primary><secondary>with <option>--exec</option></secondary></indexterm>
|
||||
Ncat will accept multiple connections, forking off a new handler for
|
||||
each. This works even in UDP mode; the usual limit of only one client
|
||||
doesn't apply. The server will keep running until you press
|
||||
each.
|
||||
The server will keep running until you press
|
||||
<keycombo><keycap>ctrl</keycap><keycap>C</keycap></keycombo> or
|
||||
otherwise terminate it externally. In this way Ncat can work much like
|
||||
inetd.<indexterm><primary>inetd</primary></indexterm>
|
||||
@@ -1779,20 +1774,17 @@ host1$ <userinput>ncat --send-only host2 < log.txt</userinput>
|
||||
<term>UDP discard server</term>
|
||||
<listitem>
|
||||
<literallayout>
|
||||
<command>ncat -l 9 --keep-open --udp --sh-exec "cat > /dev/null"</command>
|
||||
<command>ncat --udp -l --keep-open 9 --recv-only > /dev/null</command>
|
||||
</literallayout>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
With the TCP server we used <option>--keep-open</option> so the server
|
||||
could handle multiple simultaneous connections, not just one. For the
|
||||
UDP server we had to use <option>--sh-exec</option> to allow multiple
|
||||
concurrent connections. Recall from <xref linkend="ncat-usage"/> that
|
||||
a UDP server can handle only one client but with
|
||||
<option>--exec</option> and <option>--sh-exec</option> this limitation
|
||||
does not apply.
|
||||
Ncat in UDP mode uses all the same options as TCP. The caveat here is that
|
||||
connections can't be closed, only timed out, so you will eventually run out
|
||||
of sockets if you do not use a timeout. Currently, none of the timeout
|
||||
options do the appropriate thing in this instance. </para>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -117,7 +117,7 @@ static int listen_socket[NUM_LISTEN_ADDRS];
|
||||
static int stdin_eof = 0;
|
||||
static int crlf_state = 0;
|
||||
|
||||
static void handle_connection(int socket_accept);
|
||||
static void handle_connection(int socket_accept, int type, fd_set *listen_fds);
|
||||
static int read_stdin(void);
|
||||
static int read_socket(int recv_fd);
|
||||
static void post_handle_connection(struct fdinfo sinfo);
|
||||
@@ -165,14 +165,51 @@ static void sigchld_handler(int signum)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ncat_listen_stream(int proto)
|
||||
int new_listen_socket(int type, int proto, const union sockaddr_u *addr, fd_set *listen_fds)
|
||||
{
|
||||
struct fdinfo fdi;
|
||||
fdi.fd = do_listen(type, proto, addr);
|
||||
if (fdi.fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
fdi.remoteaddr = *addr; /* actually our local addr, but whatevs */
|
||||
|
||||
/* Make our listening socket non-blocking because there are timing issues
|
||||
* which could cause us to block on accept() even though select() says it's
|
||||
* readable. See UNPv1 2nd ed, p422 for more.
|
||||
*/
|
||||
unblock_socket(fdi.fd);
|
||||
|
||||
/* setup select sets and max fd */
|
||||
checked_fd_set(fdi.fd, &master_readfds);
|
||||
add_fdinfo(&client_fdlist, &fdi);
|
||||
|
||||
checked_fd_set(fdi.fd, listen_fds);
|
||||
|
||||
return fdi.fd;
|
||||
}
|
||||
|
||||
int ncat_listen()
|
||||
{
|
||||
int rc, i, fds_ready;
|
||||
fd_set listen_fds;
|
||||
struct timeval tv;
|
||||
struct timeval *tvp = NULL;
|
||||
unsigned int num_sockets;
|
||||
int proto = o.proto;
|
||||
int type = o.proto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
|
||||
|
||||
if (o.httpserver)
|
||||
return ncat_http_server();
|
||||
|
||||
#if HAVE_SYS_UN_H
|
||||
if (o.af == AF_UNIX)
|
||||
proto = 0;
|
||||
#endif
|
||||
#if HAVE_LINUX_VM_SOCKETS_H
|
||||
if (o.af == AF_VSOCK)
|
||||
proto = 0;
|
||||
#endif
|
||||
/* clear out structs */
|
||||
FD_ZERO(&master_readfds);
|
||||
FD_ZERO(&master_writefds);
|
||||
@@ -199,7 +236,7 @@ static int ncat_listen_stream(int proto)
|
||||
{
|
||||
if (o.sslalpn)
|
||||
bye("ALPN is not supported in listen mode\n");
|
||||
setup_ssl_listen();
|
||||
setup_ssl_listen(type == SOCK_STREAM ? SSLv23_server_method() : DTLS_server_method());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -230,25 +267,12 @@ static int ncat_listen_stream(int proto)
|
||||
num_sockets = 0;
|
||||
for (i = 0; i < num_listenaddrs; i++) {
|
||||
/* setup the main listening socket */
|
||||
listen_socket[num_sockets] = do_listen(SOCK_STREAM, proto, &listenaddrs[i]);
|
||||
listen_socket[num_sockets] = new_listen_socket(type, proto, &listenaddrs[i], &listen_fds);
|
||||
if (listen_socket[num_sockets] == -1) {
|
||||
if (o.debug > 0)
|
||||
logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make our listening socket non-blocking because there are timing issues
|
||||
* which could cause us to block on accept() even though select() says it's
|
||||
* readable. See UNPv1 2nd ed, p422 for more.
|
||||
*/
|
||||
unblock_socket(listen_socket[num_sockets]);
|
||||
|
||||
/* setup select sets and max fd */
|
||||
checked_fd_set(listen_socket[num_sockets], &master_readfds);
|
||||
add_fd(&client_fdlist, listen_socket[num_sockets]);
|
||||
|
||||
checked_fd_set(listen_socket[num_sockets], &listen_fds);
|
||||
|
||||
num_sockets++;
|
||||
}
|
||||
if (num_sockets == 0) {
|
||||
@@ -341,7 +365,7 @@ static int ncat_listen_stream(int proto)
|
||||
#endif
|
||||
if (checked_fd_isset(cfd, &listen_fds)) {
|
||||
/* we have a new connection request */
|
||||
handle_connection(cfd);
|
||||
handle_connection(cfd, type, &listen_fds);
|
||||
} else if (cfd == STDIN_FILENO) {
|
||||
if (o.broker) {
|
||||
read_and_broadcast(cfd);
|
||||
@@ -354,7 +378,7 @@ static int ncat_listen_stream(int proto)
|
||||
receiving anything, we can quit here. */
|
||||
return 0;
|
||||
}
|
||||
if (!o.noshutdown) shutdown_sockets(SHUT_WR);
|
||||
if (!o.noshutdown && type == SOCK_STREAM) shutdown_sockets(SHUT_WR);
|
||||
}
|
||||
if (rc < 0)
|
||||
return 1;
|
||||
@@ -380,7 +404,7 @@ static int ncat_listen_stream(int proto)
|
||||
/* Accept a connection on a listening socket. Allow or deny the connection.
|
||||
Fork a command if o.cmdexec is set. Otherwise, add the new socket to the
|
||||
watch set. */
|
||||
static void handle_connection(int socket_accept)
|
||||
static void handle_connection(int socket_accept, int type, fd_set *listen_fds)
|
||||
{
|
||||
union sockaddr_u remoteaddr;
|
||||
socklen_t ss_len;
|
||||
@@ -393,7 +417,39 @@ static void handle_connection(int socket_accept)
|
||||
ss_len = sizeof(remoteaddr.storage);
|
||||
|
||||
errno = 0;
|
||||
s.fd = accept(socket_accept, &remoteaddr.sockaddr, &ss_len);
|
||||
if (type == SOCK_STREAM) {
|
||||
s.fd = accept(socket_accept, &remoteaddr.sockaddr, &ss_len);
|
||||
}
|
||||
else {
|
||||
char buf[4] = {0};
|
||||
int nbytes = recvfrom(socket_accept, buf, sizeof(buf), MSG_PEEK,
|
||||
&remoteaddr.sockaddr, &ss_len);
|
||||
if (nbytes < 0) {
|
||||
loguser("%s.\n", socket_strerror(socket_errno()));
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* We're using connected udp. This has the down side of only
|
||||
* being able to handle one udp client at a time
|
||||
*/
|
||||
Connect(socket_accept, &remoteaddr.sockaddr, ss_len);
|
||||
s.fd = socket_accept;
|
||||
// Remove this socket from listening and put a new one up.
|
||||
for (int i = 0; i < num_listenaddrs; i++) {
|
||||
if (listen_socket[i] == socket_accept) {
|
||||
struct fdinfo *lfdi = get_fdinfo(&client_fdlist, socket_accept);
|
||||
union sockaddr_u localaddr = lfdi->remoteaddr;
|
||||
checked_fd_clr(socket_accept, &master_readfds);
|
||||
checked_fd_clr(socket_accept, listen_fds);
|
||||
rm_fd(&client_fdlist, socket_accept);
|
||||
listen_socket[i] = new_listen_socket(type, (o.af == AF_INET || o.af == AF_INET6) ? o.proto : 0, &localaddr, listen_fds);
|
||||
if (listen_socket[i] < 0) {
|
||||
bye("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s.fd < 0) {
|
||||
if (o.debug)
|
||||
@@ -406,12 +462,12 @@ static void handle_connection(int socket_accept)
|
||||
if (o.verbose) {
|
||||
#if HAVE_SYS_UN_H
|
||||
if (remoteaddr.sockaddr.sa_family == AF_UNIX)
|
||||
loguser("Connection from a client on Unix domain socket.\n");
|
||||
loguser("Connection from %s.\n", remoteaddr.un.sun_path);
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_VM_SOCKETS_H
|
||||
if (remoteaddr.sockaddr.sa_family == AF_VSOCK)
|
||||
loguser("Connection from a client on vsock socket.\n");
|
||||
loguser("Connection from %u.\n", remoteaddr.vm.svm_cid);
|
||||
else
|
||||
#endif
|
||||
if (o.chat)
|
||||
@@ -616,350 +672,6 @@ int read_socket(int recv_fd)
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
/* This is sufficiently different from the TCP code (wrt SSL, etc) that it
|
||||
* resides in its own simpler function
|
||||
*/
|
||||
static int ncat_listen_dgram(int proto)
|
||||
{
|
||||
struct {
|
||||
int fd;
|
||||
union sockaddr_u addr;
|
||||
} sockfd[NUM_LISTEN_ADDRS];
|
||||
int i, fdn = -1;
|
||||
int fdmax, nbytes, n, fds_ready;
|
||||
char buf[DEFAULT_UDP_BUF_LEN] = { 0 };
|
||||
char *tempbuf = NULL;
|
||||
fd_set read_fds;
|
||||
union sockaddr_u remotess;
|
||||
socklen_t sslen = sizeof(remotess.storage);
|
||||
struct timeval tv;
|
||||
struct timeval *tvp = NULL;
|
||||
unsigned int num_sockets;
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if(o.ssl)
|
||||
bye("DTLS is not supported in listen mode\n");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NUM_LISTEN_ADDRS; i++) {
|
||||
sockfd[i].fd = -1;
|
||||
sockfd[i].addr.storage.ss_family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
FD_ZERO(&read_fds);
|
||||
|
||||
/* Initialize remotess struct so recvfrom() doesn't hit the fan.. */
|
||||
zmem(&remotess.storage, sizeof(remotess.storage));
|
||||
remotess.storage.ss_family = o.af;
|
||||
|
||||
#ifdef WIN32
|
||||
set_pseudo_sigchld_handler(decrease_conn_count);
|
||||
#else
|
||||
/* Reap on SIGCHLD */
|
||||
Signal(SIGCHLD, sigchld_handler);
|
||||
/* Ignore the SIGPIPE that occurs when a client disconnects suddenly and we
|
||||
send data to it before noticing. */
|
||||
Signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
/* Not sure if this problem exists on Windows, but fcntl and /dev/null don't */
|
||||
#ifndef WIN32
|
||||
/* Check whether stdin is closed. Because we treat this fd specially, we
|
||||
* can't risk it being reopened for an incoming connection, so we'll hold
|
||||
* it open instead. */
|
||||
if (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF) {
|
||||
logdebug("stdin is closed, attempting to reserve STDIN_FILENO\n");
|
||||
i = open("/dev/null", O_RDONLY);
|
||||
if (i >= 0 && i != STDIN_FILENO) {
|
||||
/* Oh well, we tried */
|
||||
logdebug("Couldn't reserve STDIN_FILENO\n");
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* set for selecting udp listening sockets */
|
||||
fd_set listen_fds;
|
||||
fd_list_t listen_fdlist;
|
||||
FD_ZERO(&listen_fds);
|
||||
init_fdlist(&listen_fdlist, num_listenaddrs);
|
||||
|
||||
num_sockets = 0;
|
||||
for (i = 0; i < num_listenaddrs; i++) {
|
||||
/* create the UDP listen sockets */
|
||||
sockfd[num_sockets].fd = do_listen(SOCK_DGRAM, proto, &listenaddrs[i]);
|
||||
if (sockfd[num_sockets].fd == -1) {
|
||||
if (o.debug > 0)
|
||||
logdebug("do_listen(\"%s\"): %s\n", inet_ntop_ez(&listenaddrs[i].storage, sizeof(listenaddrs[i].storage)), socket_strerror(socket_errno()));
|
||||
continue;
|
||||
}
|
||||
checked_fd_set(sockfd[num_sockets].fd, &listen_fds);
|
||||
add_fd(&listen_fdlist, sockfd[num_sockets].fd);
|
||||
sockfd[num_sockets].addr = listenaddrs[i];
|
||||
num_sockets++;
|
||||
}
|
||||
if (num_sockets == 0) {
|
||||
if (num_listenaddrs == 1)
|
||||
bye("Unable to open listening socket on %s: %s", inet_ntop_ez(&listenaddrs[0].storage, sizeof(listenaddrs[0].storage)), socket_strerror(socket_errno()));
|
||||
else
|
||||
bye("Unable to open any listening sockets.");
|
||||
}
|
||||
|
||||
if (o.idletimeout > 0)
|
||||
tvp = &tv;
|
||||
|
||||
while (1) {
|
||||
int i, j, conn_count, socket_n;
|
||||
|
||||
if (fdn != -1) {
|
||||
/*remove socket descriptor which is burnt */
|
||||
checked_fd_clr(sockfd[fdn].fd, &listen_fds);
|
||||
rm_fd(&listen_fdlist, sockfd[fdn].fd);
|
||||
|
||||
/* Rebuild the udp socket which got burnt */
|
||||
sockfd[fdn].fd = do_listen(SOCK_DGRAM, proto, &sockfd[fdn].addr);
|
||||
if (sockfd[fdn].fd == -1)
|
||||
bye("do_listen: %s", socket_strerror(socket_errno()));
|
||||
checked_fd_set(sockfd[fdn].fd, &listen_fds);
|
||||
add_fd(&listen_fdlist, sockfd[fdn].fd);
|
||||
|
||||
}
|
||||
fdn = -1;
|
||||
socket_n = -1;
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
while (1) {
|
||||
/*
|
||||
* We just select to get a list of sockets which we can talk to
|
||||
*/
|
||||
if (o.debug > 1)
|
||||
logdebug("selecting, fdmax %d\n", listen_fdlist.fdmax);
|
||||
fds = listen_fds;
|
||||
|
||||
if (o.idletimeout > 0)
|
||||
ms_to_timeval(tvp, o.idletimeout);
|
||||
|
||||
/* The idle timer should only be running when there are active connections */
|
||||
if (get_conn_count())
|
||||
fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, tvp);
|
||||
else
|
||||
fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, NULL);
|
||||
|
||||
if (o.debug > 1)
|
||||
logdebug("select returned %d fds ready\n", fds_ready);
|
||||
|
||||
if (fds_ready == 0)
|
||||
bye("Idle timeout expired (%d ms).", o.idletimeout);
|
||||
|
||||
/*
|
||||
* Figure out which listening socket got a connection. This loop should
|
||||
* really call a function for each ready socket instead of breaking on
|
||||
* the first one.
|
||||
*/
|
||||
for (i = 0; i <= listen_fdlist.fdmax && fds_ready > 0; i++) {
|
||||
/* Loop through descriptors until there is something ready */
|
||||
if (!checked_fd_isset(i, &fds))
|
||||
continue;
|
||||
|
||||
/* Check each listening socket */
|
||||
for (j = 0; j < num_sockets; j++) {
|
||||
if (i == sockfd[j].fd) {
|
||||
if (o.debug > 1)
|
||||
logdebug("Valid descriptor %d \n", i);
|
||||
fdn = j;
|
||||
socket_n = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we found a valid socket break */
|
||||
if (fdn != -1) {
|
||||
fds_ready--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure someone connected */
|
||||
if (fdn == -1)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We just peek so we can get the client connection details without
|
||||
* removing anything from the queue. Sigh.
|
||||
*/
|
||||
nbytes = recvfrom(socket_n, buf, sizeof(buf), MSG_PEEK,
|
||||
&remotess.sockaddr, &sslen);
|
||||
if (nbytes < 0) {
|
||||
loguser("%s.\n", socket_strerror(socket_errno()));
|
||||
close(socket_n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check conditions that might cause us to deny the connection. */
|
||||
conn_count = get_conn_count();
|
||||
if (conn_count >= o.conn_limit) {
|
||||
if (o.verbose)
|
||||
loguser("New connection denied: connection limit reached (%d)\n", conn_count);
|
||||
} else if (!allow_access(&remotess)) {
|
||||
if (o.verbose)
|
||||
loguser("New connection denied: not allowed\n");
|
||||
} else {
|
||||
/* Good to go. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Dump the current datagram */
|
||||
nbytes = recv(socket_n, buf, sizeof(buf), 0);
|
||||
if (nbytes < 0) {
|
||||
loguser("%s.\n", socket_strerror(socket_errno()));
|
||||
close(socket_n);
|
||||
return 1;
|
||||
}
|
||||
ncat_log_recv(buf, nbytes);
|
||||
}
|
||||
|
||||
if (o.verbose) {
|
||||
#if HAVE_SYS_UN_H
|
||||
if (remotess.sockaddr.sa_family == AF_UNIX)
|
||||
loguser("Connection from %s.\n", remotess.un.sun_path);
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_VM_SOCKETS_H
|
||||
if (remotess.sockaddr.sa_family == AF_VSOCK)
|
||||
loguser("Connection from %u.\n", remotess.vm.svm_cid);
|
||||
else
|
||||
#endif
|
||||
loguser("Connection from %s.\n", inet_socktop(&remotess));
|
||||
}
|
||||
|
||||
conn_inc++;
|
||||
|
||||
/*
|
||||
* We're using connected udp. This has the down side of only
|
||||
* being able to handle one udp client at a time
|
||||
*/
|
||||
Connect(socket_n, &remotess.sockaddr, sslen);
|
||||
|
||||
/* clean slate for buf */
|
||||
zmem(buf, sizeof(buf));
|
||||
|
||||
/* are we executing a command? then do it */
|
||||
if (o.cmdexec) {
|
||||
struct fdinfo info = { 0 };
|
||||
|
||||
info.fd = socket_n;
|
||||
info.remoteaddr = remotess;
|
||||
if (o.keepopen)
|
||||
netrun(&info, o.cmdexec);
|
||||
else
|
||||
netexec(&info, o.cmdexec);
|
||||
continue;
|
||||
}
|
||||
|
||||
checked_fd_set(socket_n, &read_fds);
|
||||
checked_fd_set(STDIN_FILENO, &read_fds);
|
||||
fdmax = socket_n;
|
||||
|
||||
/* stdin -> socket and socket -> stdout */
|
||||
while (1) {
|
||||
fd_set fds;
|
||||
|
||||
fds = read_fds;
|
||||
|
||||
if (o.debug > 1)
|
||||
logdebug("udp select'ing\n");
|
||||
|
||||
if (o.idletimeout > 0)
|
||||
ms_to_timeval(tvp, o.idletimeout);
|
||||
|
||||
fds_ready = fselect(fdmax + 1, &fds, NULL, NULL, tvp);
|
||||
|
||||
if (fds_ready == 0)
|
||||
bye("Idle timeout expired (%d ms).", o.idletimeout);
|
||||
|
||||
if (checked_fd_isset(STDIN_FILENO, &fds)) {
|
||||
nbytes = Read(STDIN_FILENO, buf, sizeof(buf));
|
||||
if (nbytes <= 0) {
|
||||
if (nbytes < 0 && o.verbose) {
|
||||
logdebug("Error reading from stdin: %s\n", strerror(errno));
|
||||
} else if (nbytes == 0 && o.debug) {
|
||||
logdebug("EOF on stdin\n");
|
||||
}
|
||||
checked_fd_clr(STDIN_FILENO, &read_fds);
|
||||
if (nbytes < 0)
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
if (o.crlf)
|
||||
fix_line_endings((char *) buf, &nbytes, &tempbuf, &crlf_state);
|
||||
if (!o.recvonly) {
|
||||
if (tempbuf != NULL)
|
||||
n = send(socket_n, tempbuf, nbytes, 0);
|
||||
else
|
||||
n = send(socket_n, buf, nbytes, 0);
|
||||
if (n < nbytes) {
|
||||
loguser("%s.\n", socket_strerror(socket_errno()));
|
||||
close(socket_n);
|
||||
return 1;
|
||||
}
|
||||
ncat_log_send(buf, nbytes);
|
||||
}
|
||||
if (tempbuf != NULL) {
|
||||
free(tempbuf);
|
||||
tempbuf = NULL;
|
||||
}
|
||||
}
|
||||
if (checked_fd_isset(socket_n, &fds)) {
|
||||
nbytes = recv(socket_n, buf, sizeof(buf), 0);
|
||||
if (nbytes < 0) {
|
||||
loguser("%s.\n", socket_strerror(socket_errno()));
|
||||
close(socket_n);
|
||||
return 1;
|
||||
}
|
||||
ncat_log_recv(buf, nbytes);
|
||||
if (!o.sendonly)
|
||||
Write(STDOUT_FILENO, buf, nbytes);
|
||||
}
|
||||
|
||||
zmem(buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncat_listen()
|
||||
{
|
||||
#if HAVE_SYS_UN_H
|
||||
if (o.af == AF_UNIX)
|
||||
if (o.proto == IPPROTO_UDP)
|
||||
return ncat_listen_dgram(0);
|
||||
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();
|
||||
else if (o.proto == IPPROTO_UDP)
|
||||
return ncat_listen_dgram(o.proto);
|
||||
else if (o.proto == IPPROTO_SCTP)
|
||||
return ncat_listen_stream(o.proto);
|
||||
else if (o.proto == IPPROTO_TCP)
|
||||
return ncat_listen_stream(o.proto);
|
||||
else
|
||||
bye("Unknown o.proto %d\n", o.proto);
|
||||
|
||||
/* unreached */
|
||||
return 1;
|
||||
}
|
||||
|
||||
//---------------
|
||||
/* Read from recv_fd and broadcast whatever is read to all other descriptors in
|
||||
|
||||
@@ -984,13 +984,6 @@ int main(int argc, char *argv[])
|
||||
if (o.ssl)
|
||||
bye("OpenSSL does not have DTLS support compiled in.");
|
||||
#endif
|
||||
if (o.keepopen && o.cmdexec == NULL)
|
||||
bye("UDP mode does not support the -k or --keep-open options, except with --exec or --sh-exec.");
|
||||
if (o.broker)
|
||||
bye("UDP mode does not support connection brokering.\n\
|
||||
If this feature is important to you, write dev@nmap.org with a\n\
|
||||
description of how you intend to use it, as an aid to deciding how UDP\n\
|
||||
connection brokering should work.");
|
||||
}
|
||||
|
||||
/* Do whatever is necessary to receive \n for line endings on input from
|
||||
|
||||
@@ -140,7 +140,7 @@ int ncat_http_server(void)
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (o.ssl)
|
||||
setup_ssl_listen();
|
||||
setup_ssl_listen(SSLv23_server_method());
|
||||
#endif
|
||||
/* Clear the socket list */
|
||||
for (i = 0; i < NUM_LISTEN_ADDRS; i++)
|
||||
|
||||
@@ -105,10 +105,8 @@ enum {
|
||||
};
|
||||
#define CERTIFICATE_COMMENT "Automatically generated by Ncat. See https://nmap.org/ncat/."
|
||||
|
||||
SSL_CTX *setup_ssl_listen(void)
|
||||
SSL_CTX *setup_ssl_listen(const SSL_METHOD *method)
|
||||
{
|
||||
const SSL_METHOD *method;
|
||||
|
||||
if (sslctx)
|
||||
goto done;
|
||||
|
||||
@@ -138,8 +136,8 @@ SSL_CTX *setup_ssl_listen(void)
|
||||
if (!RAND_status())
|
||||
bye("Failed to seed OpenSSL PRNG (RAND_status returned false).");
|
||||
|
||||
if (!(method = SSLv23_server_method()))
|
||||
bye("SSLv23_server_method(): %s.", ERR_error_string(ERR_get_error(), NULL));
|
||||
if (!method)
|
||||
bye("Invalid SSL method: %s.", ERR_error_string(ERR_get_error(), NULL));
|
||||
if (!(sslctx = SSL_CTX_new(method)))
|
||||
bye("SSL_CTX_new(): %s.", ERR_error_string(ERR_get_error(), NULL));
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ enum {
|
||||
NCAT_SSL_HANDSHAKE_FAILED = 3
|
||||
};
|
||||
|
||||
extern SSL_CTX *setup_ssl_listen(void);
|
||||
extern SSL_CTX *setup_ssl_listen(const SSL_METHOD *method);
|
||||
|
||||
extern SSL *new_ssl(int fd);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user