0
0
mirror of https://github.com/darkk/redsocks.git synced 2025-08-25 19:25:30 +00:00

Add disclose_src option to tell client src IP to http-connect proxy

This commit is contained in:
Leonid Evdokimov 2016-04-05 02:42:34 +03:00
parent 003765ba98
commit 4521797847
6 changed files with 110 additions and 33 deletions

View File

@ -182,6 +182,7 @@ static void httpc_read_cb(struct bufferevent *buffev, void *_arg)
static struct evbuffer *httpc_mkconnect(redsocks_client *client) static struct evbuffer *httpc_mkconnect(redsocks_client *client)
{ {
struct evbuffer *buff = NULL, *retval = NULL; struct evbuffer *buff = NULL, *retval = NULL;
char *auth_string = NULL;
int len; int len;
buff = evbuffer_new(); buff = evbuffer_new();
@ -194,7 +195,6 @@ static struct evbuffer *httpc_mkconnect(redsocks_client *client)
++auth->last_auth_count; ++auth->last_auth_count;
const char *auth_scheme = NULL; const char *auth_scheme = NULL;
char *auth_string = NULL;
if (auth->last_auth_query != NULL) { if (auth->last_auth_query != NULL) {
/* find previous auth challange */ /* find previous auth challange */
@ -218,34 +218,60 @@ static struct evbuffer *httpc_mkconnect(redsocks_client *client)
} }
} }
if (auth_string == NULL) { // TODO: do accurate evbuffer_expand() while cleaning up http-auth
len = evbuffer_add_printf(buff, len = evbuffer_add_printf(buff, "CONNECT %s:%u HTTP/1.0\r\n",
"CONNECT %s:%u HTTP/1.0\r\n\r\n", inet_ntoa(client->destaddr.sin_addr),
inet_ntoa(client->destaddr.sin_addr), ntohs(client->destaddr.sin_port));
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
);
}
free(auth_string);
if (len < 0) { if (len < 0) {
redsocks_log_errno(client, LOG_ERR, "evbufer_add_printf"); redsocks_log_errno(client, LOG_ERR, "evbufer_add_printf");
goto fail; goto fail;
} }
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");
goto fail;
}
retval = buff; retval = buff;
buff = NULL; buff = NULL;
fail: fail:
if (auth_string)
free(auth_string);
if (buff) if (buff)
evbuffer_free(buff); evbuffer_free(buff);
return retval; return retval;

View File

@ -270,6 +270,27 @@ static int vp_pbool(parser_context *context, void *addr, const char *token)
return -1; 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) static int vp_pchar(parser_context *context, void *addr, const char *token)
{ {
char *p = strdup(token); char *p = strdup(token);
@ -399,6 +420,7 @@ static value_parser value_parser_by_type[] =
[pt_uint16] = vp_uint16, [pt_uint16] = vp_uint16,
[pt_in_addr] = vp_in_addr, [pt_in_addr] = vp_in_addr,
[pt_in_addr2] = vp_in_addr2, [pt_in_addr2] = vp_in_addr2,
[pt_disclose_src] = vp_disclose_src,
}; };
int parser_run(parser_context *context) int parser_run(parser_context *context)

View File

