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.

Reply via email to