feat: report what listens, and which OPNsense service it is
CI / test (3.10) (push) Successful in 40s
CI / test (3.11) (push) Successful in 30s
CI / test (3.12) (push) Successful in 31s
CI / test (3.10) (pull_request) Successful in 29s
CI / test (3.11) (pull_request) Successful in 28s
CI / test (3.12) (pull_request) Successful in 30s

get_listening_sockets reads /api/diagnostics/interface/get_socket_statistics:
netstat's sockets with sockstat's user, command and PID, collected by
configd as root, so no SSH is needed. A listening socket is one without a
peer (*:*); "*" is the any-address of the socket's family.

Which service: the socket's unit is a name of the firewall's own service
list, so netOrk can match it to the service. The command (cut to ten
characters by FreeBSD) matches a service name, the start of one, or one
of the daemons whose service is called otherwise (sshd is openssh, the
FRR daemons are frr, kea-ctrl-agent is kea-dhcp). lighttpd is the web UI,
or the captive portal when it runs as www. WireGuard's sockets belong to
the kernel and are told by the listen ports of /api/wireguard/service/show.

The fixture is a real OPNsense 26.7.5 firewall's answer, cut down, with
documentation addresses. For netOrk#673.
This commit is contained in:
Christian Manivong
2026-10-07 07:20:27 +02:00
parent 8ce7ea52e7
commit 2fb1226734
5 changed files with 1233 additions and 0 deletions
+935
View File
@@ -0,0 +1,935 @@
{
"statistics": {
"Active Internet connections": {
"tcp4/[192.0.2.1:443-192.0.2.50:38544]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "443",
"0": "192.0.2.1:443"
},
"remote": {
"address": "192.0.2.50",
"port": "38544",
"0": "192.0.2.50:38544"
},
"receive-high-water": 65700,
"send-high-water": 65700,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 525600,
"send-mbuf-bytes-max": 525600,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "7199.77",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "0.02",
"flow-id": "f6ae054e",
"flow-type": 130,
"user": "root",
"command": "lighttpd",
"pid": "46564",
"fd": "19",
"proto": "tcp4"
},
"tcp4/[192.0.2.1:443-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "443",
"0": "192.0.2.1:443"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "33552.00",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "lighttpd",
"pid": "46564",
"fd": "11",
"proto": "tcp4"
},
"tcp4/[198.51.100.1:443-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "198.51.100.1",
"port": "443",
"0": "198.51.100.1:443"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "33552.00",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "lighttpd",
"pid": "46564",
"fd": "10",
"proto": "tcp4"
},
"tcp4/[127.0.0.1:443-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "127.0.0.1",
"port": "443",
"0": "127.0.0.1:443"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "33552.00",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "lighttpd",
"pid": "46564",
"fd": "7",
"proto": "tcp4"
},
"tcp4/[192.0.2.1:80-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "80",
"0": "192.0.2.1:80"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "33552.00",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "lighttpd",
"pid": "46564",
"fd": "16",
"proto": "tcp4"
},
"tcp4/[*:8000-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "8000",
"0": "*:8000"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "41043.28",
"flow-id": "0",
"flow-type": 0,
"user": "www",
"command": "lighttpd",
"pid": "7612",
"fd": "7",
"proto": "tcp4",
"listen-queue-sizes": {
"qlen": "0",
"incqlen": "0",
"maxqlen": "128"
}
},
"tcp6/[*:8000-*:*]": {
"protocol": "tcp6",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "8000",
"0": "*:8000"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "41043.28",
"flow-id": "0",
"flow-type": 0,
"user": "www",
"command": "lighttpd",
"pid": "7612",
"fd": "4",
"proto": "tcp6",
"listen-queue-sizes": {
"qlen": "0",
"incqlen": "0",
"maxqlen": "128"
}
},
"tcp4/[192.0.2.1:8080-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "8080",
"0": "192.0.2.1:8080"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "21096.55",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "crowdsec",
"pid": "90423",
"fd": "26",
"proto": "tcp4"
},
"tcp4/[127.0.0.1:6060-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "127.0.0.1",
"port": "6060",
"0": "127.0.0.1:6060"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "41044.32",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "crowdsec",
"pid": "90423",
"fd": "20",
"proto": "tcp4"
},
"tcp4/[192.0.2.1:10050-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "10050",
"0": "192.0.2.1:10050"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "41044.31",
"flow-id": "0",
"flow-type": 0,
"user": "zabbix",
"command": "zabbix_age",
"pid": "70051",
"fd": "5",
"proto": "tcp4"
},
"tcp4/[192.0.2.1:22-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "22",
"0": "192.0.2.1:22"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "41054.14",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "sshd",
"pid": "12554",
"fd": "6",
"proto": "tcp4"
},
"tcp4/[127.0.0.1:22-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "127.0.0.1",
"port": "22",
"0": "127.0.0.1:22"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "41054.14",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "sshd",
"pid": "12554",
"fd": "11",
"proto": "tcp4"
},
"tcp4/[203.0.113.1:53-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "203.0.113.1",
"port": "53",
"0": "203.0.113.1:53"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "9830.17",
"flow-id": "0",
"flow-type": 0,
"user": "unbound",
"command": "unbound",
"pid": "10992",
"fd": "116",
"proto": "tcp4"
},
"tcp4/[127.0.0.1:953-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "127.0.0.1",
"port": "953",
"0": "127.0.0.1:953"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "9830.17",
"flow-id": "0",
"flow-type": 0,
"user": "unbound",
"command": "unbound",
"pid": "10992",
"fd": "117",
"proto": "tcp4"
},
"tcp4/[127.0.0.1:8000-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "127.0.0.1",
"port": "8000",
"0": "127.0.0.1:8000"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "10006.15",
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "kea-ctrl-a",
"pid": "14979",
"fd": "7",
"proto": "tcp4"
},
"tcp4/[127.0.0.1:2604-*:*]": {
"protocol": "tcp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "127.0.0.1",
"port": "2604",
"0": "127.0.0.1:2604"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 0,
"send-high-water": 0,
"receive-low-water": 0,
"send-low-water": 0,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 0,
"send-mbuf-bytes-max": 0,
"retransmit-timer": "0.00",
"persist-timer": "0.00",
"keepalive-timer": "0.00",
"msl2-timer": "0.00",
"delay-ack-timer": "0.00",
"inactivity-timer": "41047.92",
"flow-id": "0",
"flow-type": 0,
"user": "frr",
"command": "ospfd",
"pid": "89416",
"fd": "11",
"proto": "tcp4"
},
"udp4/[203.0.113.1:53-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "203.0.113.1",
"port": "53",
"0": "203.0.113.1:53"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "b8a211",
"flow-type": 63,
"user": "unbound",
"command": "unbound",
"pid": "10992",
"fd": "115",
"proto": "udp4"
},
"udp4/[192.0.2.1:67-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "67",
"0": "192.0.2.1:67"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "b899f5",
"flow-type": 63,
"user": "root",
"command": "kea-dhcp4",
"pid": "12917",
"fd": "19",
"proto": "udp4"
},
"udp4/[*:123-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "123",
"0": "*:123"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "c23b49",
"flow-type": 63,
"user": "root",
"command": "ntpd",
"pid": "69031",
"fd": "21",
"proto": "udp4"
},
"udp6/[*:123-*:*]": {
"protocol": "udp6",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "123",
"0": "*:123"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "0",
"flow-type": 0,
"user": "root",
"command": "ntpd",
"pid": "69031",
"fd": "20",
"proto": "udp6"
},
"udp4/[198.51.100.1:5353-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 42052,
"send-bytes-waiting": 0,
"local": {
"address": "198.51.100.1",
"port": "5353",
"0": "198.51.100.1:5353"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 321536,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "13f3",
"flow-type": 63,
"user": "root",
"command": "mdns-repea",
"pid": "12222",
"fd": "10",
"proto": "udp4"
},
"udp4/[*:1900-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "1900",
"0": "*:1900"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "c27",
"flow-type": 63,
"user": "root",
"command": "udpbroadca",
"pid": "78873",
"fd": "3",
"proto": "udp4"
},
"udp4/[192.0.2.1:161-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "192.0.2.1",
"port": "161",
"0": "192.0.2.1:161"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "130d",
"flow-type": 63,
"user": "root",
"command": "snmpd",
"pid": "53743",
"fd": "8",
"proto": "udp4"
},
"udp4/[*:51821-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "51821",
"0": "*:51821"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "945",
"flow-type": 63,
"user": "??",
"command": "??",
"pid": "??",
"fd": "??",
"proto": "udp4"
},
"udp6/[*:51821-*:*]": {
"protocol": "udp6",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "51821",
"0": "*:51821"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "0",
"flow-type": 0,
"user": "??",
"command": "??",
"pid": "??",
"fd": "??",
"proto": "udp6"
},
"udp4/[*:29281-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "29281",
"0": "*:29281"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "c23c01",
"flow-type": 63,
"user": "??",
"command": "??",
"pid": "??",
"fd": "??",
"proto": "udp4"
},
"udp4/[*:*-*:*]": {
"protocol": "udp4",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"local": {
"address": "*",
"port": "*",
"0": "*:*"
},
"remote": {
"address": "*",
"port": "*",
"0": "*:*"
},
"receive-high-water": 42080,
"send-high-water": 57344,
"receive-low-water": 1,
"send-low-water": 2048,
"receive-mbuf-bytes": 0,
"send-mbuf-bytes": 0,
"receive-mbuf-bytes-max": 336640,
"send-mbuf-bytes-max": 458752,
"flow-id": "1441",
"flow-type": 63,
"user": "_lldpd",
"command": "lldpd",
"pid": "72768",
"fd": "6",
"proto": "udp4"
}
},
"Active UNIX domain sockets": {
"fffff80016c50c80 - /var/run/configd.socket": {
"address": "fffff80016c50c80",
"type": "stream",
"receive-bytes-waiting": 0,
"send-bytes-waiting": 0,
"vnode": "0",
"connection": "fffff8006e7b8640",
"first-reference": "0",
"next-reference": "0",
"path": "/var/run/configd.socket"
}
}
}
}
+147
View File
@@ -0,0 +1,147 @@
"""What listens on an OPNsense firewall, and which OPNsense service it is (netOrk #673).
OPNsense answers through its API, ``diagnostics/interface/get_socket_statistics``:
netstat's sockets with sockstat's user, command and PID merged in, read by configd
as root. A socket that listens has no peer (``*:*``). Which service holds it comes
from the command -- cut to ten characters by FreeBSD -- matched against the
firewall's own service list; WireGuard's sockets belong to the kernel and are
told by their port.
The fixture is a real OPNsense 26.7.5 firewall's answer, cut down, with
documentation addresses.
"""
from __future__ import annotations
import json
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
from napalm_opnsense.opnsense import OPNsenseDriver
STATISTICS = json.loads((Path(__file__).parent / "fixtures" / "socket_statistics.json").read_text())
SERVICES = [
"acme", "captiveportal", "configd", "cron", "crowdsec", "frr", "kea-dhcp", "lldpd",
"login", "mdns-repeater", "ntpd", "openssh", "pf", "snmpd", "udpbroadcastrelay",
"unbound", "webgui", "wireguard", "zabbix_agentd",
] # fmt: skip
WIREGUARD = {
"rows": [
{"if": "wg1", "type": "interface", "listen-port": "51821", "status": "up"},
{"if": "wg1", "type": "peer", "allowed-ips": "10.99.99.2/32"},
{"if": "wg2", "type": "interface", "listen-port": "29281", "status": "up"},
]
}
def _driver(services=SERVICES, wireguard=WIREGUARD) -> OPNsenseDriver:
with patch("napalm_opnsense.opnsense.requests.Session"):
drv = OPNsenseDriver(hostname="fw", username="k", password="s")
drv.session = MagicMock()
def get(path: str) -> dict:
if path == "/api/diagnostics/interface/get_socket_statistics":
return STATISTICS
if path == "/api/core/service/search":
return {"rows": [{"id": n, "name": n, "running": 1} for n in services]}
if path == "/api/wireguard/service/show":
if isinstance(wireguard, Exception):
raise wireguard
return wireguard
raise AssertionError(f"unexpected GET {path}")
drv._get = get # type: ignore[method-assign]
return drv
def _sockets(drv: OPNsenseDriver | None = None) -> dict:
reading = (drv or _driver()).get_listening_sockets()
return {(s["proto"], s["port"], s["address"]): s for s in reading["sockets"]}
class TestTheReading:
def test_read_as_root(self):
assert _driver().get_listening_sockets()["attributed"] is True
def test_a_socket_comes_with_its_process_and_service(self):
assert _sockets()[("tcp", 8080, "192.0.2.1")] == {
"proto": "tcp",
"address": "192.0.2.1",
"port": 8080,
"interface": None,
"process": "crowdsec",
"pid": 90423,
"unit": "crowdsec",
"container_id": None,
}
def test_only_what_listens(self):
"""A connection has a peer; a socket without a port listens on nothing."""
sockets = _driver().get_listening_sockets()["sockets"]
assert len(sockets) == 25
assert all(s["port"] > 0 for s in sockets)
@pytest.mark.parametrize(
"proto, port, address",
[
("tcp", 8000, "0.0.0.0"),
("tcp", 8000, "::"),
("udp", 123, "0.0.0.0"),
("udp", 123, "::"),
],
)
def test_every_address_of_a_family_is_its_any_address(self, proto, port, address):
assert (proto, port, address) in _sockets()
def test_sorted_by_protocol_port_and_address(self):
sockets = _driver().get_listening_sockets()["sockets"]
keys = [(s["proto"], s["port"], s["address"]) for s in sockets]
assert keys == sorted(keys)
class TestWhichService:
@pytest.mark.parametrize(
"proto, port, address, service",
[
("tcp", 22, "192.0.2.1", "openssh"),
("tcp", 443, "192.0.2.1", "webgui"),
("tcp", 8000, "0.0.0.0", "captiveportal"), # lighttpd as www
("udp", 67, "192.0.2.1", "kea-dhcp"), # kea-dhcp4
("tcp", 8000, "127.0.0.1", "kea-dhcp"), # kea-ctrl-agent, cut short
("tcp", 2604, "127.0.0.1", "frr"), # ospfd
("udp", 5353, "198.51.100.1", "mdns-repeater"), # cut short
("udp", 1900, "0.0.0.0", "udpbroadcastrelay"),
("tcp", 10050, "192.0.2.1", "zabbix_agentd"),
("udp", 53, "203.0.113.1", "unbound"),
("udp", 123, "0.0.0.0", "ntpd"),
],
)
def test_by_its_command(self, proto, port, address, service):
assert _sockets()[(proto, port, address)]["unit"] == service
def test_the_command_stays_as_reported(self):
assert _sockets()[("udp", 5353, "198.51.100.1")]["process"] == "mdns-repea"
def test_a_service_the_firewall_does_not_list_is_none(self):
without_snmpd = [n for n in SERVICES if n != "snmpd"]
assert _sockets(_driver(services=without_snmpd))[("udp", 161, "192.0.2.1")]["unit"] is None
def test_wireguard_s_kernel_sockets_by_their_port(self):
wg = _sockets()[("udp", 51821, "0.0.0.0")]
assert (wg["process"], wg["pid"], wg["unit"]) == (None, None, "wireguard")
def test_without_wireguard_a_kernel_socket_is_nobody_s(self):
sockets = _sockets(_driver(wireguard=RuntimeError("404")))
assert sockets[("udp", 29281, "0.0.0.0")]["unit"] is None
def test_netork_finds_it():
"""netOrk asks ``hasattr(driver, "get_listening_sockets")``."""
assert hasattr(OPNsenseDriver, "get_listening_sockets")