@ -4,12 +4,20 @@
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
enum disclose_src_e {
DISCLOSE_NONE,
DISCLOSE_X_FORWARDED_FOR,
DISCLOSE_FORWARDED_IP,
DISCLOSE_FORWARDED_IPPORT,
};
typedef enum { typedef enum {
pt_bool, // "bool" from stdbool.h, not "_Bool" or anything else pt_bool, // "bool" from stdbool.h, not "_Bool" or anything else
pt_pchar, pt_pchar,
pt_uint16, pt_uint16,
pt_in_addr, pt_in_addr,
pt_in_addr2, // inaddr[0] = net, inaddr[1] = netmask pt_in_addr2, // inaddr[0] = net, inaddr[1] = netmask
pt_disclose_src,
} parser_type; } parser_type;
typedef struct parser_entry_t { typedef struct parser_entry_t {

View File

@ -77,6 +77,7 @@ static parser_entry redsocks_entries[] =
{ .key = "password", .type = pt_pchar }, { .key = "password", .type = pt_pchar },
{ .key = "listenq", .type = pt_uint16 }, { .key = "listenq", .type = pt_uint16 },
{ .key = "splice", .type = pt_bool }, { .key = "splice", .type = pt_bool },
{ .key = "disclose_src", .type = pt_disclose_src },
{ .key = "min_accept_backoff", .type = pt_uint16 }, { .key = "min_accept_backoff", .type = pt_uint16 },
{ .key = "max_accept_backoff", .type = pt_uint16 }, { .key = "max_accept_backoff", .type = pt_uint16 },
{ } { }
@ -158,6 +159,7 @@ static int redsocks_onenter(parser_section *section)
instance->config.min_backoff_ms = 100; instance->config.min_backoff_ms = 100;
instance->config.max_backoff_ms = 60000; instance->config.max_backoff_ms = 60000;
instance->config.use_splice = is_splice_good(); instance->config.use_splice = is_splice_good();
instance->config.disclose_src = DISCLOSE_NONE;
for (parser_entry *entry = &section->entries[0]; entry->key; entry++) for (parser_entry *entry = &section->entries[0]; entry->key; entry++)
entry->addr = entry->addr =
@ -170,6 +172,7 @@ static int redsocks_onenter(parser_section *section)
(strcmp(entry->key, "password") == 0) ? (void*)&instance->config.password : (strcmp(entry->key, "password") == 0) ? (void*)&instance->config.password :
(strcmp(entry->key, "listenq") == 0) ? (void*)&instance->config.listenq : (strcmp(entry->key, "listenq") == 0) ? (void*)&instance->config.listenq :
(strcmp(entry->key, "splice") == 0) ? (void*)&instance->config.use_splice : (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, "min_accept_backoff") == 0) ? (void*)&instance->config.min_backoff_ms :
(strcmp(entry->key, "max_accept_backoff") == 0) ? (void*)&instance->config.max_backoff_ms : (strcmp(entry->key, "max_accept_backoff") == 0) ? (void*)&instance->config.max_backoff_ms :
NULL; NULL;
@ -183,7 +186,6 @@ static int redsocks_onexit(parser_section *section)
* file is not correct, so correct on-the-fly config reloading is * file is not correct, so correct on-the-fly config reloading is
* currently impossible. * currently impossible.
*/ */
const char *err = NULL;
redsocks_instance *instance = section->data; redsocks_instance *instance = section->data;
section->data = NULL; section->data = NULL;
@ -202,29 +204,38 @@ static int redsocks_onexit(parser_section *section)
break; break;
} }
} }
if (!instance->relay_ss) if (!instance->relay_ss) {
err = "invalid `type` for redsocks"; parser_error(section->context, "invalid `type` <%s> for redsocks", instance->config.type);
return -1;
}
} }
else { else {
err = "no `type` for redsocks"; parser_error(section->context, "no `type` for redsocks");
return -1;
} }
if (!err && !instance->config.min_backoff_ms) { if (instance->config.disclose_src != DISCLOSE_NONE && instance->relay_ss != &http_connect_subsys) {
err = "`min_accept_backoff` must be positive, 0 ms is too low"; parser_error(section->context, "only `http-connect` supports `disclose_src` at the moment");
return -1;
} }
if (!err && !instance->config.max_backoff_ms) { if (!instance->config.min_backoff_ms) {
err = "`max_accept_backoff` must be positive, 0 ms is too low"; 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)) { if (!instance->config.max_backoff_ms) {
err = "`min_accept_backoff` must be less than `max_accept_backoff`"; parser_error(section->context, "`max_accept_backoff` must be positive, 0 ms is too low");
return -1;
} }
if (err) if (instance->config.min_backoff_ms >= instance->config.max_backoff_ms) {
parser_error(section->context, "%s", err); 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 = static parser_section redsocks_conf_section =

View File

@ -81,6 +81,14 @@ redsocks {
// login = "foobar"; // login = "foobar";
// password = "baz"; // 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 { redudp {

View File

@ -6,6 +6,7 @@
#include <assert.h> #include <assert.h>
#include <event.h> #include <event.h>
#include "list.h" #include "list.h"
#include "parser.h"
struct redsocks_client_t; struct redsocks_client_t;
@ -35,6 +36,7 @@ typedef struct redsocks_config_t {
uint16_t max_backoff_ms; // backoff capped by 65 seconds is enough :) uint16_t max_backoff_ms; // backoff capped by 65 seconds is enough :)
uint16_t listenq; uint16_t listenq;
bool use_splice; bool use_splice;
enum disclose_src_e disclose_src;
} redsocks_config; } redsocks_config;
struct tracked_event { struct tracked_event {