netstat,pscan: don't use getservbyport(), it links in a static buffer
No binary (build failed)
gcc -Wp,-MD,applets/.usage.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Iinclude -Iinclude -o applets/usage applets/usage.c
(log yok)
| @@ -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; | |
| @@ -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; |
| + | } |
| @@ -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; | |
| } | |
| @@ -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. | |