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)
|
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;
|
||||||
|
22
parser.c
22
parser.c
@ -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)
|
||||||
|
8
parser.h
8
parser.h
@ -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 {
|
||||||
|
37
redsocks.c
37
redsocks.c
@ -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 = §ion->entries[0]; entry->key; entry++)
|
for (parser_entry *entry = §ion->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 =
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user