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:
parent
003765ba98
commit
4521797847
@ -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();
|
||||
@ -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 */
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
free(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;
|
||||
}
|
||||
|
||||
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;
|
||||
buff = NULL;
|
||||
|
||||
fail:
|
||||
if (auth_string)
|
||||
free(auth_string);
|
||||
if (buff)
|
||||
evbuffer_free(buff);
|
||||
return retval;
|
||||
|
22
parser.c
22
parser.c
@ -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);
|
||||
@ -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)
|
||||
|
8
parser.h
8
parser.h
@ -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 {
|
||||
|
37
redsocks.c
37
redsocks.c
@ -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 },
|
||||
{ }
|
||||
@ -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 = §ion->entries[0]; entry->key; entry++)
|
||||
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, "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;
|
||||
@ -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;
|
||||
@ -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 =
|
||||
|
@ -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 {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <assert.h>
|
||||
#include <event.h>
|
||||
#include "list.h"
|
||||
#include "parser.h"
|
||||
|
||||
|
||||
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 listenq;
|
||||
bool use_splice;
|
||||
enum disclose_src_e disclose_src;
|
||||
} redsocks_config;
|
||||
|
||||
struct tracked_event {
|
||||
|
Loading…
Reference in New Issue
Block a user