Some time ago (it has been years actually), Otto instrumented malloc(3)
to see where unwind is using a lot of memory when it's just sitting
there.
One of the remaining areas is struct config_file with its member
outgoing_avail_ports:
if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int))))
goto error_exit;
That's a 256k just wasted on OpenBSD.
Some time ago I added and upstreamed
--disable-explicit-port-randomisation to unbound(8) so that it doesn't
need to try to find a random outgoing port on its own. On OpenBSD we can
just trust the kernel to do this for us. Apparently I left that struct
behind which is part of the userland machinery in unbound.
Especially in unwind this burns a lot of memory because this is
allocated per libunbound context. Without a config file memory usage
goes down from 10M to 6.7M.
This is a diff to get rid of outgoing_avail_ports in unwind and
unbound. I'll try to upstream it. unbound tests would be very much
appreciated.
Comments, OKs?
diff --git sbin/unwind/libunbound/libunbound/libworker.c
sbin/unwind/libunbound/libunbound/libworker.c
index 11bf5f9db55..941a3d660c8 100644
--- sbin/unwind/libunbound/libunbound/libworker.c
+++ sbin/unwind/libunbound/libunbound/libworker.c
@@ -225,6 +225,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct
ub_event_base* eb)
if(!w->is_bg || w->is_bg_thread) {
lock_basic_lock(&ctx->cfglock);
}
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
numports = cfg_condense_ports(cfg, &ports);
if(numports == 0) {
if(!w->is_bg || w->is_bg_thread) {
@@ -233,6 +234,10 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct
ub_event_base* eb)
libworker_delete(w);
return NULL;
}
+#else
+ numports = 1;
+ ports = NULL;
+#endif
w->back = outside_network_create(w->base, cfg->msg_buffer_size,
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
diff --git sbin/unwind/libunbound/util/config_file.c
sbin/unwind/libunbound/util/config_file.c
index d7bd37a8890..f3713792a25 100644
--- sbin/unwind/libunbound/util/config_file.c
+++ sbin/unwind/libunbound/util/config_file.c
@@ -84,8 +84,10 @@ size_t http2_response_buffer_max = 4 * 1024 * 1024;
/** global config during parsing */
struct config_parser_state* cfg_parser = 0;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** init ports possible for use */
static void init_outgoing_availports(int* array, int num);
+#endif
struct config_file*
config_create(void)
@@ -176,9 +178,11 @@ config_create(void)
cfg->infra_keep_probing = 0;
cfg->delay_close = 0;
cfg->udp_connect = 1;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int))))
goto error_exit;
init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
+#endif
if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
#ifdef HAVE_CHROOT
if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
@@ -482,12 +486,14 @@ int config_set_option(struct config_file* cfg, const
char* opt,
} else if(strcmp(opt, "num-threads:") == 0) {
/* not supported, library must have 1 thread in bgworker */
return 0;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
} else if(strcmp(opt, "outgoing-port-permit:") == 0) {
return cfg_mark_ports(val, 1,
cfg->outgoing_avail_ports, 65536);
} else if(strcmp(opt, "outgoing-port-avoid:") == 0) {
return cfg_mark_ports(val, 0,
cfg->outgoing_avail_ports, 65536);
+#endif
} else if(strcmp(opt, "local-zone:") == 0) {
return cfg_parse_local_zone(cfg, val);
} else if(strcmp(opt, "val-override-date:") == 0) {
@@ -1577,7 +1583,9 @@ config_delete(struct config_file* cfg)
free(cfg->nsid_cfg_str);
free(cfg->nsid);
free(cfg->module_conf);
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
free(cfg->outgoing_avail_ports);
+#endif
config_delstrlist(cfg->caps_whitelist);
config_delstrlist(cfg->private_address);
config_delstrlist(cfg->private_domain);
@@ -1640,6 +1648,7 @@ config_delete(struct config_file* cfg)
free(cfg);
}
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
static void
init_outgoing_availports(int* a, int num)
{
@@ -1668,11 +1677,7 @@ int
cfg_mark_ports(const char* str, int allow, int* avail, int num)
{
char* mid = strchr(str, '-');
-#ifdef DISABLE_EXPLICIT_PORT_RANDOMISATION
- log_warn("Explicit port randomisation disabled, ignoring "
- "outgoing-port-permit and outgoing-port-avoid configuration "
- "options");
-#endif
+
if(!mid) {
int port = atoi(str);
if(port == 0 && strcmp(str, "0") != 0) {
@@ -1738,6 +1743,7 @@ int cfg_condense_ports(struct config_file* cfg, int**
avail)
log_assert(at == num);
return num;
}
+#endif
void cfg_apply_local_port_policy(struct config_file* cfg, int num) {
(void)cfg;
diff --git sbin/unwind/libunbound/util/config_file.h
sbin/unwind/libunbound/util/config_file.h
index 0b457e3476b..136a0fd73fd 100644
--- sbin/unwind/libunbound/util/config_file.h
+++ sbin/unwind/libunbound/util/config_file.h
@@ -159,8 +159,10 @@ struct config_file {
size_t outgoing_num_tcp;
/** number of incoming tcp buffers per (per thread) */
size_t incoming_num_tcp;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** allowed udp port numbers, array with 0 if not allowed */
int* outgoing_avail_ports;
+#endif
/** EDNS buffer size to use */
size_t edns_buffer_size;
diff --git sbin/unwind/libunbound/util/configparser.y
sbin/unwind/libunbound/util/configparser.y
index c003f335839..da0bbd3d94c 100644
--- sbin/unwind/libunbound/util/configparser.y
+++ sbin/unwind/libunbound/util/configparser.y
@@ -760,18 +760,28 @@ server_outgoing_range: VAR_OUTGOING_RANGE STRING_ARG
server_outgoing_port_permit: VAR_OUTGOING_PORT_PERMIT STRING_ARG
{
OUTYY(("P(server_outgoing_port_permit:%s)\n", $2));
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!cfg_mark_ports($2, 1,
cfg_parser->cfg->outgoing_avail_ports, 65536))
yyerror("port number or range (\"low-high\") expected");
+#else
+ log_warn("option outgoing-port-permit ignored: Explicit port "
+ "randomisation disabled");
+#endif
free($2);
}
;
server_outgoing_port_avoid: VAR_OUTGOING_PORT_AVOID STRING_ARG
{
OUTYY(("P(server_outgoing_port_avoid:%s)\n", $2));
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!cfg_mark_ports($2, 0,
cfg_parser->cfg->outgoing_avail_ports, 65536))
yyerror("port number or range (\"low-high\") expected");
+#else
+ log_warn("option outgoing-port-avoid ignored: Explicit port "
+ "randomisation disabled");
+#endif
free($2);
}
;
diff --git usr.sbin/unbound/daemon/daemon.c usr.sbin/unbound/daemon/daemon.c
index 0e3923b4e9f..0051961647c 100644
--- usr.sbin/unbound/daemon/daemon.c
+++ usr.sbin/unbound/daemon/daemon.c
@@ -402,6 +402,7 @@ static void daemon_setup_modules(struct daemon* daemon)
log_edns_known_options(VERB_ALGO, daemon->env);
}
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/**
* Obtain allowed port numbers, concatenate the list, and shuffle them
* (ready to be handed out to threads).
@@ -432,6 +433,7 @@ static int daemon_get_shufport(struct daemon* daemon, int*
shufport)
}
return avail;
}
+#endif
/**
* Allocate empty worker structures. With backptr and thread-number,
@@ -452,12 +454,16 @@ daemon_create_workers(struct daemon* daemon)
fatal_exit("could not init random generator");
hash_set_raninit((uint32_t)ub_random(daemon->rand));
}
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
shufport = (int*)calloc(65536, sizeof(int));
if(!shufport)
fatal_exit("out of memory during daemon init");
numport = daemon_get_shufport(daemon, shufport);
verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
-
+#else
+ numport = 1;
+ shufport = NULL;
+#endif
daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1);
if(daemon->reuseport && (int)daemon->num < (int)daemon->num_ports) {
log_warn("cannot reduce num-threads to %d because so-reuseport "
diff --git usr.sbin/unbound/daemon/worker.c usr.sbin/unbound/daemon/worker.c
index bf8c5d6b676..b8c645898b0 100644
--- usr.sbin/unbound/daemon/worker.c
+++ usr.sbin/unbound/daemon/worker.c
@@ -1872,11 +1872,15 @@ worker_create(struct daemon* daemon, int id, int*
ports, int n)
if(!worker)
return NULL;
worker->numports = n;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
worker->ports = (int*)memdup(ports, sizeof(int)*n);
if(!worker->ports) {
free(worker);
return NULL;
}
+#else
+ worker->ports = NULL;
+#endif
worker->daemon = daemon;
worker->thread_num = id;
if(!(worker->cmd = tube_create())) {
diff --git usr.sbin/unbound/libunbound/libworker.c
usr.sbin/unbound/libunbound/libworker.c
index 11bf5f9db55..941a3d660c8 100644
--- usr.sbin/unbound/libunbound/libworker.c
+++ usr.sbin/unbound/libunbound/libworker.c
@@ -225,6 +225,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct
ub_event_base* eb)
if(!w->is_bg || w->is_bg_thread) {
lock_basic_lock(&ctx->cfglock);
}
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
numports = cfg_condense_ports(cfg, &ports);
if(numports == 0) {
if(!w->is_bg || w->is_bg_thread) {
@@ -233,6 +234,10 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct
ub_event_base* eb)
libworker_delete(w);
return NULL;
}
+#else
+ numports = 1;
+ ports = NULL;
+#endif
w->back = outside_network_create(w->base, cfg->msg_buffer_size,
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
diff --git usr.sbin/unbound/util/config_file.c
usr.sbin/unbound/util/config_file.c
index d7bd37a8890..f3713792a25 100644
--- usr.sbin/unbound/util/config_file.c
+++ usr.sbin/unbound/util/config_file.c
@@ -84,8 +84,10 @@ size_t http2_response_buffer_max = 4 * 1024 * 1024;
/** global config during parsing */
struct config_parser_state* cfg_parser = 0;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** init ports possible for use */
static void init_outgoing_availports(int* array, int num);
+#endif
struct config_file*
config_create(void)
@@ -176,9 +178,11 @@ config_create(void)
cfg->infra_keep_probing = 0;
cfg->delay_close = 0;
cfg->udp_connect = 1;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int))))
goto error_exit;
init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
+#endif
if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
#ifdef HAVE_CHROOT
if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
@@ -482,12 +486,14 @@ int config_set_option(struct config_file* cfg, const
char* opt,
} else if(strcmp(opt, "num-threads:") == 0) {
/* not supported, library must have 1 thread in bgworker */
return 0;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
} else if(strcmp(opt, "outgoing-port-permit:") == 0) {
return cfg_mark_ports(val, 1,
cfg->outgoing_avail_ports, 65536);
} else if(strcmp(opt, "outgoing-port-avoid:") == 0) {
return cfg_mark_ports(val, 0,
cfg->outgoing_avail_ports, 65536);
+#endif
} else if(strcmp(opt, "local-zone:") == 0) {
return cfg_parse_local_zone(cfg, val);
} else if(strcmp(opt, "val-override-date:") == 0) {
@@ -1577,7 +1583,9 @@ config_delete(struct config_file* cfg)
free(cfg->nsid_cfg_str);
free(cfg->nsid);
free(cfg->module_conf);
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
free(cfg->outgoing_avail_ports);
+#endif
config_delstrlist(cfg->caps_whitelist);
config_delstrlist(cfg->private_address);
config_delstrlist(cfg->private_domain);
@@ -1640,6 +1648,7 @@ config_delete(struct config_file* cfg)
free(cfg);
}
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
static void
init_outgoing_availports(int* a, int num)
{
@@ -1668,11 +1677,7 @@ int
cfg_mark_ports(const char* str, int allow, int* avail, int num)
{
char* mid = strchr(str, '-');
-#ifdef DISABLE_EXPLICIT_PORT_RANDOMISATION
- log_warn("Explicit port randomisation disabled, ignoring "
- "outgoing-port-permit and outgoing-port-avoid configuration "
- "options");
-#endif
+
if(!mid) {
int port = atoi(str);
if(port == 0 && strcmp(str, "0") != 0) {
@@ -1738,6 +1743,7 @@ int cfg_condense_ports(struct config_file* cfg, int**
avail)
log_assert(at == num);
return num;
}
+#endif
void cfg_apply_local_port_policy(struct config_file* cfg, int num) {
(void)cfg;
diff --git usr.sbin/unbound/util/config_file.h
usr.sbin/unbound/util/config_file.h
index 0b457e3476b..136a0fd73fd 100644
--- usr.sbin/unbound/util/config_file.h
+++ usr.sbin/unbound/util/config_file.h
@@ -159,8 +159,10 @@ struct config_file {
size_t outgoing_num_tcp;
/** number of incoming tcp buffers per (per thread) */
size_t incoming_num_tcp;
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** allowed udp port numbers, array with 0 if not allowed */
int* outgoing_avail_ports;
+#endif
/** EDNS buffer size to use */
size_t edns_buffer_size;
diff --git usr.sbin/unbound/util/configparser.y
usr.sbin/unbound/util/configparser.y
index c003f335839..da0bbd3d94c 100644
--- usr.sbin/unbound/util/configparser.y
+++ usr.sbin/unbound/util/configparser.y
@@ -760,18 +760,28 @@ server_outgoing_range: VAR_OUTGOING_RANGE STRING_ARG
server_outgoing_port_permit: VAR_OUTGOING_PORT_PERMIT STRING_ARG
{
OUTYY(("P(server_outgoing_port_permit:%s)\n", $2));
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!cfg_mark_ports($2, 1,
cfg_parser->cfg->outgoing_avail_ports, 65536))
yyerror("port number or range (\"low-high\") expected");
+#else
+ log_warn("option outgoing-port-permit ignored: Explicit port "
+ "randomisation disabled");
+#endif
free($2);
}
;
server_outgoing_port_avoid: VAR_OUTGOING_PORT_AVOID STRING_ARG
{
OUTYY(("P(server_outgoing_port_avoid:%s)\n", $2));
+#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!cfg_mark_ports($2, 0,
cfg_parser->cfg->outgoing_avail_ports, 65536))
yyerror("port number or range (\"low-high\") expected");
+#else
+ log_warn("option outgoing-port-avoid ignored: Explicit port "
+ "randomisation disabled");
+#endif
free($2);
}
;
--
I'm not entirely sure you are real.