Skip to content

Commit

Permalink
Implement redsocks_conn_max option, simplify accept-backoff
Browse files Browse the repository at this point in the history
Sophisticated accept-backoff is not required, it's ONLY purpose is to
protect against busy-loop when `redsocks_conn_max` does not match
RLIMIT_NOFILE.
  • Loading branch information
darkk committed Apr 14, 2016
1 parent 83702c9 commit a1be080
Show file tree
Hide file tree
Showing 16 changed files with 515 additions and 179 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,8 @@ tests/__build-tstamp__: $(OUT) tests/[a-z]* tests/[a-z]*/*
cd tests && ./build
touch $@

test: tests/__build-tstamp__
tests/prlimit-nofile: tests/prlimit-nofile.c
$(CC) $(CFLAGS) -o $@ $^

test: tests/__build-tstamp__ tests/prlimit-nofile
cd tests && env $(TEST_ENV) ./run
77 changes: 61 additions & 16 deletions base.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
Expand Down Expand Up @@ -67,13 +68,13 @@ typedef struct base_instance_t {
uint16_t tcp_keepalive_probes;
uint16_t tcp_keepalive_intvl;
#endif
uint32_t rlimit_nofile;
uint32_t redsocks_conn_max;
uint32_t connpres_idle_timeout;
uint32_t max_accept_backoff_ms;
} base_instance;

static base_instance instance = {
.configured = 0,
.log_debug = false,
.log_info = false,
};
static base_instance instance;

#if defined __FreeBSD__ || defined USE_PF
static int redir_open_private(const char *fname, int flags)
Expand Down Expand Up @@ -266,6 +267,21 @@ int apply_tcp_keepalive(int fd)
return 0;
}

uint32_t max_accept_backoff_ms()
{
return instance.max_accept_backoff_ms;
}

uint32_t redsocks_conn_max()
{
return instance.redsocks_conn_max;
}

uint32_t connpres_idle_timeout()
{
return instance.connpres_idle_timeout;
}

static redirector_subsys redirector_subsystems[] =
{
#ifdef __FreeBSD__
Expand Down Expand Up @@ -298,6 +314,10 @@ static parser_entry base_entries[] =
{ .key = "tcp_keepalive_probes", .type = pt_uint16, .addr = &instance.tcp_keepalive_probes },
{ .key = "tcp_keepalive_intvl", .type = pt_uint16, .addr = &instance.tcp_keepalive_intvl },
#endif
{ .key = "rlimit_nofile", .type = pt_uint32, .addr = &instance.rlimit_nofile },
{ .key = "redsocks_conn_max", .type = pt_uint32, .addr = &instance.redsocks_conn_max },
{ .key = "connpres_idle_timeout", .type = pt_uint32, .addr = &instance.connpres_idle_timeout },
{ .key = "max_accept_backoff", .type = pt_uint32, .addr = &instance.max_accept_backoff_ms },
{ }
};

Expand All @@ -308,12 +328,18 @@ static int base_onenter(parser_section *section)
return -1;
}
memset(&instance, 0, sizeof(instance));
instance.configured = 1;
instance.max_accept_backoff_ms = 60000;
instance.connpres_idle_timeout = 7440;
return 0;
}

static int base_onexit(parser_section *section)
{
const char *err = NULL;
if (!instance.max_accept_backoff_ms) {
parser_error(section->context, "`max_accept_backoff` must be positive, 0 ms is too low");
return -1;
}

if (instance.redirector_name) {
redirector_subsys *ss;
Expand All @@ -324,20 +350,17 @@ static int base_onexit(parser_section *section)
break;
}
}
if (!instance.redirector)
err = "invalid `redirector` set";
if (!instance.redirector) {
parser_error(section->context, "invalid `redirector` set <%s>", instance.redirector_name);
return -1;
}
}
else {
err = "no `redirector` set";
parser_error(section->context, "no `redirector` set");
return -1;
}

if (err)
parser_error(section->context, "%s", err);

if (!err)
instance.configured = 1;

return err ? -1 : 0;
return 0;
}

static parser_section base_conf_section =
Expand Down Expand Up @@ -393,6 +416,28 @@ static int base_init()
goto fail;
}

if (instance.rlimit_nofile) {
struct rlimit rlmt;
rlmt.rlim_cur = instance.rlimit_nofile;
rlmt.rlim_max = instance.rlimit_nofile;
if (setrlimit(RLIMIT_NOFILE, &rlmt) != 0) {
log_errno(LOG_ERR, "setrlimit(RLIMIT_NOFILE, %u)", instance.rlimit_nofile);
goto fail;
}
} else {
struct rlimit rlmt;
if (getrlimit(RLIMIT_NOFILE, &rlmt) != 0) {
log_errno(LOG_ERR, "getrlimit(RLIMIT_NOFILE)");
goto fail;
}
instance.rlimit_nofile = rlmt.rlim_cur;
}

if (!instance.redsocks_conn_max) {
instance.redsocks_conn_max = (instance.rlimit_nofile - instance.rlimit_nofile / 4)
/ (redsocks_has_splice_instance() ? 6 : 2);
}

if (instance.daemon) {
devnull = open("/dev/null", O_RDWR);
if (devnull == -1) {
Expand Down
4 changes: 4 additions & 0 deletions base.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
int getdestaddr(int fd, const struct sockaddr_in *client, const struct sockaddr_in *bindaddr, struct sockaddr_in *destaddr);
int apply_tcp_keepalive(int fd);

uint32_t redsocks_conn_max();
uint32_t connpres_idle_timeout();
uint32_t max_accept_backoff_ms();

/* vim:set tabstop=4 softtabstop=4 shiftwidth=4: */
/* vim:set foldmethod=marker foldlevel=32 foldmarker={,}: */
#endif /* BASE_H_SUN_JUN__3_20_15_57_2007 */
3 changes: 2 additions & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "utils.h"
#include "version.h"
#include "config.h"
#include "base.h"

