mirror of
https://github.com/nmap/nmap.git
synced 2025-12-21 06:59:01 +00:00
Implemented a more robust URI parser. Code largely adapted from ncat/http.c.
This commit is contained in:
@@ -77,7 +77,6 @@ struct proxy_parser {
|
|||||||
char *tokens;
|
char *tokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct proxy_parser *proxy_parser_new(const char *proxychainstr);
|
static struct proxy_parser *proxy_parser_new(const char *proxychainstr);
|
||||||
static void proxy_parser_next(struct proxy_parser *parser);
|
static void proxy_parser_next(struct proxy_parser *parser);
|
||||||
static void proxy_parser_delete(struct proxy_parser *parser);
|
static void proxy_parser_delete(struct proxy_parser *parser);
|
||||||
@@ -197,14 +196,199 @@ void proxy_chain_context_delete(struct proxy_chain_context *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX
|
static char *mkstr(const char *start, const char *end) {
|
||||||
* This function is just an ugly PoC.
|
char *s;
|
||||||
*
|
|
||||||
* A clean version should handle:
|
assert(end >= start);
|
||||||
* - both v4 and v6 adresses
|
s = (char *) safe_malloc(end - start + 1);
|
||||||
* - hostnames (how do we want to resolve them though??)
|
memcpy(s, start, end - start);
|
||||||
* - user:pass@ prefix before host specification
|
s[end - start] = '\0';
|
||||||
*/
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uri_free(struct uri *uri) {
|
||||||
|
if (uri->scheme)
|
||||||
|
free(uri->scheme);
|
||||||
|
if (uri->user)
|
||||||
|
free(uri->user);
|
||||||
|
if (uri->pass)
|
||||||
|
free(uri->pass);
|
||||||
|
if (uri->host)
|
||||||
|
free(uri->host);
|
||||||
|
if (uri->path)
|
||||||
|
free(uri->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lowercase(char *s) {
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
for (p = s; *p != '\0'; p++)
|
||||||
|
*p = tolower((int) (unsigned char) *p);
|
||||||
|
|
||||||
|
return p - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hex_digit_value(char digit) {
|
||||||
|
const char *DIGITS = "0123456789abcdef";
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if ((unsigned char) digit == '\0')
|
||||||
|
return -1;
|
||||||
|
p = strchr(DIGITS, tolower((int) (unsigned char) digit));
|
||||||
|
if (p == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return p - DIGITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int percent_decode(char *s) {
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
/* Skip to the first '%'. If there are no percent escapes, this lets us
|
||||||
|
* return without doing any copying. */
|
||||||
|
q = s;
|
||||||
|
while (*q != '\0' && *q != '%')
|
||||||
|
q++;
|
||||||
|
|
||||||
|
p = q;
|
||||||
|
while (*q != '\0') {
|
||||||
|
if (*q == '%') {
|
||||||
|
int c, d;
|
||||||
|
|
||||||
|
q++;
|
||||||
|
c = hex_digit_value(*q);
|
||||||
|
if (c == -1)
|
||||||
|
return -1;
|
||||||
|
q++;
|
||||||
|
d = hex_digit_value(*q);
|
||||||
|
if (d == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*p++ = c * 16 + d;
|
||||||
|
q++;
|
||||||
|
} else {
|
||||||
|
*p++ = *q++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
return p - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uri_parse_authority(const char *authority, struct uri *uri) {
|
||||||
|
const char *portsep;
|
||||||
|
const char *host_start, *host_end;
|
||||||
|
char *tail;
|
||||||
|
|
||||||
|
/* We do not support "user:pass@" userinfo. The proxy has no use for it. */
|
||||||
|
if (strchr(authority, '@') != NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Find the beginning and end of the host. */
|
||||||
|
host_start = authority;
|
||||||
|
|
||||||
|
if (*host_start == '[') {
|
||||||
|
/* IPv6 address in brackets. */
|
||||||
|
host_start++;
|
||||||
|
host_end = strchr(host_start, ']');
|
||||||
|
|
||||||
|
if (host_end == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
portsep = host_end + 1;
|
||||||
|
|
||||||
|
if (!(*portsep == ':' || *portsep == '\0'))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
portsep = strrchr(authority, ':');
|
||||||
|
|
||||||
|
if (portsep == NULL)
|
||||||
|
portsep = strchr(authority, '\0');
|
||||||
|
host_end = portsep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the port number. */
|
||||||
|
if (*portsep == ':' && *(portsep + 1) != '\0') {
|
||||||
|
long n;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
n = parse_long(portsep + 1, &tail);
|
||||||
|
if (errno != 0 || *tail != '\0' || tail == portsep + 1 || n < 1 || n > 65535)
|
||||||
|
return -1;
|
||||||
|
uri->port = n;
|
||||||
|
} else {
|
||||||
|
uri->port = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the host. */
|
||||||
|
uri->host = mkstr(host_start, host_end);
|
||||||
|
if (percent_decode(uri->host) < 0) {
|
||||||
|
free(uri->host);
|
||||||
|
uri->host = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_uri(const char *proxystr, struct uri *uri) {
|
||||||
|
const char *p, *q;
|
||||||
|
|
||||||
|
/* Scheme, section 3.1. */
|
||||||
|
p = proxystr;
|
||||||
|
if (!isalpha(*p))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
while (isalpha(*q) || isdigit(*q) || *q == '+' || *q == '-' || *q == '.')
|
||||||
|
q++;
|
||||||
|
|
||||||
|
if (*q != ':')
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
uri->scheme = mkstr(p, q);
|
||||||
|
|
||||||
|
/* "An implementation should accept uppercase letters as equivalent to
|
||||||
|
* lowercase in scheme names (e.g., allow "HTTP" as well as "http") for the
|
||||||
|
* sake of robustness..." */
|
||||||
|
lowercase(uri->scheme);
|
||||||
|
|
||||||
|
/* Authority, section 3.2. */
|
||||||
|
p = q + 1;
|
||||||
|
if (*p == '/' && *(p + 1) == '/') {
|
||||||
|
char *authority = NULL;
|
||||||
|
|
||||||
|
p += 2;
|
||||||
|
q = p;
|
||||||
|
while (!(*q == '/' || *q == '?' || *q == '#' || *q == '\0'))
|
||||||
|
q++;
|
||||||
|
;
|
||||||
|
authority = mkstr(p, q);
|
||||||
|
if (uri_parse_authority(authority, uri) < 0) {
|
||||||
|
free(authority);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
free(authority);
|
||||||
|
|
||||||
|
p = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Path, section 3.3. We include the query and fragment in the path. The
|
||||||
|
* path is also not percent-decoded because we just pass it on to the origin
|
||||||
|
* server. */
|
||||||
|
|
||||||
|
q = strchr(p, '\0');
|
||||||
|
uri->path = mkstr(p, q);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
uri_free(uri);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct proxy_node *proxy_node_new(char *proxystr) {
|
static struct proxy_node *proxy_node_new(char *proxystr) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -214,8 +398,16 @@ static struct proxy_node *proxy_node_new(char *proxystr) {
|
|||||||
pxop = ProxyBackends[i];
|
pxop = ProxyBackends[i];
|
||||||
if (strncasecmp(proxystr, pxop->prefix, strlen(pxop->prefix)) == 0) {
|
if (strncasecmp(proxystr, pxop->prefix, strlen(pxop->prefix)) == 0) {
|
||||||
struct proxy_node *proxy;
|
struct proxy_node *proxy;
|
||||||
|
struct uri uri;
|
||||||
|
|
||||||
|
memset(&uri, 0x00, sizeof(struct uri));
|
||||||
|
|
||||||
|
if (parse_uri(proxystr, &uri) < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pxop->node_new(&proxy, &uri);
|
||||||
|
uri_free(&uri);
|
||||||
|
|
||||||
pxop->node_new(&proxy, proxystr);
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,15 @@ enum nsock_proxy_state {
|
|||||||
|
|
||||||
/* ------------------- STRUCTURES ------------------- */
|
/* ------------------- STRUCTURES ------------------- */
|
||||||
|
|
||||||
|
struct uri {
|
||||||
|
char *scheme;
|
||||||
|
char *user;
|
||||||
|
char *pass;
|
||||||
|
char *host;
|
||||||
|
char *path;
|
||||||
|
int port;
|
||||||
|
};
|
||||||
|
|
||||||
/* Static information about a proxy node in the chain. This is generated by
|
/* Static information about a proxy node in the chain. This is generated by
|
||||||
* parsing the proxy specification string given by user. Those structures are
|
* parsing the proxy specification string given by user. Those structures are
|
||||||
* then read-only and stored in the nsock_pool. */
|
* then read-only and stored in the nsock_pool. */
|
||||||
@@ -128,7 +137,7 @@ struct proxy_op {
|
|||||||
const char *prefix;
|
const char *prefix;
|
||||||
enum nsock_proxy_type type;
|
enum nsock_proxy_type type;
|
||||||
|
|
||||||
int (*node_new)(struct proxy_node **node, char *proxystr);
|
int (*node_new)(struct proxy_node **node, const struct uri *uri);
|
||||||
void (*node_delete)(struct proxy_node *node);
|
void (*node_delete)(struct proxy_node *node);
|
||||||
|
|
||||||
int (*info_new)(void **info);
|
int (*info_new)(void **info);
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define DEFAULT_PROXY_PORT_HTTP "8080"
|
#define DEFAULT_PROXY_PORT_HTTP 8080
|
||||||
|
|
||||||
struct http_proxy_info {
|
struct http_proxy_info {
|
||||||
void *dummy;
|
void *dummy;
|
||||||
@@ -67,7 +67,7 @@ struct http_proxy_info {
|
|||||||
|
|
||||||
|
|
||||||
/* ---- PROTOTYPES ---- */
|
/* ---- PROTOTYPES ---- */
|
||||||
static int proxy_http_node_new(struct proxy_node **node, char *proxystr);
|
static int proxy_http_node_new(struct proxy_node **node, const struct uri *uri);
|
||||||
static void proxy_http_node_delete(struct proxy_node *node);
|
static void proxy_http_node_delete(struct proxy_node *node);
|
||||||
static int proxy_http_info_new(void **info);
|
static int proxy_http_info_new(void **info);
|
||||||
static void proxy_http_info_delete(void *info);
|
static void proxy_http_info_delete(void *info);
|
||||||
@@ -90,25 +90,23 @@ const struct proxy_op proxy_http_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int proxy_http_node_new(struct proxy_node **node, char *proxystr) {
|
int proxy_http_node_new(struct proxy_node **node, const struct uri *uri) {
|
||||||
struct sockaddr_in *sin;
|
struct sockaddr_in *sin;
|
||||||
struct proxy_node *proxy;
|
struct proxy_node *proxy;
|
||||||
char *strhost, *strport, *saveptr;
|
|
||||||
|
|
||||||
proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node));
|
proxy = (struct proxy_node *)safe_zalloc(sizeof(struct proxy_node));
|
||||||
proxy->ops = &proxy_http_ops;
|
proxy->ops = &proxy_http_ops;
|
||||||
|
|
||||||
strhost = strtok_r(proxystr + 7, ":", &saveptr);
|
|
||||||
strport = strtok_r(NULL, ":", &saveptr);
|
|
||||||
if (strport == NULL)
|
|
||||||
strport = DEFAULT_PROXY_PORT_HTTP;
|
|
||||||
|
|
||||||
sin = (struct sockaddr_in *)&proxy->ss;
|
sin = (struct sockaddr_in *)&proxy->ss;
|
||||||
sin->sin_family = AF_INET;
|
sin->sin_family = AF_INET;
|
||||||
inet_pton(AF_INET, strhost, &sin->sin_addr);
|
inet_pton(AF_INET, uri->host, &sin->sin_addr); /* TODO Resolve hostnames!! */
|
||||||
|
|
||||||
proxy->sslen = sizeof(struct sockaddr_in);
|
proxy->sslen = sizeof(struct sockaddr_in);
|
||||||
proxy->port = (unsigned short)atoi(strport);
|
|
||||||
|
if (uri->port == 0)
|
||||||
|
proxy->port = DEFAULT_PROXY_PORT_HTTP;
|
||||||
|
else
|
||||||
|
proxy->port = (unsigned short)uri->port;
|
||||||
|
|
||||||
*node = proxy;
|
*node = proxy;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user