Skip to content

Commit

Permalink
Add disclose_src option to tell client src IP to http-connect proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
darkk committed Apr 4, 2016
1 parent 003765b commit 4521797
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 31 deletions.
62 changes: 44 additions & 18 deletions http-connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ static void httpc_read_cb(struct bufferevent *buffev, void *_arg)
static struct evbuffer *httpc_mkconnect(redsocks_client *client)
{
struct evbuffer *buff = NULL, *retval = NULL;
char *auth_string = NULL;
int len;

buff = evbuffer_new();
Expand All @@ -194,7 +195,6 @@ static struct evbuffer *httpc_mkconnect(redsocks_client *client)
++auth->last_auth_count;

const char *auth_scheme = NULL;
char *auth_string = NULL;

if (auth->last_auth_query != NULL) {
/* find previous auth challange */
Expand All @@ -218,34 +218,60 @@ static struct evbuffer *httpc_mkconnect(redsocks_client *client)
}
}

if (auth_string == NULL) {
len = evbuffer_add_printf(buff,
"CONNECT %s:%u HTTP/1.0\r\n\r\n",
inet_ntoa(client->destaddr.sin_addr),
ntohs(client->destaddr.sin_port)
);
} else {
len = evbuffer_add_printf(buff,
"CONNECT %s:%u HTTP/1.0\r\n%s %s %s\r\n\r\n",
inet_ntoa(client->destaddr.sin_addr),
ntohs(client->destaddr.sin_port),
auth_response_header,
auth_scheme,
auth_string
);
// TODO: do accurate evbuffer_expand() while cleaning up http-auth
len = evbuffer_add_printf(buff, "CONNECT %s:%u HTTP/1.0\r\n",
inet_ntoa(client->destaddr.sin_addr),
ntohs(client->destaddr.sin_port));
if (len < 0) {
redsocks_log_errno(client, LOG_ERR, "evbufer_add_printf");
goto fail;
}

free(auth_string);
if (auth_string) {
len = evbuffer_add_printf(buff, "%s %s %s\r\n",
auth_response_header, auth_scheme, auth_string);
if (len < 0) {
redsocks_log_errno(client, LOG_ERR, "evbufer_add_printf");
goto fail;
}
free(auth_string);
auth_string = NULL;
}

const enum disclose_src_e disclose_src = client->instance->config.disclose_src;
if (disclose_src != DISCLOSE_NONE) {
char clientip[INET_ADDRSTRLEN];
const char *ip = inet_ntop(client->clientaddr.sin_family, &client->clientaddr.sin_addr, clientip, sizeof(clientip));
if (!ip) {
redsocks_log_errno(client, LOG_ERR, "inet_ntop");
goto fail;
}
if (disclose_src == DISCLOSE_X_FORWARDED_FOR) {
len = evbuffer_add_printf(buff, "X-Forwarded-For: %s\r\n", ip);
} else if (disclose_src == DISCLOSE_FORWARDED_IP) {
len = evbuffer_add_printf(buff, "Forwarded: for=%s\r\n", ip);
} else if (disclose_src == DISCLOSE_FORWARDED_IPPORT) {
len = evbuffer_add_printf(buff, "Forwarded: for=\"%s:%d\"\r\n", ip,
ntohs(client->clientaddr.sin_port));
}
if (len < 0) {
redsocks_log_errno(client, LOG_ERR, "evbufer_add_printf");
goto fail;
}
}

len = evbuffer_add(buff, "\r\n", 2);
if (len < 0) {
redsocks_log_errno(client, LOG_ERR, "evbufer_add_printf");
redsocks_log_errno(client, LOG_ERR, "evbufer_add");
goto fail;
}

retval = buff;
buff = NULL;

fail:
if (auth_string)
free(auth_string);
if (buff)
evbuffer_free(buff);
return retval;
Expand Down
22 changes: 22 additions & 0 deletions parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,27 @@ static int vp_pbool(parser_context *context, void *addr, const char *token)
return -1;
}

static int vp_disclose_src(parser_context *context, void *addr, const char *token)
{
enum disclose_src_e *dst = addr;
struct { char *name; enum disclose_src_e value; } opt[] = {
{ "off", DISCLOSE_NONE },
{ "no", DISCLOSE_NONE },
{ "false", DISCLOSE_NONE },
{ "X-Forwarded-For", DISCLOSE_X_FORWARDED_FOR },
{ "Forwarded_ip", DISCLOSE_FORWARDED_IP },
{ "Forwarded_ipport", DISCLOSE_FORWARDED_IPPORT },
};
for (int i = 0; i < SIZEOF_ARRAY(opt); ++i) {
if (strcmp(token, opt[i].name) == 0) {
*dst = opt[i].value;
return 0;
}
}
parser_error(context, "disclose_src <%s> is not parsed", token);
return -1;
}

static int vp_pchar(parser_context *context, void *addr, const char *token)
{
char *p = strdup(token);
Expand Down Expand Up @@ -399,6 +420,7 @@ static value_parser value_parser_by_type[] =
[pt_uint16] = vp_uint16,
[pt_in_addr] = vp_in_addr,
[pt_in_addr2] = vp_in_addr2,
[pt_disclose_src] = vp_disclose_src,
};

int parser_run(parser_context *context)
Expand Down
8 changes: 8 additions & 0 deletions parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@
#include <stdio.h>
#include <stdbool.h>

