]>
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 | |
7 | diff -c -d -u -r1.55 netstat.c | |
8 | --- netstat.c 1 Dec 2007 19:00:40 -0000 1.55 | |
9 | +++ netstat.c 20 Feb 2008 23:04:29 -0000 | |
10 | @@ -96,6 +96,13 @@ | |
11 | #include "util.h" | |
12 | #include "proc.h" | |
13 | ||
14 | +#ifdef HAVE_NETLINK | |
15 | +#include <asm/types.h> | |
16 | +#include <linux/netlink.h> | |
17 | +#include <linux/inet_diag.h> | |
18 | +#endif | |
19 | + | |
20 | + | |
21 | #define PROGNAME_WIDTH 20 | |
22 | ||
23 | #if !defined(s6_addr32) && defined(in6a_words) | |
24 | @@ -828,11 +835,194 @@ | |
25 | } | |
26 | } | |
27 | ||
28 | + | |
29 | + | |
30 | +#ifdef HAVE_NETLINK | |
31 | +int tcp_netlink() | |
32 | +{ | |
33 | + /* a newer alternative to /proc/net/tcp[6] - using NETLINK DIAG | |
34 | + runs much faster with large number of entries | |
35 | + essentially just a bridge - converts from DIAG to /proc/net/tcp format | |
36 | + largely taken directly from ss of iproute package | |
37 | + | |
38 | + returns -1 if NETLINK isn't available, in which case the old /proc/net/tcp code is run | |
39 | + */ | |
40 | + | |
41 | + int fd; | |
42 | + struct sockaddr_nl nladdr; | |
43 | + struct { | |
44 | + struct nlmsghdr nlh; | |
45 | + struct inet_diag_req r; | |
46 | + } req; | |
47 | + struct msghdr msg; | |
48 | + char buf[8192]; | |
49 | + char linebuf[8192]; | |
50 | + struct iovec iov; | |
51 | + int lnr = 0; | |
52 | + struct inet_diag_msg *r; | |
53 | + int rv = 0; | |
54 | + | |
55 | + if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0) | |
56 | + return -1; | |
57 | + | |
58 | + memset(&nladdr, 0, sizeof(nladdr)); | |
59 | + nladdr.nl_family = AF_NETLINK; | |
60 | + | |
61 | + req.nlh.nlmsg_len = sizeof(req); | |
62 | + req.nlh.nlmsg_type = TCPDIAG_GETSOCK; | |
63 | + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; | |
64 | + req.nlh.nlmsg_pid = 0; | |
65 | + req.nlh.nlmsg_seq = 123456; | |
66 | + memset(&req.r, 0, sizeof(req.r)); | |
67 | + req.r.idiag_family = AF_INET; | |
68 | + req.r.idiag_states = 0xfff; | |
69 | + req.r.idiag_ext = 0; | |
70 | + | |
71 | + iov.iov_base = &req; | |
72 | + iov.iov_len = sizeof(req); | |
73 | + | |
74 | + msg = (struct msghdr) { | |
75 | + .msg_name = (void*)&nladdr, | |
76 | + .msg_namelen = sizeof(nladdr), | |
77 | + .msg_iov = &iov, | |
78 | + .msg_iovlen = 1, | |
79 | + }; | |
80 | + | |
81 | + if (sendmsg(fd, &msg, 0) < 0) | |
82 | + { | |
83 | + rv = -1; | |
84 | + goto netlink_done; | |
85 | + } | |
86 | + | |
87 | + iov.iov_base = buf; | |
88 | + iov.iov_len = sizeof(buf); | |
89 | + | |
90 | + while (1) | |
91 | + { | |
92 | + int status; | |
93 | + struct nlmsghdr *h; | |
94 | + | |
95 | + msg = (struct msghdr) { | |
96 | + (void*)&nladdr, sizeof(nladdr), | |
97 | + &iov, 1, | |
98 | + NULL, 0, | |
99 | + 0 | |
100 | + }; | |
101 | + | |
102 | + status = recvmsg(fd, &msg, 0); | |
103 | + | |
104 | + if (status < 0) | |
105 | + { | |
106 | + if (errno == EINTR) | |
107 | + continue; | |
108 | + rv = -2; | |
109 | + goto netlink_done; | |
110 | + } | |
111 | + | |
112 | + if (status == 0) | |
113 | + { | |
114 | + rv = 0; | |
115 | + goto netlink_done; | |
116 | + } | |
117 | + | |
118 | + | |
119 | + h = (struct nlmsghdr*)buf; | |
120 | + while (NLMSG_OK(h, status)) | |
121 | + { | |
122 | + if (h->nlmsg_seq == 123456) | |
123 | + { | |
124 | + if (h->nlmsg_type == NLMSG_DONE) | |
125 | + { | |
126 | + rv = 0; | |
127 | + goto netlink_done; | |
128 | + } | |
129 | + | |
130 | + if (h->nlmsg_type == NLMSG_ERROR) | |
131 | + { | |
132 | + rv = -2; | |
133 | + goto netlink_done; | |
134 | + } | |
135 | + | |
136 | + r = NLMSG_DATA(h); | |
137 | + | |
138 | + if (r->idiag_family == AF_INET) | |
139 | + { | |
140 | + snprintf (linebuf,8192, | |
141 | + "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08X %08X %5d %8d %d", | |
142 | + lnr, | |
143 | + r->id.idiag_src[0], | |
144 | + ntohs(r->id.idiag_sport), | |
145 | + r->id.idiag_dst[0], | |
146 | + ntohs(r->id.idiag_dport), | |
147 | + r->idiag_state, | |
148 | + r->idiag_wqueue, r->idiag_rqueue, | |
149 | + r->idiag_timer, | |
150 | + r->idiag_expires/10, // (diag reports as miliseconds, /proc interface stuck at centiseconds) | |
151 | + r->idiag_retrans, | |
152 | + r->idiag_uid, | |
153 | + r->idiag_retrans, | |
154 | + r->idiag_inode); | |
155 | + } | |
156 | + else | |
157 | + { /* ipv6 */ | |
158 | + snprintf (linebuf,8192, | |
159 | + "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X %02X %08X:%08X %02X:%08X %08X %5d %8d %d", | |
160 | + lnr, | |
161 | + r->id.idiag_src[0], | |
162 | + r->id.idiag_src[1], | |
163 | + r->id.idiag_src[2], | |
164 | + r->id.idiag_src[3], | |
165 | + ntohs(r->id.idiag_sport), | |
166 | + r->id.idiag_dst[0], | |
167 | + r->id.idiag_dst[1], | |
168 | + r->id.idiag_dst[2], | |
169 | + r->id.idiag_dst[3], | |
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 | + | |
181 | + tcp_do_one (++lnr, linebuf); | |
182 | + } | |
183 | + h = NLMSG_NEXT(h, status); | |
184 | + } | |
185 | + } | |
186 | + | |
187 | + | |
188 | + netlink_done: | |
189 | + if (fd >= 0) | |
190 | + close (fd); | |
191 | + return rv; | |
192 | +} | |
193 | +#endif | |
194 | + | |
195 | + | |
196 | static int tcp_info(void) | |
197 | { | |
198 | - INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)", | |
199 | - tcp_do_one); | |
200 | + int rv = -1; | |
201 | + | |
202 | +#ifdef HAVE_NETLINK | |
203 | + rv = tcp_netlink(); | |
204 | +#endif | |
205 | + | |
206 | + if (rv == -1) | |
207 | + { | |
208 | + // netlink is not available - so parse /proc/net/tcp | |
209 | + INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)", | |
210 | + tcp_do_one); | |
211 | + } | |
212 | + else if (rv == 0) | |
213 | + return 0; | |
214 | + | |
215 | + return -1; | |
216 | } | |
217 | + | |
218 | ||
219 | static void udp_do_one(int lnr, const char *line) | |
220 | { | |
221 | --- config.in~ 2009-03-10 04:37:40.000000000 +0200 | |
222 | +++ config.in 2009-03-10 04:38:14.092903210 +0200 | |
223 | @@ -89,3 +89,4 @@ | |
224 | bool 'IP Masquerading support' HAVE_FW_MASQUERADE n | |
225 | bool 'Build iptunnel and ipmaddr' HAVE_IP_TOOLS n | |
226 | bool 'Build mii-tool' HAVE_MII n | |
227 | +bool 'Use Netlink Diag' HAVE_NETLINK y | |
228 | --- config.h~ 2009-03-10 04:49:18.000000000 +0200 | |
229 | +++ config.h 2009-03-10 04:49:55.762832175 +0200 | |
230 | @@ -72,3 +72,4 @@ | |
231 | #define HAVE_FW_MASQUERADE 1 | |
232 | #define HAVE_IP_TOOLS 0 | |
233 | #define HAVE_MII 1 | |
234 | +#define HAVE_NETLINK 1 | |
235 | --- config.make~ 2009-03-10 04:49:18.000000000 +0200 | |
236 | +++ config.make 2009-03-10 04:50:19.880072014 +0200 | |
237 | @@ -33,3 +33,4 @@ | |
238 | # HAVE_FW_MASQUERADE=1 | |
239 | # HAVE_IP_TOOLS=0 | |
240 | HAVE_MII=1 | |
241 | +HAVE_NETLINK=1 |