network_command_t::read_from_packet allocates an nwc by switch on
p->get_id() and only reaches the receive(p) call (which transfers
packet ownership to the nwc) when the switch produced one. An
unknown id fell through default, the function returned NULL with
p still live, and the caller — socket_info_t::receive_nwc — set
its own packet member to NULL anyway, dropping the only pointer
to the 8KB packet buffer. Each junk-id packet from a peer leaked.
nettool's parallel implementation in src/nettool/nettool.cc has
the identical leak in the same shape: switch falls through
default with p still live, the caller (network_check_activity)
doesn't free it. nettool only constructs nwc_service_t, so
every other reply from the server hits default and leaks 8KB
per packet — a malicious or buggy server can starve a
long-running admin tool of memory.
That could explain why the server always run out of memory after some time. Well spotted.