diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-15 23:57:46 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-15 23:57:46 +0000 |
commit | 418a7fb29b19e42818b5df681c83b3bfc62db3c6 (patch) | |
tree | 2d52ed5b0dac5336e5e4c2f19321d6f6eaeb9206 /networking | |
parent | c2b3e370d6b98ef37d48582d55b26794ac2bf63f (diff) | |
download | busybox-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.in | 8 | ||||
-rw-r--r-- | networking/netstat.c | 319 |
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 | ||
502 | config 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 | |||
502 | config NSLOOKUP | 510 | config 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 | ||
17 | enum { | ||
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 | ||
27 | static int flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; | 34 | static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; |
28 | 35 | ||
29 | enum { | 36 | enum { |
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 | |||
93 | static const char *net_conn_line = PRINT_NET_CONN; | ||
94 | |||
95 | |||
96 | #if ENABLE_FEATURE_IPV6 | ||
97 | static 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 | ||
113 | static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr) | ||
114 | #else | ||
115 | static 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 | |||
71 | static const char *get_sname(int port, const char *proto, int num) | 123 | static 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) | |||
86 | static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, const char *proto, int numeric) | 138 | static 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 | ||
109 | static void tcp_do_one(int lnr, const char *line) | 169 | static 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 | ||
274 | static void raw_do_one(int lnr, const char *line) | 300 | static 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 | |||
357 | static void unix_do_one(int nr, const char *line) | 354 | static 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 | |||
513 | int netstat_main(int argc, char **argv); | 499 | int netstat_main(int argc, char **argv); |
514 | int netstat_main(int argc, char **argv) | 500 | int 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); |