mirror of
https://github.com/nmap/nmap.git
synced 2026-08-27 11:55:27 +00:00
Merge 647c28b9da into db4aefddfa
This commit is contained in:
commit
ef9adc7ac3
4 changed files with 147 additions and 4 deletions
|
|
@ -306,6 +306,20 @@ void nsock_proxychain_delete(nsock_proxychain chain);
|
|||
* nsock_pool_set_proxychain(). Existing nsock_iod will connect as normal. */
|
||||
int nsock_pool_set_proxychain(nsock_pool nspool, nsock_proxychain chain);
|
||||
|
||||
/* Proxy type constants returned by nsock_proxychain_first_node_info(). */
|
||||
#define NSOCK_PROXY_TYPE_HTTP 0
|
||||
#define NSOCK_PROXY_TYPE_SOCKS4 1
|
||||
|
||||
/* Retrieve the address, port, and type of the first proxy node in a chain.
|
||||
* ss and sslen are filled with the proxy server's sockaddr. port is filled with
|
||||
* the proxy port. proxy_type is set to one of the NSOCK_PROXY_TYPE_* constants.
|
||||
* Returns 1 on success, 0 if the chain is NULL or empty. */
|
||||
int nsock_proxychain_first_node_info(nsock_proxychain chain,
|
||||
struct sockaddr_storage *ss,
|
||||
size_t *sslen,
|
||||
unsigned short *port,
|
||||
int *proxy_type);
|
||||
|
||||
/* nsock_event handles a single event. Its ID is generally returned when the
|
||||
* event is created, and the event itself is included in callbacks
|
||||
*
|
||||
|
|
|
|||
|
|
@ -152,6 +152,30 @@ int nsock_pool_set_proxychain(nsock_pool nspool, nsock_proxychain chain) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int nsock_proxychain_first_node_info(nsock_proxychain chain,
|
||||
struct sockaddr_storage *ss,
|
||||
size_t *sslen,
|
||||
unsigned short *port,
|
||||
int *proxy_type) {
|
||||
struct proxy_chain *pchain = (struct proxy_chain *)chain;
|
||||
gh_lnode_t *first;
|
||||
struct proxy_node *node;
|
||||
|
||||
if (!pchain)
|
||||
return 0;
|
||||
|
||||
first = gh_list_first_elem(&pchain->nodes);
|
||||
if (!first)
|
||||
return 0;
|
||||
|
||||
node = container_of(first, struct proxy_node, nodeq);
|
||||
*ss = node->ss;
|
||||
*sslen = node->sslen;
|
||||
*port = node->port;
|
||||
*proxy_type = (int)node->spec->type;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) {
|
||||
struct npool *nsp = (struct npool *)nspool;
|
||||
struct proxy_chain_context *ctx;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,15 @@ public:
|
|||
ConnectProbe();
|
||||
~ConnectProbe();
|
||||
int sd; /* Socket descriptor used for connection. -1 if not valid. */
|
||||
|
||||
/* SOCKS4 proxy state for connect scans using --proxy. */
|
||||
enum ProxyState { PROXY_NONE = 0, PROXY_CONNECTING, PROXY_READING };
|
||||
ProxyState proxy_state;
|
||||
struct sockaddr_storage proxy_target_ss; /* original target address */
|
||||
size_t proxy_target_sslen;
|
||||
uint16_t proxy_target_port;
|
||||
uint8_t proxy_resp_buf[8]; /* buffer for 8-byte SOCKS4 response */
|
||||
int proxy_resp_len; /* bytes received so far */
|
||||
};
|
||||
|
||||
struct IPExtraProbeData_icmp {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
#include "scan_engine_connect.h"
|
||||
#include "libnetutil/netutil.h" /* for max_sd() */
|
||||
#include "NmapOps.h"
|
||||
#include <nsock.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
|
@ -207,6 +208,10 @@ bool ConnectScanInfo::clearSD(int sd) {
|
|||
|
||||
ConnectProbe::ConnectProbe() {
|
||||
sd = -1;
|
||||
proxy_state = PROXY_NONE;
|
||||
proxy_target_sslen = 0;
|
||||
proxy_target_port = 0;
|
||||
proxy_resp_len = 0;
|
||||
}
|
||||
|
||||
ConnectProbe::~ConnectProbe() {
|
||||
|
|
@ -488,6 +493,31 @@ UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss,
|
|||
#if HAVE_IPV6
|
||||
else sin6->sin6_port = htons(probe->pspec()->pd.tcp.dport);
|
||||
#endif
|
||||
|
||||
/* If a SOCKS4 proxy chain is configured, connect to the proxy instead of
|
||||
* the target directly and perform the SOCKS4 handshake asynchronously. */
|
||||
struct sockaddr_storage proxy_ss;
|
||||
size_t proxy_sslen = 0;
|
||||
unsigned short proxy_port = 0;
|
||||
int proxy_type = -1;
|
||||
if (o.proxy_chain &&
|
||||
nsock_proxychain_first_node_info(o.proxy_chain, &proxy_ss, &proxy_sslen,
|
||||
&proxy_port, &proxy_type) == 1 &&
|
||||
proxy_type == NSOCK_PROXY_TYPE_SOCKS4 &&
|
||||
sock.ss_family == AF_INET) {
|
||||
/* Save the real target so we can build the SOCKS4 request later. */
|
||||
CP->proxy_state = ConnectProbe::PROXY_CONNECTING;
|
||||
memcpy(&CP->proxy_target_ss, &sock, socklen);
|
||||
CP->proxy_target_sslen = socklen;
|
||||
CP->proxy_target_port = destport;
|
||||
|
||||
/* Point sin/socklen at the proxy address. */
|
||||
((struct sockaddr_in *)&proxy_ss)->sin_port = htons(proxy_port);
|
||||
memcpy(&sock, &proxy_ss, proxy_sslen);
|
||||
socklen = proxy_sslen;
|
||||
sin = (struct sockaddr_in *) &sock;
|
||||
}
|
||||
|
||||
/* We don't record a byte count for connect probes. */
|
||||
hss->probeSent(0);
|
||||
rc = connect(CP->sd, (struct sockaddr *)&sock, socklen);
|
||||
|
|
@ -510,6 +540,23 @@ UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss,
|
|||
PacketTrace::traceConnect(IPPROTO_TCP, (sockaddr *) &sock, socklen, rc,
|
||||
connect_errno, &USI->now);
|
||||
USI->gstats->CSI->watchSD(CP->sd);
|
||||
} else if (CP->proxy_state == ConnectProbe::PROXY_CONNECTING && connect_errno == 0) {
|
||||
/* Immediate synchronous connect to proxy succeeded — send SOCKS4 request
|
||||
* and watch for the response. */
|
||||
uint8_t req[9];
|
||||
struct sockaddr_in *tsin = (struct sockaddr_in *)&CP->proxy_target_ss;
|
||||
req[0] = 4; req[1] = 1;
|
||||
req[2] = (CP->proxy_target_port >> 8) & 0xff;
|
||||
req[3] = CP->proxy_target_port & 0xff;
|
||||
memcpy(&req[4], &tsin->sin_addr.s_addr, 4);
|
||||
req[8] = 0; /* empty user id */
|
||||
if (send(CP->sd, (char *)req, sizeof(req), 0) == (int)sizeof(req)) {
|
||||
CP->proxy_state = ConnectProbe::PROXY_READING;
|
||||
USI->gstats->CSI->watchSD(CP->sd);
|
||||
} else {
|
||||
handleConnectResult(USI, hss, probeI, ECONNREFUSED, true);
|
||||
probe = NULL;
|
||||
}
|
||||
} else {
|
||||
handleConnectResult(USI, hss, probeI, connect_errno, true);
|
||||
probe = NULL;
|
||||
|
|
@ -601,11 +648,60 @@ bool do_one_select_round(UltraScanInfo *USI, struct timeval *stime) {
|
|||
checked_fd_isset(sd, &fds_wtmp) ||
|
||||
checked_fd_isset(sd, &fds_xtmp))) {
|
||||
numGoodSD++;
|
||||
if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char *) &optval,
|
||||
&optlen) != 0)
|
||||
optval = socket_errno(); /* Stupid Solaris ... */
|
||||
ConnectProbe *CP = probe->CP();
|
||||
|
||||
handleConnectResult(USI, host, probeI, optval);
|
||||
if (CP->proxy_state == ConnectProbe::PROXY_CONNECTING) {
|
||||
/* Connected (or failed) to proxy server. Check result. */
|
||||
if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char *) &optval,
|
||||
&optlen) != 0)
|
||||
optval = socket_errno();
|
||||
if (optval != 0) {
|
||||
handleConnectResult(USI, host, probeI, optval);
|
||||
} else {
|
||||
/* Send the 9-byte SOCKS4 CONNECT request. */
|
||||
uint8_t req[9];
|
||||
struct sockaddr_in *tsin =
|
||||
(struct sockaddr_in *)&CP->proxy_target_ss;
|
||||
req[0] = 4; req[1] = 1;
|
||||
req[2] = (CP->proxy_target_port >> 8) & 0xff;
|
||||
req[3] = CP->proxy_target_port & 0xff;
|
||||
memcpy(&req[4], &tsin->sin_addr.s_addr, 4);
|
||||
req[8] = 0; /* empty user id */
|
||||
if (send(sd, (char *)req, sizeof(req), 0) == (int)sizeof(req)) {
|
||||
CP->proxy_state = ConnectProbe::PROXY_READING;
|
||||
/* Stop watching for writability; keep read + except. */
|
||||
checked_fd_clr(sd, &USI->gstats->CSI->fds_write);
|
||||
} else {
|
||||
handleConnectResult(USI, host, probeI, ECONNREFUSED);
|
||||
}
|
||||
}
|
||||
} else if (CP->proxy_state == ConnectProbe::PROXY_READING) {
|
||||
/* Reading the 8-byte SOCKS4 response. */
|
||||
int recvd = recv(sd,
|
||||
(char *)CP->proxy_resp_buf + CP->proxy_resp_len,
|
||||
8 - CP->proxy_resp_len, 0);
|
||||
if (recvd > 0) {
|
||||
CP->proxy_resp_len += recvd;
|
||||
if (CP->proxy_resp_len >= 8) {
|
||||
/* Full response received: byte[1]==90 means granted. */
|
||||
if (CP->proxy_resp_buf[1] == 90)
|
||||
handleConnectResult(USI, host, probeI, 0);
|
||||
else
|
||||
handleConnectResult(USI, host, probeI, ECONNREFUSED);
|
||||
}
|
||||
/* Partial read: probe stays outstanding, wait for more data. */
|
||||
} else if (recvd == 0) {
|
||||
handleConnectResult(USI, host, probeI, ECONNREFUSED);
|
||||
} else {
|
||||
handleConnectResult(USI, host, probeI, socket_errno());
|
||||
}
|
||||
} else {
|
||||
/* Normal (no proxy) connect result. */
|
||||
if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char *) &optval,
|
||||
&optlen) != 0)
|
||||
optval = socket_errno(); /* Stupid Solaris ... */
|
||||
handleConnectResult(USI, host, probeI, optval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue