0
0
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:
Leonid Evdokimov 2008-08-18 17:46:27 +07:00
parent 40fda9b6b7
commit 7c714b750f
3 changed files with 152 additions and 63 deletions

View File

@ -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;
}; };

View File

@ -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 = &section->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 = &section->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;
} }

View File

@ -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;