1 - from http://www.ducksong.com/misc/netstat-netlink-diag-patch.txt
4 ===================================================================
5 RCS file: /cvsroot/net-tools/net-tools/netstat.c,v
6 retrieving revision 1.55
7 diff -urNp -x '*.orig' net-tools-2.10.org/config.h net-tools-2.10/config.h
8 --- net-tools-2.10.org/config.h 2023-12-02 23:34:04.104218822 +0100
9 +++ net-tools-2.10/config.h 2023-12-02 23:34:04.168219581 +0100
11 #define HAVE_IP_TOOLS 0
13 #define HAVE_SELINUX 1
14 +#define HAVE_NETLINK 1
15 diff -urNp -x '*.orig' net-tools-2.10.org/config.in net-tools-2.10/config.in
16 --- net-tools-2.10.org/config.in 2021-01-07 00:22:35.000000000 +0100
17 +++ net-tools-2.10/config.in 2023-12-02 23:34:04.168219581 +0100
18 @@ -98,3 +98,4 @@ bool 'Build mii-tool' HAVE_MII y
19 bool 'Build plipconfig' HAVE_PLIP_TOOLS y
20 bool 'Build slattach' HAVE_SERIAL_TOOLS y
21 bool 'SELinux support' HAVE_SELINUX n
22 +bool 'Use Netlink Diag' HAVE_NETLINK y
23 diff -urNp -x '*.orig' net-tools-2.10.org/config.make net-tools-2.10/config.make
24 --- net-tools-2.10.org/config.make 2023-12-02 23:34:04.104218822 +0100
25 +++ net-tools-2.10/config.make 2023-12-02 23:34:04.168219581 +0100
26 @@ -36,3 +36,4 @@ HAVE_HWIRDA=1
31 diff -urNp -x '*.orig' net-tools-2.10.org/netstat.c net-tools-2.10/netstat.c
32 --- net-tools-2.10.org/netstat.c 2021-01-07 00:22:35.000000000 +0100
33 +++ net-tools-2.10/netstat.c 2023-12-02 23:34:04.168219581 +0100
35 #include <bluetooth/bluetooth.h>
39 +#include <asm/types.h>
40 +#include <linux/netlink.h>
41 +#include <linux/inet_diag.h>
45 #define PROGNAME_WIDTH 20
46 #define SELINUX_WIDTH 50
48 @@ -1216,11 +1223,194 @@ static void tcp_do_one(int lnr, const ch
49 finish_this_one(uid,inode,timers);
57 + /* a newer alternative to /proc/net/tcp[6] - using NETLINK DIAG
58 + runs much faster with large number of entries
59 + essentially just a bridge - converts from DIAG to /proc/net/tcp format
60 + largely taken directly from ss of iproute package
62 + returns -1 if NETLINK isn't available, in which case the old /proc/net/tcp code is run
66 + struct sockaddr_nl nladdr;
68 + struct nlmsghdr nlh;
69 + struct inet_diag_req r;
76 + struct inet_diag_msg *r;
79 + if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
82 + memset(&nladdr, 0, sizeof(nladdr));
83 + nladdr.nl_family = AF_NETLINK;
85 + req.nlh.nlmsg_len = sizeof(req);
86 + req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
87 + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
88 + req.nlh.nlmsg_pid = 0;
89 + req.nlh.nlmsg_seq = 123456;
90 + memset(&req.r, 0, sizeof(req.r));
91 + req.r.idiag_family = AF_INET;
92 + req.r.idiag_states = 0xfff;
93 + req.r.idiag_ext = 0;
95 + iov.iov_base = &req;
96 + iov.iov_len = sizeof(req);
98 + msg = (struct msghdr) {
99 + .msg_name = (void*)&nladdr,
100 + .msg_namelen = sizeof(nladdr),
105 + if (sendmsg(fd, &msg, 0) < 0)
111 + iov.iov_base = buf;
112 + iov.iov_len = sizeof(buf);
117 + struct nlmsghdr *h;
119 + msg = (struct msghdr) {
120 + (void*)&nladdr, sizeof(nladdr),
126 + status = recvmsg(fd, &msg, 0);
130 + if (errno == EINTR)
143 + h = (struct nlmsghdr*)buf;
144 + while (NLMSG_OK(h, status))
146 + if (h->nlmsg_seq == 123456)
148 + if (h->nlmsg_type == NLMSG_DONE)
154 + if (h->nlmsg_type == NLMSG_ERROR)
162 + if (r->idiag_family == AF_INET)
164 + snprintf (linebuf,8192,
165 + "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08X %08X %5d %8d %d",
167 + r->id.idiag_src[0],
168 + ntohs(r->id.idiag_sport),
169 + r->id.idiag_dst[0],
170 + ntohs(r->id.idiag_dport),
172 + r->idiag_wqueue, r->idiag_rqueue,
174 + r->idiag_expires/10, // (diag reports as miliseconds, /proc interface stuck at centiseconds)
182 + snprintf (linebuf,8192,
183 + "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X %02X %08X:%08X %02X:%08X %08X %5d %8d %d",
185 + r->id.idiag_src[0],
186 + r->id.idiag_src[1],
187 + r->id.idiag_src[2],
188 + r->id.idiag_src[3],
189 + ntohs(r->id.idiag_sport),
190 + r->id.idiag_dst[0],
191 + r->id.idiag_dst[1],
192 + r->id.idiag_dst[2],
193 + r->id.idiag_dst[3],
194 + ntohs(r->id.idiag_dport),
196 + r->idiag_wqueue, r->idiag_rqueue,
198 + r->idiag_expires/10, // (diag reports as miliseconds, /proc interface stuck at centiseconds)
205 + tcp_do_one (++lnr, linebuf, r->idiag_family == AF_INET ? "tcp" : "tcp6");
207 + h = NLMSG_NEXT(h, status);
220 static int tcp_info(void)
222 - INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
223 - tcp_do_one, "tcp", "tcp6");
227 + rv = tcp_netlink();
232 + // netlink is not available - so parse /proc/net/tcp
233 + INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",
234 + tcp_do_one, "tcp", "tcp6");
243 static int notnull(const struct sockaddr_storage *sas)