1
0
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:
henri
2013-04-22 19:29:18 +00:00
parent a6bcd9cb7e
commit 28604b63e3
5 changed files with 158 additions and 57 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 *)&current->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;
}

View File

@@ -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);