/* Broadcast a message to all the descriptors in fds. Returns -1 if any of the sends failed. */ int ncat_broadcast(fd_set *fds, const fd_list_t *fdlist, const char *msg, size_t size) { struct fdinfo *fdn; int i, ret; if (o.recvonly) return size; ret = 0; for (i = 0; i <= fdlist->fdmax; i++) { if (!FD_ISSET(i, fds)) continue; fdn = get_fdinfo(fdlist, i); ncat_assert(fdn != NULL); if (blocking_fdinfo_send(fdn, msg, size) <= 0) { if (o.debug > 1) logdebug("Error sending to fd %d: %s.\n", i, socket_strerror(socket_errno())); ret = -1; } } ncat_log_send(msg, size); return ret; }
int ncat_send(struct fdinfo *fdn, const char *buf, size_t size) { int n; if (o.recvonly) return size; n = blocking_fdinfo_send(fdn, buf, size); if (n <= 0) return n; ncat_log_send(buf, size); return n; }
static void read_stdin_handler(nsock_pool nsp, nsock_event evt, void *data) { enum nse_status status = nse_status(evt); enum nse_type type = nse_type(evt); char *buf, *tmp = NULL; int nbytes; assert(type == NSE_TYPE_READ); if (status == NSE_STATUS_EOF) { if (o.sendonly) { /* In --send-only mode, exit after EOF on stdin. */ nsock_loop_quit(nsp); } else { shutdown(nsi_getsd(cs.sock_nsi), SHUT_WR); } return; } else if (status == NSE_STATUS_ERROR) { loguser("%s.\n", socket_strerror(nse_errorcode(evt))); exit(1); } else if (status == NSE_STATUS_TIMEOUT) { loguser("%s.\n", socket_strerror(ETIMEDOUT)); exit(1); } else if (status == NSE_STATUS_CANCELLED || status == NSE_STATUS_KILL) { return; } else { assert(status == NSE_STATUS_SUCCESS); } buf = nse_readbuf(evt, &nbytes); /* read from stdin */ if (o.linedelay) ncat_delay_timer(o.linedelay); if (o.crlf) { if (fix_line_endings(buf, &nbytes, &tmp, &cs.crlf_state)) buf = tmp; } nsock_write(nsp, cs.sock_nsi, write_socket_handler, -1, NULL, buf, nbytes); ncat_log_send(buf, nbytes); if (tmp) free(tmp); refresh_idle_timer(nsp); }
void ncat_log_recv(const char *data, size_t len) { /* Currently the log formats don't distinguish sends and receives. */ ncat_log_send(data, len); }
/* 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; 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; } 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 */ 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())); 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); fds_ready = fselect(listen_fdlist.fdmax + 1, &fds, NULL, NULL, tvp); 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 (!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.debug > 1) logdebug("Valid Connection from %d\n", socket_n); 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; if (o.keepopen) netrun(&info, o.cmdexec); else netexec(&info, o.cmdexec); continue; } FD_SET(socket_n, &read_fds); 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 (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"); } 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 (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; }