mirror of
https://github.com/nmap/nmap.git
synced 2025-12-20 22:49:01 +00:00
Design improvements.
Externally: The calling application can build a proxychain object and assign it to one (or more) NSP. Once a NSP get assigned a proxychain it's not possible to remove it so that consistency is (should be...) ensured. Internally: An IOD comes with a proxychain context structure storing the whole tunnel state. Also each proxy type now has a table of associated functions to use as hooks for TCP connects(), read() and write() requests. As a result, adding support of new proxy type should be easier. Code also gains readability in comparison to large switch/cases that redirect the execution flow according to the given proxy type.
This commit is contained in:
@@ -131,6 +131,8 @@ typedef void *nsock_ssl_session;
|
||||
typedef void *nsock_ssl_ctx;
|
||||
typedef void *nsock_ssl;
|
||||
|
||||
typedef void *nsock_proxychain;
|
||||
|
||||
|
||||
/* Logging-related data structures */
|
||||
|
||||
@@ -187,8 +189,6 @@ enum nsock_loopstatus {
|
||||
NSOCK_LOOP_QUIT
|
||||
};
|
||||
|
||||
int nsock_set_proxychain(nsock_pool nsp, const char *proxystr);
|
||||
|
||||
enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout);
|
||||
|
||||
/* Calling this function will cause nsock_loop to quit on its next iteration
|
||||
@@ -270,6 +270,21 @@ void nsock_set_log_function(nsock_pool nsp, nsock_logger_t logger);
|
||||
nsock_loglevel_t nsock_get_loglevel(nsock_pool nsp);
|
||||
void nsock_set_loglevel(nsock_pool nsp, nsock_loglevel_t loglevel);
|
||||
|
||||
/* Parse a proxy chain description string and build a nsock_proxychain object
|
||||
* accordingly. If the optional nsock_pool parameter is passed in, it gets
|
||||
* associated to the chain object. The alternative is to pass nsp=NULL and call
|
||||
* nsp_set_proxychain() manually. Whatever is done, the chain object has to be
|
||||
* deleted by the caller, using proxychain_delete(). */
|
||||
int nsock_proxychain_new(const char *proxystr, nsock_proxychain *chain, nsock_pool nspool);
|
||||
|
||||
/* If nsock_proxychain_new() returned success, caller has to free the chain
|
||||
* object using this function. */
|
||||
void nsock_proxychain_delete(nsock_proxychain chain);
|
||||
|
||||
/* Assign a previously created proxychain object to a nsock pool. After this,
|
||||
* new connections requests will be issued through the chain of proxies (if
|
||||
* possible). */
|
||||
int nsp_set_proxychain(nsock_pool nspool, nsock_proxychain chain);
|
||||
|
||||
/* nsock_event handles a single event. Its ID is generally returned when the
|
||||
* event is created, and the event itself is included in callbacks
|
||||
|
||||
@@ -66,6 +66,9 @@
|
||||
#include <string.h>
|
||||
|
||||
|
||||
extern struct proxy_actions *ProxyActions;
|
||||
|
||||
|
||||
/* Create the actual socket (nse->iod->sd) underlying the iod. This unblocks the
|
||||
* socket, binds to the localaddr address, sets IP options, and sets the
|
||||
* broadcast flag. Trying to change these functions after making this call will
|
||||
@@ -266,15 +269,7 @@ nsock_event_id nsock_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_hand
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
|
||||
if (nsi->px_ctx) {
|
||||
memcpy(&nsi->px_ctx->target_ss, saddr, sslen);
|
||||
nsi->px_ctx->target_sslen = sslen;
|
||||
nsi->px_ctx->target_port = port;
|
||||
nsi->px_ctx->target_handler = handler;
|
||||
|
||||
saddr = (struct sockaddr *)&nsi->px_ctx->px_current->ss;
|
||||
sslen = nsi->px_ctx->px_current->sslen;
|
||||
port = nsi->px_ctx->px_current->port;
|
||||
handler = nsock_proxy_ev_handler;
|
||||
return IOD_PX_TCP_CONNECT(nsi)(nsp, ms_iod, handler, timeout_msecs, userdata, saddr, sslen, port);
|
||||
}
|
||||
|
||||
return nsock_connect_tcp_direct(nsp, ms_iod, handler, timeout_msecs, userdata, saddr, sslen, port);
|
||||
|
||||
@@ -219,8 +219,9 @@ typedef struct {
|
||||
SSL_CTX *sslctx;
|
||||
#endif
|
||||
|
||||
/* Proxy chain (or NULL) */
|
||||
struct proxy_node *px_chain;
|
||||
/* Optional proxy chain (NULL is not set). Can only be set once per NSP (using
|
||||
* nsock_proxychain_new() or nsp_set_proxychain(). */
|
||||
struct proxy_chain *px_chain;
|
||||
|
||||
} mspool;
|
||||
|
||||
|
||||
@@ -84,52 +84,94 @@ static void proxy_parser_delete(struct proxy_parser *parser);
|
||||
|
||||
static struct proxy_node *proxy_node_new(char *proxystr);
|
||||
static void proxy_node_delete(struct proxy_node *proxy);
|
||||
static void proxy_chain_delete(struct proxy_node *chain);
|
||||
|
||||
static void forward_event(mspool *nsp, msevent *nse, void *udata);
|
||||
|
||||
void proxy_http_node_init(struct proxy_node *proxy, char *proxystr);
|
||||
static void proxy_http_node_init(struct proxy_node *proxy, char *proxystr);
|
||||
static void proxy_http_ev_handler(nsock_pool nspool, nsock_event nsevent, void *udata);
|
||||
|
||||
|
||||
static nsock_event_id proxy_http_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler,
|
||||
int timeout_msecs, void *userdata, struct sockaddr *saddr,
|
||||
size_t sslen, unsigned short port);
|
||||
static char *proxy_http_data_encode(const char *src, size_t len, size_t *dlen);
|
||||
static char *proxy_http_data_decode(const char *src, size_t len, size_t *dlen);
|
||||
|
||||
/* XXX for the sake of stability we might want to have
|
||||
* a write-once only API. So that proxyinfo pointers that
|
||||
* are used in the IODs remain valid...
|
||||
*
|
||||
* A proxy chain is a comma-separated list of proxy specification strings:
|
||||
* proto://[user:pass@]host[:port]
|
||||
*/
|
||||
int nsock_set_proxychain(nsock_pool nspool, const char *proxystr) {
|
||||
mspool *nsp = (mspool *)nspool;
|
||||
|
||||
if (nsp->px_chain) {
|
||||
proxy_chain_delete(nsp->px_chain);
|
||||
nsp->px_chain = NULL;
|
||||
const struct proxy_actions ProxyActions[PROXY_TYPE_COUNT] = {
|
||||
[PROXY_TYPE_HTTP] = {
|
||||
.connect_tcp = proxy_http_connect_tcp,
|
||||
.data_encode = proxy_http_data_encode,
|
||||
.data_decode = proxy_http_data_decode
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* A proxy chain is a comma-separated list of proxy specification strings:
|
||||
* proto://[user:pass@]host[:port] */
|
||||
int nsock_proxychain_new(const char *proxystr, nsock_proxychain *chain, nsock_pool nspool) {
|
||||
mspool *nsp = (mspool *)nspool;
|
||||
struct proxy_chain **pchain = (struct proxy_chain **)chain;
|
||||
|
||||
*pchain = (struct proxy_chain *)safe_malloc(sizeof(struct proxy_chain));
|
||||
(*pchain)->specstr = strdup(proxystr);
|
||||
gh_list_init(&(*pchain)->nodes);
|
||||
|
||||
/* Pass NULL to reset the proxy chain. */
|
||||
if (proxystr) {
|
||||
struct proxy_node **ppx;
|
||||
struct proxy_parser *parser;
|
||||
|
||||
ppx = &nsp->px_chain;
|
||||
for (parser = proxy_parser_new(proxystr); !parser->done; proxy_parser_next(parser)) {
|
||||
*ppx = parser->value;
|
||||
ppx = &parser->value->next;
|
||||
gh_list_append(&(*pchain)->nodes, parser->value);
|
||||
}
|
||||
proxy_parser_delete(parser);
|
||||
}
|
||||
|
||||
if (nsp) {
|
||||
if (nsp_set_proxychain(nspool, *pchain) < 0) {
|
||||
nsock_proxychain_delete(*pchain);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nsock_proxychain_delete(nsock_proxychain chain) {
|
||||
struct proxy_chain *pchain = (struct proxy_chain *)chain;
|
||||
|
||||
if (pchain) {
|
||||
struct proxy_node *node;
|
||||
|
||||
free(pchain->specstr);
|
||||
while ((node = (struct proxy_node *)gh_list_pop(&pchain->nodes)) != NULL) {
|
||||
proxy_node_delete(node);
|
||||
}
|
||||
|
||||
gh_list_free(&pchain->nodes);
|
||||
free(pchain);
|
||||
}
|
||||
}
|
||||
|
||||
int nsp_set_proxychain(nsock_pool nspool, nsock_proxychain chain) {
|
||||
mspool *nsp = (mspool *)nspool;
|
||||
|
||||
if (nsp && nsp->px_chain) {
|
||||
nsock_trace(nsp, "Invalid call to %s. Existing proxychain on this nsock_pool", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nsp->px_chain = (struct proxy_chain *)chain;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct proxy_chain_context *proxy_chain_context_new(nsock_pool nspool) {
|
||||
mspool *nsp = (mspool *)nspool;
|
||||
struct proxy_chain_context *ctx;
|
||||
|
||||
ctx = (struct proxy_chain_context *)safe_malloc(sizeof(struct proxy_chain_context));
|
||||
ctx->px_state = PROXY_STATE_INITIAL;
|
||||
ctx->px_current = nsp->px_chain;
|
||||
ctx->px_current = GH_LIST_FIRST_ELEM(&nsp->px_chain->nodes);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -188,7 +230,6 @@ static struct proxy_node *proxy_node_new(char *proxystr) {
|
||||
}
|
||||
|
||||
proxy->px_type = PROXY_TYPE_HTTP;
|
||||
proxy->next = NULL;
|
||||
proxy_http_node_init(proxy, proxystr);
|
||||
|
||||
return proxy;
|
||||
@@ -199,15 +240,6 @@ static void proxy_node_delete(struct proxy_node *proxy) {
|
||||
free(proxy);
|
||||
}
|
||||
|
||||
static void proxy_chain_delete(struct proxy_node *chain) {
|
||||
struct proxy_node *p, *next;
|
||||
|
||||
for (p = chain; p != NULL; p = next) {
|
||||
next = p->next;
|
||||
proxy_node_delete(p);
|
||||
}
|
||||
}
|
||||
|
||||
void forward_event(mspool *nsp, msevent *nse, void *udata) {
|
||||
enum nse_type cached_type;
|
||||
enum nse_status cached_status;
|
||||
@@ -230,17 +262,19 @@ void forward_event(mspool *nsp, msevent *nse, void *udata) {
|
||||
|
||||
void nsock_proxy_ev_handler(nsock_pool nspool, nsock_event nsevent, void *udata) {
|
||||
msevent *nse = (msevent *)nsevent;
|
||||
struct proxy_node *current;
|
||||
|
||||
if (nse->status != NSE_STATUS_SUCCESS)
|
||||
fatal("Error, but this is debug only!");
|
||||
|
||||
switch (nse->iod->px_ctx->px_current->px_type) {
|
||||
current = PROXY_CTX_CURRENT(nse->iod->px_ctx);
|
||||
switch (current->px_type) {
|
||||
case PROXY_TYPE_HTTP:
|
||||
proxy_http_ev_handler(nspool, nsevent, udata);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("Invalid proxy type (%d)", nse->iod->px_ctx->px_current->px_type);
|
||||
fatal("Invalid proxy type (%d)", current->px_type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,16 +308,17 @@ void proxy_http_ev_handler(nsock_pool nspool, nsock_event nsevent, void *udata)
|
||||
case PROXY_STATE_INITIAL:
|
||||
nse->iod->px_ctx->px_state = PROXY_STATE_HTTP_TCP_CONNECTED;
|
||||
|
||||
if (nse->iod->px_ctx->px_current->next == NULL) {
|
||||
if (PROXY_CTX_NEXT(nse->iod->px_ctx)) {
|
||||
struct proxy_node *next;
|
||||
|
||||
next = PROXY_CTX_NEXT(nse->iod->px_ctx);
|
||||
ss = &next->ss;
|
||||
sslen = next->sslen;
|
||||
port = next->port;
|
||||
} else {
|
||||
ss = &nse->iod->px_ctx->target_ss;
|
||||
sslen = nse->iod->px_ctx->target_sslen;
|
||||
port = nse->iod->px_ctx->target_port;
|
||||
|
||||
assert(inet_ntop_ez(ss, sslen));
|
||||
} else {
|
||||
ss = &nse->iod->px_ctx->px_current->next->ss;
|
||||
sslen = nse->iod->px_ctx->px_current->next->sslen;
|
||||
port = nse->iod->px_ctx->px_current->next->port;
|
||||
}
|
||||
nsock_printf(nspool, (nsock_iod)nse->iod, nsock_proxy_ev_handler,
|
||||
4000, udata, "CONNECT %s:%d HTTP/1.1\r\n\r\n",
|
||||
@@ -323,3 +358,33 @@ void proxy_http_ev_handler(nsock_pool nspool, nsock_event nsevent, void *udata)
|
||||
}
|
||||
}
|
||||
|
||||
nsock_event_id proxy_http_connect_tcp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler,
|
||||
int timeout_msecs, void *userdata, struct sockaddr *saddr,
|
||||
size_t sslen, unsigned short port) {
|
||||
msiod *nsi = (msiod *)ms_iod;
|
||||
struct proxy_node *current;
|
||||
|
||||
memcpy(&nsi->px_ctx->target_ss, saddr, sslen);
|
||||
nsi->px_ctx->target_sslen = sslen;
|
||||
nsi->px_ctx->target_port = port;
|
||||
nsi->px_ctx->target_handler = handler;
|
||||
|
||||
current = PROXY_CTX_CURRENT(nsi->px_ctx);
|
||||
saddr = (struct sockaddr *)¤t->ss;
|
||||
sslen = current->sslen;
|
||||
port = current->port;
|
||||
handler = nsock_proxy_ev_handler;
|
||||
|
||||
return nsock_connect_tcp_direct(nsp, ms_iod, handler, timeout_msecs, userdata, saddr, sslen, port);
|
||||
}
|
||||
|
||||
char *proxy_http_data_encode(const char *src, size_t len, size_t *dlen) {
|
||||
// TODO
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *proxy_http_data_decode(const char *src, size_t len, size_t *dlen) {
|
||||
// TODO
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,11 +57,24 @@
|
||||
#ifndef NSOCK_PROXY_H
|
||||
#define NSOCK_PROXY_H
|
||||
|
||||
#include "gh_list.h"
|
||||
#include <nsock.h>
|
||||
|
||||
|
||||
/* ------------------ UTIL MACROS ------------------ */
|
||||
#define PROXY_CTX_CURRENT(ctx) ((struct proxy_node *)(GH_LIST_ELEM_DATA((ctx)->px_current)))
|
||||
#define PROXY_CTX_NEXT(ctx) ((struct proxy_node *)((GH_LIST_ELEM_NEXT((ctx)->px_current)) ? GH_LIST_ELEM_DATA(GH_LIST_ELEM_NEXT((ctx)->px_current)) : NULL))
|
||||
#define PROXY_CTX_NODES(ctx) ((ctx)->px_chain->nodes)
|
||||
|
||||
#define IOD_PX_TCP_CONNECT(iod) (ProxyActions[PROXY_CTX_CURRENT((iod)->px_ctx)->px_type].connect_tcp)
|
||||
#define IOD_PX_DATA_ENCODE(iod) (ProxyActions[PROXY_CTX_CURRENT((iod)->px_ctx)->px_type].data_encode)
|
||||
#define IOD_PX_DATA_DECODE(iod) (ProxyActions[PROXY_CTX_CURRENT((iod)->px_ctx)->px_type].data_decode)
|
||||
|
||||
|
||||
/* ------------------- CONSTANTS ------------------- */
|
||||
enum nsock_proxy_type {
|
||||
PROXY_TYPE_HTTP,
|
||||
PROXY_TYPE_HTTP = 0,
|
||||
PROXY_TYPE_COUNT,
|
||||
};
|
||||
|
||||
enum nsock_proxy_state {
|
||||
@@ -81,15 +94,20 @@ struct proxy_node {
|
||||
struct sockaddr_storage ss;
|
||||
size_t sslen;
|
||||
unsigned short port;
|
||||
};
|
||||
|
||||
/* Use a 'next' pointer instead of a gh_list. This is lighter and doesn't
|
||||
* affect performances since the proxy list isn't dynamic. */
|
||||
struct proxy_node *next;
|
||||
struct proxy_chain {
|
||||
char *specstr;
|
||||
gh_list nodes;
|
||||
};
|
||||
|
||||
struct proxy_chain_context {
|
||||
struct proxy_chain *px_chain;
|
||||
|
||||
/* Those fields are used to store current state during the tunnel
|
||||
* establishment phase. */
|
||||
gh_list_elem *px_current;
|
||||
enum nsock_proxy_state px_state;
|
||||
struct proxy_node *px_current;
|
||||
|
||||
struct sockaddr_storage target_ss;
|
||||
size_t target_sslen;
|
||||
@@ -97,6 +115,13 @@ struct proxy_chain_context {
|
||||
nsock_ev_handler target_handler;
|
||||
};
|
||||
|
||||
struct proxy_actions {
|
||||
nsock_event_id (*connect_tcp)(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_handler handler, int mstimeout,
|
||||
void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port);
|
||||
char *(*data_encode)(const char *src, size_t len, size_t *dlen);
|
||||
char *(*data_decode)(const char *src, size_t len, size_t *dlen);
|
||||
};
|
||||
|
||||
|
||||
/* ------------------- PROTOTYPES ------------------- */
|
||||
void nsock_proxy_ev_handler(nsock_pool nspool, nsock_event nsevent, void *udata);
|
||||
|
||||
Reference in New Issue
Block a user