extern app_subsys redsocks_subsys;
extern app_subsys debug_subsys;
Expand Down Expand Up @@ -161,7 +162,7 @@ int main(int argc, char **argv)
log_error(LOG_WARNING, "libevent version mismatch! headers %8x, runtime %8x\n", LIBEVENT_VERSION_NUMBER, event_get_version_number());
}

log_error(LOG_NOTICE, "redsocks started");
log_error(LOG_NOTICE, "redsocks started, conn_max=%u", redsocks_conn_max());

event_dispatch();

Expand Down
31 changes: 29 additions & 2 deletions parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,18 @@ static int vp_uint16(parser_context *context, void *addr, const char *token)
return 0;
}

static int vp_uint32(parser_context *context, void *addr, const char *token)
{
char *end;
uint32_t uli = strtoul(token, &end, 0);
if (*end != '\0') {
parser_error(context, "integer is not parsed");
return -1;
}
*(uint32_t*)addr = uli;
return 0;
}

static int vp_in_addr(parser_context *context, void *addr, const char *token)
{
struct in_addr ia;
Expand Down Expand Up @@ -430,15 +442,30 @@ static int vp_in_addr2(parser_context *context, void *addr, const char *token)
return retval;
}

static int vp_obsolete(parser_context *context, void *addr, const char *token)
{
parser_error(context, "obsolete key, delete it");
return -1;
}

static int vp_redsocks_max_accept_backoff(parser_context *context, void *addr, const char *token)
{
parser_error(context, "max_accept_backoff is not per-port setting anymore, move it from `redsocks` to `base`");
return -1;
}

static value_parser value_parser_by_type[] =
{
[pt_bool] = vp_pbool,
[pt_pchar] = vp_pchar,
[pt_uint16] = vp_uint16,
[pt_uint32] = vp_uint32,
[pt_in_addr] = vp_in_addr,
[pt_in_addr2] = vp_in_addr2,
[pt_disclose_src] = vp_disclose_src,
[pt_on_proxy_fail] = vp_on_proxy_fail,
[pt_obsolete] = vp_obsolete,
[pt_redsocks_max_accept_backoff] = vp_redsocks_max_accept_backoff,
};

int parser_run(parser_context *context)
Expand Down Expand Up @@ -571,7 +598,7 @@ int parser_run(parser_context *context)
parser_error(context, "assignment termination outside of any section");
}
else if (key_token && !value_token) {
parser_error(context, "assignment has only key but no value");
parser_error(context, "assignment has only key <%s> but no value", key_token);
}
else if (key_token && value_token) {
parser_entry *e;
Expand All @@ -580,7 +607,7 @@ int parser_run(parser_context *context)
break;
if (e->key) {
if ( (value_parser_by_type[e->type])(context, e->addr, value_token) == -1 )
parser_error(context, "value can't be parsed");
parser_error(context, "value <%s> can't be parsed for key <%s>", value_token, key_token);
}
else {
parser_error(context, "assignment with unknown key <%s>", key_token);
Expand Down
3 changes: 3 additions & 0 deletions parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ typedef enum {
pt_bool, // "bool" from stdbool.h, not "_Bool" or anything else
pt_pchar,
pt_uint16,
pt_uint32,
pt_in_addr,
pt_in_addr2, // inaddr[0] = net, inaddr[1] = netmask
pt_disclose_src,
pt_on_proxy_fail,
pt_obsolete,
pt_redsocks_max_accept_backoff,
} parser_type;

typedef struct parser_entry_t {
Expand Down
Loading

0 comments on commit a1be080

Please sign in to comment.