]>
Commit | Line | Data |
---|---|---|
3ada5ed8 ER |
1 | - from http://www.ducksong.com/misc/netstat-netlink-diag-patch.txt |
2 | ||
3 | Index: netstat.c | |
4 | =================================================================== | |
5 | RCS file: /cvsroot/net-tools/net-tools/netstat.c,v | |
6 | retrieving revision 1.55 | |
581b2566 MK |
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 | |
10 | @@ -73,3 +73,4 @@ | |
11 | #define HAVE_IP_TOOLS 0 | |
12 | #define HAVE_MII 1 | |
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 | |
27 | # HAVE_IP_TOOLS=0 | |
28 | HAVE_MII=1 | |
29 | HAVE_SELINUX=1 | |
30 | +HAVE_NETLINK=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 | |
34 | @@ -107,6 +107,13 @@ | |
35 | #include <bluetooth/bluetooth.h> | |
36 | #endif | |
3ada5ed8 ER |
37 | |
38 | +#ifdef HAVE_NETLINK | |
39 | +#include <asm/types.h> | |
40 | +#include <linux/netlink.h> | |
41 | +#include <linux/inet_diag.h> | |
42 | +#endif | |
43 | + | |
44 | + | |
45 | #define PROGNAME_WIDTH 20 | |
581b2566 | 46 | #define SELINUX_WIDTH 50 |
3ada5ed8 | 47 | |
581b2566 MK |
48 | @@ -1216,11 +1223,194 @@ static void tcp_do_one(int lnr, const ch |
49 | finish_this_one(uid,inode,timers); | |
3ada5ed8 ER |
50 | } |
51 | ||
52 | + | |
53 | + | |
54 | +#ifdef HAVE_NETLINK | |
55 | +int tcp_netlink() | |
56 | +{ | |
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 | |
61 | + | |
62 | + returns -1 if NETLINK isn't available, in which case the old /proc/net/tcp code is run | |
63 | + */ | |
64 | + | |
65 | + int fd; | |
66 | + struct sockaddr_nl nladdr; | |
67 | + struct { | |
68 | + struct nlmsghdr nlh; | |
69 | + struct inet_diag_req r; | |
70 | + } req; | |
71 | + struct msghdr msg; | |
72 | + char buf[8192]; | |
73 | + char linebuf[8192]; | |
74 | + struct iovec iov; | |
75 | + int lnr = 0; | |
76 | + struct inet_diag_msg *r; | |
77 | + int rv = 0; | |
78 | + | |
79 | + if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0) | |
80 | + return -1; | |
81 | + | |
82 | + memset(&nladdr, 0, sizeof(nladdr)); | |
83 | + nladdr.nl_family = AF_NETLINK; | |
84 | + | |
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; | |
94 | + | |
95 | + iov.iov_base = &req; | |
96 | + iov.iov_len = sizeof(req); | |
97 | + | |
98 | + msg = (struct msghdr) { | |
99 | + .msg_name = (void*)&nladdr, | |
100 | + .msg_namelen = sizeof(nladdr), | |
101 | + .msg_iov = &iov, | |
102 | + .msg_iovlen = 1, | |
103 | + }; | |
104 | + | |
105 | + if (sendmsg(fd, &msg, 0) < 0) | |
106 | + { | |
107 | + rv = -1; | |
108 | + goto netlink_done; | |
109 | + } | |
110 | + | |
111 | + iov.iov_base = buf; | |
112 | + iov.iov_len = sizeof(buf); | |
113 | + | |
114 | + while (1) | |
115 | + { | |
116 | + int status; | |
117 | + struct nlmsghdr *h; | |
118 | + | |
119 | + msg = (struct msghdr) { | |
120 | + (void*)&nladdr, sizeof(nladdr), | |
121 | + &iov, 1, | |
122 | + NULL, 0, | |
123 | + 0 | |
124 | + }; | |
125 | + | |
126 | + status = recvmsg(fd, &msg, 0); | |
127 | + | |
128 | + if (status < 0) | |
129 | + { | |
130 | + if (errno == EINTR) | |
131 | + continue; | |
132 | + rv = -2; | |
133 | + goto netlink_done; | |
134 | + } | |
135 | + | |
136 | + if (status == 0) | |
137 | + { | |
138 | + rv = 0; | |
139 | + goto netlink_done; | |
140 | + } | |
141 | + | |
142 | + | |
143 | + h = (struct nlmsghdr*)buf; | |
144 | + while (NLMSG_OK(h, status)) | |
145 | + { | |
146 | + if (h->nlmsg_seq == 123456) | |
147 | + { | |
148 | + if (h->nlmsg_type == NLMSG_DONE) | |
149 | + { | |
150 | + rv = 0; | |
151 | + goto netlink_done; | |
152 | + } | |
153 | + | |
154 | + if (h->nlmsg_type == NLMSG_ERROR) | |
155 | + { | |
156 | + rv = -2; | |
157 | + goto netlink_done; | |
158 | + } | |
159 | + | |
160 | + r = NLMSG_DATA(h); | |
161 | + | |
162 | + if (r->idiag_family == AF_INET) | |
163 | + { | |
164 | + snprintf (linebuf,8192, | |
165 | + "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08X %08X %5d %8d %d", | |
166 | + lnr, | |
167 | + r->id.idiag_src[0], | |
168 | + ntohs(r->id.idiag_sport), | |
169 | + r->id.idiag_dst[0], | |
170 | + ntohs(r->id.idiag_dport), | |
171 | + r->idiag_state, | |
172 | + r->idiag_wqueue, r->idiag_rqueue, | |
173 | + r->idiag_timer, | |
174 | + r->idiag_expires/10, // (diag reports as miliseconds, /proc interface stuck at centiseconds) | |
175 | + r->idiag_retrans, | |
176 | + r->idiag_uid, | |
177 | + r->idiag_retrans, | |
178 | + r->idiag_inode); | |
179 | + } | |
180 | + else | |
181 | + { /* ipv6 */ | |
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", | |
184 | + lnr, | |
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), | |
195 | + r->idiag_state, | |
196 | + r->idiag_wqueue, r->idiag_rqueue, | |
197 | + r->idiag_timer, | |
198 | + r->idiag_expires/10, // (diag reports as miliseconds, /proc interface stuck at centiseconds) | |
199 | + r->idiag_retrans, | |
200 | + r->idiag_uid, | |
201 | + r->idiag_retrans, | |
202 | + r->idiag_inode); | |
203 | + } | |
204 | + | |
03596bd7 | 205 | + tcp_do_one (++lnr, linebuf, r->idiag_family == AF_INET ? "tcp" : "tcp6"); |
3ada5ed8 ER |
206 | + } |
207 | + h = NLMSG_NEXT(h, status); | |
208 | + } | |
209 | + } | |
210 | + | |
211 | + | |
212 | + netlink_done: | |
213 | + if (fd >= 0) | |
214 | + close (fd); | |
215 | + return rv; | |
216 | +} | |
217 | +#endif | |
218 | + | |
219 | + | |
220 | static int tcp_info(void) | |
221 | { | |
222 | - INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)", | |
03596bd7 | 223 | - tcp_do_one, "tcp", "tcp6"); |
3ada5ed8 ER |
224 | + int rv = -1; |
225 | + | |
226 | +#ifdef HAVE_NETLINK | |
227 | + rv = tcp_netlink(); | |
228 | +#endif | |
229 | + | |
230 | + if (rv == -1) | |
231 | + { | |
232 | + // netlink is not available - so parse /proc/net/tcp | |
233 | + INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)", | |
03596bd7 | 234 | + tcp_do_one, "tcp", "tcp6"); |
3ada5ed8 ER |
235 | + } |
236 | + else if (rv == 0) | |
237 | + return 0; | |
238 | + | |
239 | + return -1; | |
240 | } | |
241 | + | |
242 | ||
581b2566 | 243 | static int notnull(const struct sockaddr_storage *sas) |
3ada5ed8 | 244 | { |