enum disclose_src_e {
DISCLOSE_NONE,
DISCLOSE_X_FORWARDED_FOR,
DISCLOSE_FORWARDED_IP,
DISCLOSE_FORWARDED_IPPORT,
};

typedef enum {
pt_bool, // "bool" from stdbool.h, not "_Bool" or anything else
pt_pchar,
pt_uint16,
pt_in_addr,
pt_in_addr2, // inaddr[0] = net, inaddr[1] = netmask
pt_disclose_src,
} parser_type;

typedef struct parser_entry_t {
Expand Down
37 changes: 24 additions & 13 deletions redsocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ static parser_entry redsocks_entries[] =
{ .key = "password", .type = pt_pchar },
{ .key = "listenq", .type = pt_uint16 },
{ .key = "splice", .type = pt_bool },
{ .key = "disclose_src", .type = pt_disclose_src },
{ .key = "min_accept_backoff", .type = pt_uint16 },
{ .key = "max_accept_backoff", .type = pt_uint16 },
{ }
Expand Down Expand Up @@ -158,6 +159,7 @@ static int redsocks_onenter(parser_section *section)
instance->config.min_backoff_ms = 100;
instance->config.max_backoff_ms = 60000;
instance->config.use_splice = is_splice_good();
instance->config.disclose_src = DISCLOSE_NONE;

for (parser_entry *entry = &section->entries[0]; entry->key; entry++)
entry->addr =
Expand All @@ -170,6 +172,7 @@ static int redsocks_onenter(parser_section *section)
(strcmp(entry->key, "password") == 0) ? (void*)&instance->config.password :
(strcmp(entry->key, "listenq") == 0) ? (void*)&instance->config.listenq :
(strcmp(entry->key, "splice") == 0) ? (void*)&instance->config.use_splice :
(strcmp(entry->key, "disclose_src") == 0) ? (void*)&instance->config.disclose_src :
(strcmp(entry->key, "min_accept_backoff") == 0) ? (void*)&instance->config.min_backoff_ms :
(strcmp(entry->key, "max_accept_backoff") == 0) ? (void*)&instance->config.max_backoff_ms :
NULL;
Expand All @@ -183,7 +186,6 @@ static int redsocks_onexit(parser_section *section)
* file is not correct, so correct on-the-fly config reloading is
* currently impossible.
*/
const char *err = NULL;
redsocks_instance *instance = section->data;

section->data = NULL;
Expand All @@ -202,29 +204,38 @@ static int redsocks_onexit(parser_section *section)
break;
}
}
if (!instance->relay_ss)
err = "invalid `type` for redsocks";
if (!instance->relay_ss) {
parser_error(section->context, "invalid `type` <%s> for redsocks", instance->config.type);
return -1;
}
}
else {
err = "no `type` for redsocks";
parser_error(section->context, "no `type` for redsocks");
return -1;
}

if (!err && !instance->config.min_backoff_ms) {
err = "`min_accept_backoff` must be positive, 0 ms is too low";
if (instance->config.disclose_src != DISCLOSE_NONE && instance->relay_ss != &http_connect_subsys) {
parser_error(section->context, "only `http-connect` supports `disclose_src` at the moment");
return -1;
}

if (!err && !instance->config.max_backoff_ms) {
err = "`max_accept_backoff` must be positive, 0 ms is too low";
if (!instance->config.min_backoff_ms) {
parser_error(section->context, "`min_accept_backoff` must be positive, 0 ms is too low");
return -1;
}

if (!err && !(instance->config.min_backoff_ms < instance->config.max_backoff_ms)) {
err = "`min_accept_backoff` must be less than `max_accept_backoff`";
if (!instance->config.max_backoff_ms) {
parser_error(section->context, "`max_accept_backoff` must be positive, 0 ms is too low");
return -1;
}

if (err)
parser_error(section->context, "%s", err);
if (instance->config.min_backoff_ms >= instance->config.max_backoff_ms) {
parser_error(section->context, "`min_accept_backoff` (%d) must be less than `max_accept_backoff` (%d)",
instance->config.min_backoff_ms, instance->config.max_backoff_ms);
return -1;
}

return err ? -1 : 0;
return 0;
}

static parser_section redsocks_conf_section =
Expand Down
8 changes: 8 additions & 0 deletions redsocks.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ redsocks {

// login = "foobar";
// password = "baz";

// known ways to disclose client IP to the proxy:
// false -- disclose nothing
// http-connect supports:
// X-Forwarded-For -- X-Forwarded-For: IP
// Forwarded_ip -- Forwarded: for=IP # see RFC7239
// Forwarded_ipport -- Forwarded: for="IP:port" # see RFC7239
// disclose_src = false;
}

redudp {
Expand Down
2 changes: 2 additions & 0 deletions redsocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <assert.h>
#include <event.h>
#include "list.h"
#include "parser.h"


struct redsocks_client_t;
Expand Down Expand Up @@ -35,6 +36,7 @@ typedef struct redsocks_config_t {
uint16_t max_backoff_ms; // backoff capped by 65 seconds is enough :)
uint16_t listenq;
bool use_splice;
enum disclose_src_e disclose_src;
} redsocks_config;

struct tracked_event {
Expand Down

0 comments on commit 4521797

Please sign in to comment.