[git commit] netstat, pscan: don't use getservbyport(), it links in a static buffer
Denys Vlasenko
vda.linux at googlemail.com
Tue Feb 24 21:42:30 UTC 2026
commit: https://git.busybox.net/busybox/commit/?id=c0037a997420886ea9cc295a7cd76d0955064c88
branch: https://git.busybox.net/busybox/log/?h=master
function old new delta
bb_get_servname_by_port - 182 +182
ip_port_str 112 121 +9
pscan_main 594 591 -3
getservbyport 53 - -53
getservbyport_r 430 - -430
------------------------------------------------------------------------------
(add/remove: 2/4 grow/shrink: 1/1 up/down: 191/-486) Total: -295 bytes
text data bss dec hex filename
1080362 555 5056 1085973 109215 busybox_old
1080067 555 5024 1085646 1090ce busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
include/libbb.h | 3 +++
libbb/bb_get_servname_by_port.c | 48 +++++++++++++++++++++++++++++++++++++++++
networking/netstat.c | 11 +++++-----
networking/pscan.c | 12 ++++++-----
4 files changed, 64 insertions(+), 10 deletions(-)
diff --git a/include/libbb.h b/include/libbb.h
index df974e3fc..f02d2c756 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -911,6 +911,9 @@ char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa) FAST_FUNC RETU
/* inet_[ap]ton on steroids */
char* xmalloc_sockaddr2dotted(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
+// NB: unlike getservbyport, port paramenter is NOT in network order
+#define getservbyport dont_use_getservbyport_uses_global_buffer
+char* bb_get_servname_by_port(char **p_etc_services, int port, const char *type) FAST_FUNC RETURNS_MALLOC;
// "old" (ipv4 only) API
// users: traceroute.c hostname.c - use _list_ of all IPs
struct hostent *xgethostbyname(const char *name) FAST_FUNC;
diff --git a/libbb/bb_get_servname_by_port.c b/libbb/bb_get_servname_by_port.c
new file mode 100644
index 000000000..d8ba55226
--- /dev/null
+++ b/libbb/bb_get_servname_by_port.c
@@ -0,0 +1,48 @@
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2026 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+//kbuild:lib-$(CONFIG_NETSTAT) += bb_get_servname_by_port.o
+//kbuild:lib-$(CONFIG_PSCAN) += bb_get_servname_by_port.o
+#include "libbb.h"
+
+char* FAST_FUNC bb_get_servname_by_port(char **p_etc_services, int port, const char *type)
+{
+ char *sp;
+
+ sp = *p_etc_services;
+ if (!sp) {
+//TODO: we need mmap_entire_file() for this use case!
+ sp = xmalloc_open_read_close("/etc/services", NULL);
+ if (!sp)
+ return NULL;
+ *p_etc_services = sp;
+ }
+ while (*sp) {
+ const char *portstr, *sp_end;
+ char *end;
+ unsigned portnum;
+
+ sp = skip_whitespace(sp);
+ if (*sp == '#')
+ goto next;
+ sp_end = skip_non_whitespace(sp);
+ portstr = skip_whitespace(sp_end);
+ portnum = bb_strtou(portstr, &end, 10);
+ if (portnum != port || *end != '/')
+ goto next;
+ if (type) {
+ end++;
+ end = is_prefixed_with(end, type);
+ if (!end || !(isspace(*end) || *end == '\0'))
+ goto next;
+ }
+ return auto_string(xstrndup(sp, sp_end - sp));
+ next:
+ sp = strchrnul(sp, '\n');
+ }
+ return NULL;
+}
diff --git a/networking/netstat.c b/networking/netstat.c
index d7afa8fdd..80d94221b 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -176,6 +176,7 @@ struct globals {
smallint prg_cache_loaded;
struct prg_node *prg_hash[PRG_HASH_SIZE];
#endif
+ char **p_etc_services;
#if ENABLE_FEATURE_NETSTAT_PRG
const char *progname_banner;
#endif
@@ -378,15 +379,15 @@ static void build_ipv4_addr(char* local_addr, struct sockaddr_in* localaddr)
static const char *get_sname(int port, const char *proto, int numeric)
{
- if (!port)
+ if (port == 0)
return "*";
if (!numeric) {
- struct servent *se = getservbyport(port, proto);
+ const char *se = bb_get_servname_by_port(G.p_etc_services, port, proto);
if (se)
- return se->s_name;
+ return se;
}
/* hummm, we may return static buffer here!! */
- return itoa(ntohs(port));
+ return itoa(port);
}
static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric)
@@ -402,7 +403,7 @@ static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int
if (!host)
host = xmalloc_sockaddr2dotted_noport(addr);
- xasprintf_inplace(host, "%s:%s", host, get_sname(htons(port), proto, numeric));
+ xasprintf_inplace(host, "%s:%s", host, get_sname(port, proto, numeric));
return host;
}
diff --git a/networking/pscan.c b/networking/pscan.c
index 13785deca..454dba3fb 100644
--- a/networking/pscan.c
+++ b/networking/pscan.c
@@ -37,13 +37,13 @@
#define DERR(...) ((void)0)
#endif
-static const char *port_name(unsigned port)
+static const char *port_name(char **p_etc_services, unsigned port)
{
- struct servent *server;
+ char *server;
- server = getservbyport(htons(port), NULL);
+ server = bb_get_servname_by_port(p_etc_services, port, NULL);
if (server)
- return server->s_name;
+ return server;
return "unknown";
}
@@ -62,6 +62,7 @@ int pscan_main(int argc UNUSED_PARAM, char **argv)
* Rule of thumb: with min_rtt of N msec, scanning 1000 ports
* will take N seconds at absolute minimum */
const char *opt_min_rtt = "5"; /* -T: default min rtt in msec */
+ char *p_etc_services = NULL;
const char *result_str;
len_and_sockaddr *lsap;
int s;
@@ -152,7 +153,8 @@ int pscan_main(int argc UNUSED_PARAM, char **argv)
DMSG("out of loop @%u", diff);
if (result_str)
printf("%5u" "\t" "tcp" "\t" "%s" "\t" "%s" "\n",
- port, result_str, port_name(port));
+ port, result_str, port_name(&p_etc_services, port)
+ );
/* Estimate new rtt - we don't want to wait entire timeout
* for each port. *4 allows for rise in net delay.
More information about the busybox-cvs
mailing list