summaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-15 23:57:46 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-15 23:57:46 +0000
commit418a7fb29b19e42818b5df681c83b3bfc62db3c6 (patch)
tree2d52ed5b0dac5336e5e4c2f19321d6f6eaeb9206 /networking
parentc2b3e370d6b98ef37d48582d55b26794ac2bf63f (diff)
downloadbusybox-w32-418a7fb29b19e42818b5df681c83b3bfc62db3c6.tar.gz
busybox-w32-418a7fb29b19e42818b5df681c83b3bfc62db3c6.tar.bz2
busybox-w32-418a7fb29b19e42818b5df681c83b3bfc62db3c6.zip
netstat: introduce -W: wide, ipv6-friendly output
netstat: shrink by ~500 bytes (patch by Cristian Ionescu-Idbohrn <cristian.ionescu-idbohrn@axis.com>) netstat: fix for bogus state value for raw sockets
Diffstat (limited to 'networking')
-rw-r--r--networking/Config.in8
-rw-r--r--networking/netstat.c319
2 files changed, 161 insertions, 166 deletions
diff --git a/networking/Config.in b/networking/Config.in
index f389fe9d4..de62f4ebc 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -499,6 +499,14 @@ config NETSTAT
499 help 499 help
500 netstat prints information about the Linux networking subsystem. 500 netstat prints information about the Linux networking subsystem.
501 501
502config FEATURE_NETSTAT_WIDE
503 bool " Enable wide netstat output"
504 default n
505 depends on NETSTAT
506 help
507 Add support for wide columns. Useful when displaying IPv6 addresses
508 (-W option).
509
502config NSLOOKUP 510config NSLOOKUP
503 bool "nslookup" 511 bool "nslookup"
504 default n 512 default n
diff --git a/networking/netstat.c b/networking/netstat.c
index d89d3aa5a..3ba81cd24 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -14,6 +14,13 @@
14#include "busybox.h" 14#include "busybox.h"
15#include "inet_common.h" 15#include "inet_common.h"
16 16
17enum {
18 OPT_extended = 0x4,
19 OPT_showroute = 0x100,
20 OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE,
21};
22# define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")
23
17#define NETSTAT_CONNECTED 0x01 24#define NETSTAT_CONNECTED 0x01
18#define NETSTAT_LISTENING 0x02 25#define NETSTAT_LISTENING 0x02
19#define NETSTAT_NUMERIC 0x04 26#define NETSTAT_NUMERIC 0x04
@@ -24,7 +31,7 @@
24#define NETSTAT_UNIX 0x80 31#define NETSTAT_UNIX 0x80
25#define NETSTAT_ALLPROTO (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX) 32#define NETSTAT_ALLPROTO (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX)
26 33
27static int flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; 34static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO;
28 35
29enum { 36enum {
30 TCP_ESTABLISHED = 1, 37 TCP_ESTABLISHED = 1,
@@ -68,6 +75,51 @@ typedef enum {
68#define SO_WAITDATA (1<<17) /* wait data to read */ 75#define SO_WAITDATA (1<<17) /* wait data to read */
69#define SO_NOSPACE (1<<18) /* no space to write */ 76#define SO_NOSPACE (1<<18) /* no space to write */
70 77
78/* Standard printout size */
79#define PRINT_IP_MAX_SIZE 23
80#define PRINT_NET_CONN "%s %6ld %6ld %-23s %-23s %-12s\n"
81#define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State\n"
82
83/* When there are IPv6 connections the IPv6 addresses will be
84 * truncated to none-recognition. The '-W' option makes the
85 * address columns wide enough to accomodate for longest possible
86 * IPv6 addresses, i.e. addresses of the form
87 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd
88 */
89#define PRINT_IP_MAX_SIZE_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */
90#define PRINT_NET_CONN_WIDE "%s %6ld %6ld %-51s %-51s %-12s\n"
91#define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State\n"
92
93static const char *net_conn_line = PRINT_NET_CONN;
94
95
96#if ENABLE_FEATURE_IPV6
97static void build_ipv6_addr(char* local_addr, struct sockaddr_in6* localaddr)
98{
99 char addr6[INET6_ADDRSTRLEN];
100 struct in6_addr in6;
101
102 sscanf(local_addr, "%08X%08X%08X%08X",
103 &in6.s6_addr32[0], &in6.s6_addr32[1],
104 &in6.s6_addr32[2], &in6.s6_addr32[3]);
105 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
106 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr->sin6_addr);
107
108 localaddr->sin6_family = AF_INET6;
109}
110#endif
111
112#if ENABLE_FEATURE_IPV6
113static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr)
114#else
115static void build_ipv4_addr(char* local_addr, struct sockaddr_in* localaddr)
116#endif
117{
118 sscanf(local_addr, "%X",
119 &((struct sockaddr_in *) localaddr)->sin_addr.s_addr);
120 ((struct sockaddr *) localaddr)->sa_family = AF_INET;
121}
122
71static const char *get_sname(int port, const char *proto, int num) 123static const char *get_sname(int port, const char *proto, int num)
72{ 124{
73 /* hummm, we return static buffer here!! */ 125 /* hummm, we return static buffer here!! */
@@ -86,7 +138,10 @@ static const char *get_sname(int port, const char *proto, int num)
86static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, const char *proto, int numeric) 138static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, const char *proto, int numeric)
87{ 139{
88 const char *port_name; 140 const char *port_name;
141 int max_len;
142 int port_name_len;
89 143
144// TODO: replace by xmalloc_sockaddr2host?
90#if ENABLE_FEATURE_IPV6 145#if ENABLE_FEATURE_IPV6
91 if (addr->sa_family == AF_INET6) { 146 if (addr->sa_family == AF_INET6) {
92 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr, 147 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
@@ -99,23 +154,25 @@ static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int
99 0xffffffff); 154 0xffffffff);
100 } 155 }
101 port_name = get_sname(htons(port), proto, numeric); 156 port_name = get_sname(htons(port), proto, numeric);
102 if ((strlen(ip_port) + strlen(port_name)) > 22) 157
103 ip_port[22 - strlen(port_name)] = '\0'; 158 max_len = (option_mask32 & OPT_widedisplay)
159 ? (PRINT_IP_MAX_SIZE_WIDE - 1)
160 : (PRINT_IP_MAX_SIZE - 1);
161 port_name_len = strlen(port_name);
162 if ((strlen(ip_port) + port_name_len) > max_len)
163 ip_port[max_len - port_name_len] = '\0';
104 ip_port += strlen(ip_port); 164 ip_port += strlen(ip_port);
105 strcat(ip_port, ":"); 165 *ip_port++ = ':';
106 strcat(ip_port, port_name); 166 strcpy(ip_port, port_name);
107} 167}
108 168
109static void tcp_do_one(int lnr, const char *line) 169static void tcp_do_one(int lnr, const char *line)
110{ 170{
111 char local_addr[64], rem_addr[64]; 171 char local_addr[64], rem_addr[64];
112 const char *state_str;
113 char more[512]; 172 char more[512];
114 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 173 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
115#if ENABLE_FEATURE_IPV6 174#if ENABLE_FEATURE_IPV6
116 struct sockaddr_in6 localaddr, remaddr; 175 struct sockaddr_in6 localaddr, remaddr;
117 char addr6[INET6_ADDRSTRLEN];
118 struct in6_addr in6;
119#else 176#else
120 struct sockaddr_in localaddr, remaddr; 177 struct sockaddr_in localaddr, remaddr;
121#endif 178#endif
@@ -126,53 +183,37 @@ static void tcp_do_one(int lnr, const char *line)
126 183
127 more[0] = '\0'; 184 more[0] = '\0';
128 num = sscanf(line, 185 num = sscanf(line,
129 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 186 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
130 &d, local_addr, &local_port, 187 &d, local_addr, &local_port,
131 rem_addr, &rem_port, &state, 188 rem_addr, &rem_port, &state,
132 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 189 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
133 190
134 if (strlen(local_addr) > 8) { 191 if (strlen(local_addr) > 8) {
135#if ENABLE_FEATURE_IPV6 192#if ENABLE_FEATURE_IPV6
136 sscanf(local_addr, "%08X%08X%08X%08X", 193 build_ipv6_addr(local_addr, &localaddr);
137 &in6.s6_addr32[0], &in6.s6_addr32[1], 194 build_ipv6_addr(rem_addr, &remaddr);
138 &in6.s6_addr32[2], &in6.s6_addr32[3]);
139 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
140 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
141 sscanf(rem_addr, "%08X%08X%08X%08X",
142 &in6.s6_addr32[0], &in6.s6_addr32[1],
143 &in6.s6_addr32[2], &in6.s6_addr32[3]);
144 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
145 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
146 localaddr.sin6_family = AF_INET6;
147 remaddr.sin6_family = AF_INET6;
148#endif 195#endif
149 } else { 196 } else {
150 sscanf(local_addr, "%X", 197 build_ipv4_addr(local_addr, &localaddr);
151 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 198 build_ipv4_addr(rem_addr, &remaddr);
152 sscanf(rem_addr, "%X",
153 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
154 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
155 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
156 } 199 }
157 200
158 if (num < 10) { 201 if (num < 10) {
159 bb_error_msg("warning, got bogus tcp line"); 202 bb_error_msg("warning, got bogus tcp line");
160 return; 203 return;
161 } 204 }
162 state_str = tcp_state[state]; 205
163 if ((rem_port && (flags & NETSTAT_CONNECTED)) 206 if ((rem_port && (flags & NETSTAT_CONNECTED))
164 || (!rem_port && (flags & NETSTAT_LISTENING)) 207 || (!rem_port && (flags & NETSTAT_LISTENING))
165 ) { 208 ) {
166 snprint_ip_port(local_addr, sizeof(local_addr), 209 snprint_ip_port(local_addr, sizeof(local_addr),
167 (struct sockaddr *) &localaddr, local_port, 210 (struct sockaddr *) &localaddr, local_port,
168 "tcp", flags & NETSTAT_NUMERIC); 211 "tcp", flags & NETSTAT_NUMERIC);
169
170 snprint_ip_port(rem_addr, sizeof(rem_addr), 212 snprint_ip_port(rem_addr, sizeof(rem_addr),
171 (struct sockaddr *) &remaddr, rem_port, 213 (struct sockaddr *) &remaddr, rem_port,
172 "tcp", flags & NETSTAT_NUMERIC); 214 "tcp", flags & NETSTAT_NUMERIC);
173 215 printf(net_conn_line,
174 printf("tcp %6ld %6ld %-23s %-23s %-12s\n", 216 "tcp", rxq, txq, local_addr, rem_addr, tcp_state[state]);
175 rxq, txq, local_addr, rem_addr, state_str);
176 } 217 }
177} 218}
178 219
@@ -184,8 +225,6 @@ static void udp_do_one(int lnr, const char *line)
184 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 225 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
185#if ENABLE_FEATURE_IPV6 226#if ENABLE_FEATURE_IPV6
186 struct sockaddr_in6 localaddr, remaddr; 227 struct sockaddr_in6 localaddr, remaddr;
187 char addr6[INET6_ADDRSTRLEN];
188 struct in6_addr in6;
189#else 228#else
190 struct sockaddr_in localaddr, remaddr; 229 struct sockaddr_in localaddr, remaddr;
191#endif 230#endif
@@ -196,34 +235,20 @@ static void udp_do_one(int lnr, const char *line)
196 235
197 more[0] = '\0'; 236 more[0] = '\0';
198 num = sscanf(line, 237 num = sscanf(line,
199 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 238 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
200 &d, local_addr, &local_port, 239 &d, local_addr, &local_port,
201 rem_addr, &rem_port, &state, 240 rem_addr, &rem_port, &state,
202 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 241 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
203 242
204 if (strlen(local_addr) > 8) { 243 if (strlen(local_addr) > 8) {
205#if ENABLE_FEATURE_IPV6 244#if ENABLE_FEATURE_IPV6
206 /* Demangle what the kernel gives us */ 245 /* Demangle what the kernel gives us */
207 sscanf(local_addr, "%08X%08X%08X%08X", 246 build_ipv6_addr(local_addr, &localaddr);
208 &in6.s6_addr32[0], &in6.s6_addr32[1], 247 build_ipv6_addr(rem_addr, &remaddr);
209 &in6.s6_addr32[2], &in6.s6_addr32[3]);
210 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
211 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
212 sscanf(rem_addr, "%08X%08X%08X%08X",
213 &in6.s6_addr32[0], &in6.s6_addr32[1],
214 &in6.s6_addr32[2], &in6.s6_addr32[3]);
215 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
216 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
217 localaddr.sin6_family = AF_INET6;
218 remaddr.sin6_family = AF_INET6;
219#endif 248#endif
220 } else { 249 } else {
221 sscanf(local_addr, "%X", 250 build_ipv4_addr(local_addr, &localaddr);
222 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 251 build_ipv4_addr(rem_addr, &remaddr);
223 sscanf(rem_addr, "%X",
224 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
225 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
226 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
227 } 252 }
228 253
229 if (num < 10) { 254 if (num < 10) {
@@ -234,52 +259,51 @@ static void udp_do_one(int lnr, const char *line)
234 case TCP_ESTABLISHED: 259 case TCP_ESTABLISHED:
235 state_str = "ESTABLISHED"; 260 state_str = "ESTABLISHED";
236 break; 261 break;
237
238 case TCP_CLOSE: 262 case TCP_CLOSE:
239 state_str = ""; 263 state_str = "";
240 break; 264 break;
241
242 default: 265 default:
243 state_str = "UNKNOWN"; 266 state_str = "UNKNOWN";
244 break; 267 break;
245 } 268 }
246 269
247#if ENABLE_FEATURE_IPV6 270#if ENABLE_FEATURE_IPV6
248# define notnull(A) (((A.sin6_family == AF_INET6) && \ 271# define notnull(A) ( \
249 ((A.sin6_addr.s6_addr32[0]) || \ 272 ( (A.sin6_family == AF_INET6) \
250 (A.sin6_addr.s6_addr32[1]) || \ 273 && (A.sin6_addr.s6_addr32[0] | A.sin6_addr.s6_addr32[1] | \
251 (A.sin6_addr.s6_addr32[2]) || \ 274 A.sin6_addr.s6_addr32[2] | A.sin6_addr.s6_addr32[3]) \
252 (A.sin6_addr.s6_addr32[3]))) || \ 275 ) || ( \
253 ((A.sin6_family == AF_INET) && \ 276 (A.sin6_family == AF_INET) \
254 ((struct sockaddr_in *) &A)->sin_addr.s_addr)) 277 && ((struct sockaddr_in*)&A)->sin_addr.s_addr \
278 ) \
279)
255#else 280#else
256# define notnull(A) (A.sin_addr.s_addr) 281# define notnull(A) (A.sin_addr.s_addr)
257#endif 282#endif
258 if ((notnull(remaddr) && (flags & NETSTAT_CONNECTED)) 283 {
259 || (!notnull(remaddr) && (flags & NETSTAT_LISTENING)) 284 int have_remaddr = notnull(remaddr);
260 ) { 285 if ((have_remaddr && (flags & NETSTAT_CONNECTED))
261 snprint_ip_port(local_addr, sizeof(local_addr), 286 || (!have_remaddr && (flags & NETSTAT_LISTENING))
262 (struct sockaddr *) &localaddr, local_port, 287 ) {
263 "udp", flags & NETSTAT_NUMERIC); 288 snprint_ip_port(local_addr, sizeof(local_addr),
264 289 (struct sockaddr *) &localaddr, local_port,
265 snprint_ip_port(rem_addr, sizeof(rem_addr), 290 "udp", flags & NETSTAT_NUMERIC);
266 (struct sockaddr *) &remaddr, rem_port, 291 snprint_ip_port(rem_addr, sizeof(rem_addr),
267 "udp", flags & NETSTAT_NUMERIC); 292 (struct sockaddr *) &remaddr, rem_port,
268 293 "udp", flags & NETSTAT_NUMERIC);
269 printf("udp %6ld %6ld %-23s %-23s %-12s\n", 294 printf(net_conn_line,
270 rxq, txq, local_addr, rem_addr, state_str); 295 "udp", rxq, txq, local_addr, rem_addr, state_str);
296 }
271 } 297 }
272} 298}
273 299
274static void raw_do_one(int lnr, const char *line) 300static void raw_do_one(int lnr, const char *line)
275{ 301{
276 char local_addr[64], rem_addr[64]; 302 char local_addr[64], rem_addr[64];
277 char *state_str, more[512]; 303 char more[512];
278 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 304 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
279#if ENABLE_FEATURE_IPV6 305#if ENABLE_FEATURE_IPV6
280 struct sockaddr_in6 localaddr, remaddr; 306 struct sockaddr_in6 localaddr, remaddr;
281 char addr6[INET6_ADDRSTRLEN];
282 struct in6_addr in6;
283#else 307#else
284 struct sockaddr_in localaddr, remaddr; 308 struct sockaddr_in localaddr, remaddr;
285#endif 309#endif
@@ -290,73 +314,47 @@ static void raw_do_one(int lnr, const char *line)
290 314
291 more[0] = '\0'; 315 more[0] = '\0';
292 num = sscanf(line, 316 num = sscanf(line,
293 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 317 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
294 &d, local_addr, &local_port, 318 &d, local_addr, &local_port,
295 rem_addr, &rem_port, &state, 319 rem_addr, &rem_port, &state,
296 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 320 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
297 321
298 if (strlen(local_addr) > 8) { 322 if (strlen(local_addr) > 8) {
299#if ENABLE_FEATURE_IPV6 323#if ENABLE_FEATURE_IPV6
300 sscanf(local_addr, "%08X%08X%08X%08X", 324 build_ipv6_addr(local_addr, &localaddr);
301 &in6.s6_addr32[0], &in6.s6_addr32[1], 325 build_ipv6_addr(rem_addr, &remaddr);
302 &in6.s6_addr32[2], &in6.s6_addr32[3]);
303 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
304 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
305 sscanf(rem_addr, "%08X%08X%08X%08X",
306 &in6.s6_addr32[0], &in6.s6_addr32[1],
307 &in6.s6_addr32[2], &in6.s6_addr32[3]);
308 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
309 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
310 localaddr.sin6_family = AF_INET6;
311 remaddr.sin6_family = AF_INET6;
312#endif 326#endif
313 } else { 327 } else {
314 sscanf(local_addr, "%X", 328 build_ipv4_addr(local_addr, &localaddr);
315 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 329 build_ipv4_addr(rem_addr, &remaddr);
316 sscanf(rem_addr, "%X",
317 &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
318 ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
319 ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
320 } 330 }
321 331
322 if (num < 10) { 332 if (num < 10) {
323 bb_error_msg("warning, got bogus raw line"); 333 bb_error_msg("warning, got bogus raw line");
324 return; 334 return;
325 } 335 }
326 state_str = itoa(state);
327 336
328#if ENABLE_FEATURE_IPV6 337 {
329# define notnull(A) (((A.sin6_family == AF_INET6) && \ 338 int have_remaddr = notnull(remaddr);
330 ((A.sin6_addr.s6_addr32[0]) || \ 339 if ((have_remaddr && (flags & NETSTAT_CONNECTED))
331 (A.sin6_addr.s6_addr32[1]) || \ 340 || (!have_remaddr && (flags & NETSTAT_LISTENING))
332 (A.sin6_addr.s6_addr32[2]) || \ 341 ) {
333 (A.sin6_addr.s6_addr32[3]))) || \ 342 snprint_ip_port(local_addr, sizeof(local_addr),
334 ((A.sin6_family == AF_INET) && \ 343 (struct sockaddr *) &localaddr, local_port,
335 ((struct sockaddr_in *) &A)->sin_addr.s_addr)) 344 "raw", flags & NETSTAT_NUMERIC);
336#else 345 snprint_ip_port(rem_addr, sizeof(rem_addr),
337# define notnull(A) (A.sin_addr.s_addr) 346 (struct sockaddr *) &remaddr, rem_port,
338#endif 347 "raw", flags & NETSTAT_NUMERIC);
339 if ((notnull(remaddr) && (flags & NETSTAT_CONNECTED)) 348 printf(net_conn_line,
340 || (!notnull(remaddr) && (flags & NETSTAT_LISTENING)) 349 "raw", rxq, txq, local_addr, rem_addr, itoa(state));
341 ) { 350 }
342 snprint_ip_port(local_addr, sizeof(local_addr),
343 (struct sockaddr *) &localaddr, local_port,
344 "raw", flags & NETSTAT_NUMERIC);
345
346 snprint_ip_port(rem_addr, sizeof(rem_addr),
347 (struct sockaddr *) &remaddr, rem_port,
348 "raw", flags & NETSTAT_NUMERIC);
349
350 printf("raw %6ld %6ld %-23s %-23s %-12s\n",
351 rxq, txq, local_addr, rem_addr, state_str);
352 } 351 }
353} 352}
354 353
355#define HAS_INODE 1
356
357static void unix_do_one(int nr, const char *line) 354static void unix_do_one(int nr, const char *line)
358{ 355{
359 static int has = 0; 356 static smallint has_inode = 0;
357
360 char path[PATH_MAX], ss_flags[32]; 358 char path[PATH_MAX], ss_flags[32];
361 const char *ss_proto, *ss_state, *ss_type; 359 const char *ss_proto, *ss_state, *ss_type;
362 int num, state, type, inode; 360 int num, state, type, inode;
@@ -365,18 +363,18 @@ static void unix_do_one(int nr, const char *line)
365 363
366 if (nr == 0) { 364 if (nr == 0) {
367 if (strstr(line, "Inode")) 365 if (strstr(line, "Inode"))
368 has |= HAS_INODE; 366 has_inode = 1;
369 return; 367 return;
370 } 368 }
371 path[0] = '\0'; 369 path[0] = '\0';
372 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s", 370 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
373 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path); 371 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
374 if (num < 6) { 372 if (num < 6) {
375 bb_error_msg("warning, got bogus unix line"); 373 bb_error_msg("warning, got bogus unix line");
376 return; 374 return;
377 } 375 }
378 if (!(has & HAS_INODE)) 376 if (!has_inode)
379 snprintf(path,sizeof(path),"%d",inode); 377 sprintf(path, "%d", inode);
380 378
381 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) { 379 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
382 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) { 380 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
@@ -392,7 +390,6 @@ static void unix_do_one(int nr, const char *line)
392 case 0: 390 case 0:
393 ss_proto = "unix"; 391 ss_proto = "unix";
394 break; 392 break;
395
396 default: 393 default:
397 ss_proto = "??"; 394 ss_proto = "??";
398 } 395 }
@@ -401,23 +398,18 @@ static void unix_do_one(int nr, const char *line)
401 case SOCK_STREAM: 398 case SOCK_STREAM:
402 ss_type = "STREAM"; 399 ss_type = "STREAM";
403 break; 400 break;
404
405 case SOCK_DGRAM: 401 case SOCK_DGRAM:
406 ss_type = "DGRAM"; 402 ss_type = "DGRAM";
407 break; 403 break;
408
409 case SOCK_RAW: 404 case SOCK_RAW:
410 ss_type = "RAW"; 405 ss_type = "RAW";
411 break; 406 break;
412
413 case SOCK_RDM: 407 case SOCK_RDM:
414 ss_type = "RDM"; 408 ss_type = "RDM";
415 break; 409 break;
416
417 case SOCK_SEQPACKET: 410 case SOCK_SEQPACKET:
418 ss_type = "SEQPACKET"; 411 ss_type = "SEQPACKET";
419 break; 412 break;
420
421 default: 413 default:
422 ss_type = "UNKNOWN"; 414 ss_type = "UNKNOWN";
423 } 415 }
@@ -426,7 +418,6 @@ static void unix_do_one(int nr, const char *line)
426 case SS_FREE: 418 case SS_FREE:
427 ss_state = "FREE"; 419 ss_state = "FREE";
428 break; 420 break;
429
430 case SS_UNCONNECTED: 421 case SS_UNCONNECTED:
431 /* 422 /*
432 * Unconnected sockets may be listening 423 * Unconnected sockets may be listening
@@ -438,19 +429,15 @@ static void unix_do_one(int nr, const char *line)
438 ss_state = ""; 429 ss_state = "";
439 } 430 }
440 break; 431 break;
441
442 case SS_CONNECTING: 432 case SS_CONNECTING:
443 ss_state = "CONNECTING"; 433 ss_state = "CONNECTING";
444 break; 434 break;
445
446 case SS_CONNECTED: 435 case SS_CONNECTED:
447 ss_state = "CONNECTED"; 436 ss_state = "CONNECTED";
448 break; 437 break;
449
450 case SS_DISCONNECTING: 438 case SS_DISCONNECTING:
451 ss_state = "DISCONNECTING"; 439 ss_state = "DISCONNECTING";
452 break; 440 break;
453
454 default: 441 default:
455 ss_state = "UNKNOWN"; 442 ss_state = "UNKNOWN";
456 } 443 }
@@ -462,13 +449,12 @@ static void unix_do_one(int nr, const char *line)
462 strcat(ss_flags, "W "); 449 strcat(ss_flags, "W ");
463 if (unix_flags & SO_NOSPACE) 450 if (unix_flags & SO_NOSPACE)
464 strcat(ss_flags, "N "); 451 strcat(ss_flags, "N ");
465
466 strcat(ss_flags, "]"); 452 strcat(ss_flags, "]");
467 453
468 printf("%-5s %-6ld %-11s %-10s %-13s ", 454 printf("%-5s %-6ld %-11s %-10s %-13s ",
469 ss_proto, refcnt, ss_flags, ss_type, ss_state); 455 ss_proto, refcnt, ss_flags, ss_type, ss_state);
470 if (has & HAS_INODE) 456 if (has_inode)
471 printf("%-6d ",inode); 457 printf("%-6d ", inode);
472 else 458 else
473 printf("- "); 459 printf("- ");
474 puts(path); 460 puts(path);
@@ -513,20 +499,16 @@ static void do_info(const char *file, const char *name, void (*proc)(int, const
513int netstat_main(int argc, char **argv); 499int netstat_main(int argc, char **argv);
514int netstat_main(int argc, char **argv) 500int netstat_main(int argc, char **argv)
515{ 501{
516 enum {
517 OPT_extended = 0x4,
518 OPT_showroute = 0x100,
519 };
520 unsigned opt; 502 unsigned opt;
521#if ENABLE_FEATURE_IPV6 503#if ENABLE_FEATURE_IPV6
522 int inet = 1; 504 smallint inet = 1;
523 int inet6 = 1; 505 smallint inet6 = 1;
524#else 506#else
525 enum { inet = 1, inet6 = 0 }; 507 enum { inet = 1, inet6 = 0 };
526#endif 508#endif
527 509
528 /* Option string must match NETSTAT_xxx constants */ 510 /* Option string must match NETSTAT_xxx constants */
529 opt = getopt32(argc, argv, "laentuwxr"); 511 opt = getopt32(argc, argv, NETSTAT_OPTS);
530 if (opt & 0x1) { // -l 512 if (opt & 0x1) { // -l
531 flags &= ~NETSTAT_CONNECTED; 513 flags &= ~NETSTAT_CONNECTED;
532 flags |= NETSTAT_LISTENING; 514 flags |= NETSTAT_LISTENING;
@@ -543,10 +525,14 @@ int netstat_main(int argc, char **argv)
543 bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); 525 bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended));
544 return 0; 526 return 0;
545#else 527#else
546 bb_error_msg_and_die("-r (display routing table) is not compiled in"); 528 bb_show_usage();
547#endif 529#endif
548 } 530 }
549 531
532 if (opt & OPT_widedisplay) { // -W
533 net_conn_line = PRINT_NET_CONN_WIDE;
534 }
535
550 opt &= NETSTAT_ALLPROTO; 536 opt &= NETSTAT_ALLPROTO;
551 if (opt) { 537 if (opt) {
552 flags &= ~NETSTAT_ALLPROTO; 538 flags &= ~NETSTAT_ALLPROTO;
@@ -561,7 +547,8 @@ int netstat_main(int argc, char **argv)
561 printf("(only servers)"); 547 printf("(only servers)");
562 else 548 else
563 printf("(w/o servers)"); 549 printf("(w/o servers)");
564 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State\n"); 550 printf((opt & OPT_widedisplay) ? PRINT_NET_CONN_HEADER_WIDE : PRINT_NET_CONN_HEADER,
551 "Local Address", "Foreign Address");
565 } 552 }
566 if (inet && flags & NETSTAT_TCP) 553 if (inet && flags & NETSTAT_TCP)
567 do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one); 554 do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one);