mirror of
https://github.com/darkk/redsocks.git
synced 2025-08-26 19:55:30 +00:00
Added ability to create many redsocks config sections to have many redirectors.
This commit is contained in:
parent
40fda9b6b7
commit
7c714b750f
2
parser.h
2
parser.h
@ -33,7 +33,7 @@ struct parser_section_t {
|
|||||||
parser_section_onenter onenter; // is called on entry to section
|
parser_section_onenter onenter; // is called on entry to section
|
||||||
parser_section_onexit onexit; // is called on exit from section
|
parser_section_onexit onexit; // is called on exit from section
|
||||||
parser_entry *entries;
|
parser_entry *entries;
|
||||||
//void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
211
redsocks.c
211
redsocks.c
@ -55,51 +55,75 @@ static relay_subsys *relay_subsystems[] =
|
|||||||
&socks5_subsys,
|
&socks5_subsys,
|
||||||
};
|
};
|
||||||
|
|
||||||
static redsocks_instance instance =
|
list_head instances = LIST_HEAD_INIT(instances);
|
||||||
{ // almost NULL-initializer
|
|
||||||
.clients = LIST_HEAD_INIT(instance.clients)
|
|
||||||
};
|
|
||||||
|
|
||||||
static parser_entry redsocks_entries[] =
|
static parser_entry redsocks_entries[] =
|
||||||
{
|
{
|
||||||
{ .key = "local_ip", .type = pt_in_addr, .addr = &instance.config.bindaddr.sin_addr },
|
{ .key = "local_ip", .type = pt_in_addr },
|
||||||
{ .key = "local_port", .type = pt_uint16, .addr = &instance.config.bindaddr.sin_port },
|
{ .key = "local_port", .type = pt_uint16 },
|
||||||
{ .key = "ip", .type = pt_in_addr, .addr = &instance.config.relayaddr.sin_addr },
|
{ .key = "ip", .type = pt_in_addr },
|
||||||
{ .key = "port", .type = pt_uint16, .addr = &instance.config.relayaddr.sin_port },
|
{ .key = "port", .type = pt_uint16 },
|
||||||
{ .key = "type", .type = pt_pchar, .addr = &instance.config.type },
|
{ .key = "type", .type = pt_pchar },
|
||||||
{ .key = "login", .type = pt_pchar, .addr = &instance.config.login },
|
{ .key = "login", .type = pt_pchar },
|
||||||
{ .key = "password", .type = pt_pchar, .addr = &instance.config.password },
|
{ .key = "password", .type = pt_pchar },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int redsocks_onenter(parser_section *section)
|
static int redsocks_onenter(parser_section *section)
|
||||||
{
|
{
|
||||||
if (instance.config.type) {
|
redsocks_instance *instance = calloc(1, sizeof(*instance));
|
||||||
parser_error(section->context, "only one instance of redsocks is valid");
|
if (!instance) {
|
||||||
|
parser_error(section->context, "Not enough memory");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
instance.config.bindaddr.sin_family = AF_INET;
|
|
||||||
instance.config.bindaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
INIT_LIST_HEAD(&instance->list);
|
||||||
instance.config.relayaddr.sin_family = AF_INET;
|
INIT_LIST_HEAD(&instance->clients);
|
||||||
instance.config.relayaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
instance->config.bindaddr.sin_family = AF_INET;
|
||||||
|
instance->config.bindaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
instance->config.relayaddr.sin_family = AF_INET;
|
||||||
|
instance->config.relayaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
|
||||||
|
for (parser_entry *entry = §ion->entries[0]; entry->key; entry++)
|
||||||
|
entry->addr =
|
||||||
|
(strcmp(entry->key, "local_ip") == 0) ? &instance->config.bindaddr.sin_addr :
|
||||||
|
(strcmp(entry->key, "local_port") == 0) ? &instance->config.bindaddr.sin_port :
|
||||||
|
(strcmp(entry->key, "ip") == 0) ? &instance->config.relayaddr.sin_addr :
|
||||||
|
(strcmp(entry->key, "port") == 0) ? &instance->config.relayaddr.sin_port :
|
||||||
|
(strcmp(entry->key, "type") == 0) ? &instance->config.type :
|
||||||
|
(strcmp(entry->key, "login") == 0) ? &instance->config.login :
|
||||||
|
(strcmp(entry->key, "password") == 0) ? &instance->config.password :
|
||||||
|
NULL;
|
||||||
|
section->data = instance;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int redsocks_onexit(parser_section *section)
|
static int redsocks_onexit(parser_section *section)
|
||||||
{
|
{
|
||||||
|
/* FIXME: Rewrite in bullet-proof style. There are memory leaks if config
|
||||||
|
* file is not correct, so correct on-the-fly config reloading is
|
||||||
|
* currently impossible.
|
||||||
|
*/
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
instance.config.bindaddr.sin_port = htons(instance.config.bindaddr.sin_port);
|
redsocks_instance *instance = section->data;
|
||||||
instance.config.relayaddr.sin_port = htons(instance.config.relayaddr.sin_port);
|
|
||||||
|
|
||||||
if (instance.config.type) {
|
section->data = NULL;
|
||||||
|
for (parser_entry *entry = §ion->entries[0]; entry->key; entry++)
|
||||||
|
entry->addr = NULL;
|
||||||
|
|
||||||
|
instance->config.bindaddr.sin_port = htons(instance->config.bindaddr.sin_port);
|
||||||
|
instance->config.relayaddr.sin_port = htons(instance->config.relayaddr.sin_port);
|
||||||
|
|
||||||
|
if (instance->config.type) {
|
||||||
relay_subsys **ss;
|
relay_subsys **ss;
|
||||||
FOREACH(ss, relay_subsystems) {
|
FOREACH(ss, relay_subsystems) {
|
||||||
if (!strcmp((*ss)->name, instance.config.type)) {
|
if (!strcmp((*ss)->name, instance->config.type)) {
|
||||||
instance.relay_ss = *ss;
|
instance->relay_ss = *ss;
|
||||||
|
list_add(&instance->list, &instances);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!instance.relay_ss)
|
if (!instance->relay_ss)
|
||||||
err = "invalid `type` for redsocks";
|
err = "invalid `type` for redsocks";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -648,14 +672,12 @@ static const char *redsocks_event_str(unsigned short what)
|
|||||||
"???";
|
"???";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void redsocks_debug_dump(int sig, short what, void *_arg)
|
static void redsocks_debug_dump_instance(redsocks_instance *instance, time_t now)
|
||||||
{
|
{
|
||||||
redsocks_instance *self = _arg;
|
|
||||||
redsocks_client *client = NULL;
|
redsocks_client *client = NULL;
|
||||||
time_t now = redsocks_time(NULL);
|
|
||||||
|
|
||||||
log_error(LOG_DEBUG, "Dumping client list:");
|
log_error(LOG_DEBUG, "Dumping client list for instance %p:", instance);
|
||||||
list_for_each_entry(client, &self->clients, list) {
|
list_for_each_entry(client, &instance->clients, list) {
|
||||||
const char *s_client_evshut = redsocks_evshut_str(client->client_evshut);
|
const char *s_client_evshut = redsocks_evshut_str(client->client_evshut);
|
||||||
const char *s_relay_evshut = redsocks_evshut_str(client->relay_evshut);
|
const char *s_relay_evshut = redsocks_evshut_str(client->relay_evshut);
|
||||||
|
|
||||||
@ -672,19 +694,26 @@ static void redsocks_debug_dump(int sig, short what, void *_arg)
|
|||||||
log_error(LOG_DEBUG, "End of client list.");
|
log_error(LOG_DEBUG, "End of client list.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int redsocks_init()
|
static void redsocks_debug_dump(int sig, short what, void *_arg)
|
||||||
{
|
{
|
||||||
|
redsocks_instance *instance = NULL;
|
||||||
|
time_t now = redsocks_time(NULL);
|
||||||
|
|
||||||
|
list_for_each_entry(instance, &instances, list)
|
||||||
|
redsocks_debug_dump_instance(instance, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void redsocks_fini_instance(redsocks_instance *instance);
|
||||||
|
|
||||||
|
static int redsocks_init_instance(redsocks_instance *instance)
|
||||||
|
{
|
||||||
|
/* FIXME: redsocks_fini_instance is called in case of failure, this
|
||||||
|
* function will remove instance from instances list - result
|
||||||
|
* looks ugly.
|
||||||
|
*/
|
||||||
int error;
|
int error;
|
||||||
int on = 1;
|
int on = 1;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
struct sigaction sa = { }, sa_old = { };
|
|
||||||
|
|
||||||
sa.sa_handler = SIG_IGN;
|
|
||||||
sa.sa_flags = SA_RESTART;
|
|
||||||
if (sigaction(SIGPIPE, &sa, &sa_old) == -1) {
|
|
||||||
log_errno(LOG_ERR, "sigaction");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
@ -698,7 +727,7 @@ static int redsocks_init()
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = bind(fd, (struct sockaddr*)&instance.config.bindaddr, sizeof(instance.config.bindaddr));
|
error = bind(fd, (struct sockaddr*)&instance->config.bindaddr, sizeof(instance->config.bindaddr));
|
||||||
if (error) {
|
if (error) {
|
||||||
log_errno(LOG_ERR, "bind");
|
log_errno(LOG_ERR, "bind");
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -716,48 +745,108 @@ static int redsocks_init()
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
signal_set(&instance.debug_dumper, SIGUSR1, redsocks_debug_dump, &instance);
|
event_set(&instance->listener, fd, EV_READ | EV_PERSIST, redsocks_accept_client, instance);
|
||||||
error = signal_add(&instance.debug_dumper, NULL);
|
error = event_add(&instance->listener, NULL);
|
||||||
if (error) {
|
|
||||||
log_errno(LOG_ERR, "signal_add");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_set(&instance.listener, fd, EV_READ | EV_PERSIST, redsocks_accept_client, &instance);
|
|
||||||
error = event_add(&instance.listener, NULL);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
log_errno(LOG_ERR, "event_add");
|
log_errno(LOG_ERR, "event_add");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
fd = -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
|
||||||
if (signal_initialized(&instance.debug_dumper)) {
|
|
||||||
signal_del(&instance.debug_dumper);
|
|
||||||
memset(&instance.debug_dumper, 0, sizeof(instance.debug_dumper));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event_initialized(&instance.listener)) {
|
fail:
|
||||||
event_del(&instance.listener);
|
redsocks_fini_instance(instance);
|
||||||
memset(&instance.listener, 0, sizeof(instance.listener));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
close(fd);
|
if (close(fd) != 0)
|
||||||
|
log_errno(LOG_WARNING, "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drops instance completely, freeing its memory and removing from
|
||||||
|
* instances list.
|
||||||
|
*/
|
||||||
|
static void redsocks_fini_instance(redsocks_instance *instance) {
|
||||||
|
if (!list_empty(&instance->clients)) {
|
||||||
|
redsocks_client *tmp, *client = NULL;
|
||||||
|
|
||||||
|
log_error(LOG_WARNING, "There are connected clients during shutdown! Disconnecting them.");
|
||||||
|
list_for_each_entry_safe(client, tmp, &instance->clients, list) {
|
||||||
|
redsocks_drop_client(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_initialized(&instance->listener)) {
|
||||||
|
if (event_del(&instance->listener) != 0)
|
||||||
|
log_errno(LOG_WARNING, "event_del");
|
||||||
|
if (close(EVENT_FD(&instance->listener)) != 0)
|
||||||
|
log_errno(LOG_WARNING, "close");
|
||||||
|
memset(&instance->listener, 0, sizeof(instance->listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&instance->list);
|
||||||
|
|
||||||
|
free(instance->config.type);
|
||||||
|
free(instance->config.login);
|
||||||
|
free(instance->config.password);
|
||||||
|
|
||||||
|
memset(instance, 0, sizeof(*instance));
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int redsocks_fini();
|
||||||
|
|
||||||
|
static struct event debug_dumper;
|
||||||
|
|
||||||
|
static int redsocks_init() {
|
||||||
|
struct sigaction sa = { }, sa_old = { };
|
||||||
|
redsocks_instance *tmp, *instance = NULL;
|
||||||
|
|
||||||
|
sa.sa_handler = SIG_IGN;
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
if (sigaction(SIGPIPE, &sa, &sa_old) == -1) {
|
||||||
|
log_errno(LOG_ERR, "sigaction");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal_set(&debug_dumper, SIGUSR1, redsocks_debug_dump, NULL);
|
||||||
|
if (signal_add(&debug_dumper, NULL) != 0) {
|
||||||
|
log_errno(LOG_ERR, "signal_add");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry_safe(instance, tmp, &instances, list) {
|
||||||
|
if (redsocks_init_instance(instance) != 0)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
// that was the first resource allocation, it return's on failure, not goto-fail's
|
// that was the first resource allocation, it return's on failure, not goto-fail's
|
||||||
sigaction(SIGPIPE, &sa_old, NULL);
|
sigaction(SIGPIPE, &sa_old, NULL);
|
||||||
|
|
||||||
|
redsocks_fini();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int redsocks_fini()
|
static int redsocks_fini()
|
||||||
{
|
{
|
||||||
if (event_initialized(&instance.listener)) {
|
redsocks_instance *tmp, *instance = NULL;
|
||||||
event_del(&instance.listener);
|
|
||||||
close(EVENT_FD(&instance.listener));
|
list_for_each_entry_safe(instance, tmp, &instances, list)
|
||||||
memset(&instance.listener, 0, sizeof(instance.listener));
|
redsocks_fini_instance(instance);
|
||||||
|
|
||||||
|
if (signal_initialized(&debug_dumper)) {
|
||||||
|
if (signal_del(&debug_dumper) != 0)
|
||||||
|
log_errno(LOG_WARNING, "signal_del");
|
||||||
|
memset(&debug_dumper, 0, sizeof(debug_dumper));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ typedef struct redsocks_config_t {
|
|||||||
} redsocks_config;
|
} redsocks_config;
|
||||||
|
|
||||||
typedef struct redsocks_instance_t {
|
typedef struct redsocks_instance_t {
|
||||||
|
list_head list;
|
||||||
redsocks_config config;
|
redsocks_config config;
|
||||||
struct event listener;
|
struct event listener;
|
||||||
struct event debug_dumper;
|
|
||||||
list_head clients;
|
list_head clients;
|
||||||
relay_subsys *relay_ss;
|
relay_subsys *relay_ss;
|
||||||
} redsocks_instance;
|
} redsocks_instance;
|
||||||
|
Loading…
Reference in New Issue
Block a user