Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking/netstat.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/networking/netstat.c
r1765 r2725 9 9 * IPV6 support added by Bart Visscher <magick@linux-fan.com> 10 10 * 11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 11 * 2008-07-10 12 * optional '-p' flag support ported from net-tools by G. Somlo <somlo@cmu.edu> 13 * 14 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 12 15 */ 13 16 … … 15 18 #include "inet_common.h" 16 19 20 //usage:#define netstat_trivial_usage 21 //usage: "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" 22 //usage:#define netstat_full_usage "\n\n" 23 //usage: "Display networking information\n" 24 //usage: "\nOptions:" 25 //usage: IF_ROUTE( 26 //usage: "\n -r Routing table" 27 //usage: ) 28 //usage: "\n -a All sockets" 29 //usage: "\n -l Listening sockets" 30 //usage: "\n Else: connected sockets" 31 //usage: "\n -t TCP sockets" 32 //usage: "\n -u UDP sockets" 33 //usage: "\n -w Raw sockets" 34 //usage: "\n -x Unix sockets" 35 //usage: "\n Else: all socket types" 36 //usage: "\n -e Other/more information" 37 //usage: "\n -n Don't resolve names" 38 //usage: IF_FEATURE_NETSTAT_WIDE( 39 //usage: "\n -W Wide display" 40 //usage: ) 41 //usage: IF_FEATURE_NETSTAT_PRG( 42 //usage: "\n -p Show PID/program name for sockets" 43 //usage: ) 44 45 #define NETSTAT_OPTS "laentuwx" \ 46 IF_ROUTE( "r") \ 47 IF_FEATURE_NETSTAT_WIDE("W") \ 48 IF_FEATURE_NETSTAT_PRG( "p") 49 17 50 enum { 18 OPT_extended = 0x4, 19 OPT_showroute = 0x100, 20 OPT_widedisplay = 0x200 * ENABLE_FEATURE_NETSTAT_WIDE, 51 OPT_sock_listen = 1 << 0, // l 52 OPT_sock_all = 1 << 1, // a 53 OPT_extended = 1 << 2, // e 54 OPT_noresolve = 1 << 3, // n 55 OPT_sock_tcp = 1 << 4, // t 56 OPT_sock_udp = 1 << 5, // u 57 OPT_sock_raw = 1 << 6, // w 58 OPT_sock_unix = 1 << 7, // x 59 OPTBIT_x = 7, 60 IF_ROUTE( OPTBIT_ROUTE,) 61 IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) 62 IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG ,) 63 OPT_route = IF_ROUTE( (1 << OPTBIT_ROUTE)) + 0, // r 64 OPT_wide = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W 65 OPT_prg = IF_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG )) + 0, // p 21 66 }; 22 # define NETSTAT_OPTS "laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")23 67 24 68 #define NETSTAT_CONNECTED 0x01 … … 32 76 #define NETSTAT_ALLPROTO (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX) 33 77 34 static smallint flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO;35 78 36 79 enum { … … 45 88 TCP_LAST_ACK, 46 89 TCP_LISTEN, 47 TCP_CLOSING /* now a valid state */90 TCP_CLOSING, /* now a valid state */ 48 91 }; 49 92 … … 71 114 } socket_state; 72 115 73 #define SO_ACCEPTCON (1<<16) /* performed a listen */ 74 #define SO_WAITDATA (1<<17) /* wait data to read */ 75 #define SO_NOSPACE (1<<18) /* no space to write */ 76 77 /* Standard printout size */ 78 #define PRINT_IP_MAX_SIZE 23 79 #define PRINT_NET_CONN "%s %6ld %6ld %-23s %-23s %-12s\n" 80 #define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State\n" 81 116 #define SO_ACCEPTCON (1<<16) /* performed a listen */ 117 #define SO_WAITDATA (1<<17) /* wait data to read */ 118 #define SO_NOSPACE (1<<18) /* no space to write */ 119 120 #define ADDR_NORMAL_WIDTH 23 82 121 /* When there are IPv6 connections the IPv6 addresses will be 83 122 * truncated to none-recognition. The '-W' option makes the … … 86 125 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd 87 126 */ 88 #define PRINT_IP_MAX_SIZE_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ 89 #define PRINT_NET_CONN_WIDE "%s %6ld %6ld %-51s %-51s %-12s\n" 90 #define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State\n" 91 92 static const char *net_conn_line = PRINT_NET_CONN; 127 #define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ 128 #if ENABLE_FEATURE_NETSTAT_WIDE 129 # define FMT_NET_CONN_DATA "%s %6ld %6ld %-*s %-*s %-12s" 130 # define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-*s %-*s State %s\n" 131 #else 132 # define FMT_NET_CONN_DATA "%s %6ld %6ld %-23s %-23s %-12s" 133 # define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State %s\n" 134 #endif 135 136 #define PROGNAME_WIDTH 20 137 #define PROGNAME_WIDTH_STR "20" 138 /* PROGNAME_WIDTH chars: 12345678901234567890 */ 139 #define PROGNAME_BANNER "PID/Program name " 140 141 struct prg_node { 142 struct prg_node *next; 143 long inode; 144 char name[PROGNAME_WIDTH]; 145 }; 146 147 #define PRG_HASH_SIZE 211 148 149 struct globals { 150 smallint flags; 151 #if ENABLE_FEATURE_NETSTAT_PRG 152 smallint prg_cache_loaded; 153 struct prg_node *prg_hash[PRG_HASH_SIZE]; 154 #endif 155 #if ENABLE_FEATURE_NETSTAT_PRG 156 const char *progname_banner; 157 #endif 158 #if ENABLE_FEATURE_NETSTAT_WIDE 159 unsigned addr_width; 160 #endif 161 }; 162 #define G (*ptr_to_globals) 163 #define flags (G.flags ) 164 #define prg_cache_loaded (G.prg_cache_loaded) 165 #define prg_hash (G.prg_hash ) 166 #if ENABLE_FEATURE_NETSTAT_PRG 167 # define progname_banner (G.progname_banner ) 168 #else 169 # define progname_banner "" 170 #endif 171 #define INIT_G() do { \ 172 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 173 flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ 174 } while (0) 175 176 177 #if ENABLE_FEATURE_NETSTAT_PRG 178 179 /* Deliberately truncating long to unsigned *int* */ 180 #define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) 181 182 static void prg_cache_add(long inode, char *name) 183 { 184 unsigned hi = PRG_HASHIT(inode); 185 struct prg_node **pnp, *pn; 186 187 prg_cache_loaded = 2; 188 for (pnp = prg_hash + hi; (pn = *pnp) != NULL; pnp = &pn->next) { 189 if (pn->inode == inode) { 190 /* Some warning should be appropriate here 191 as we got multiple processes for one i-node */ 192 return; 193 } 194 } 195 *pnp = xzalloc(sizeof(struct prg_node)); 196 pn = *pnp; 197 pn->inode = inode; 198 safe_strncpy(pn->name, name, PROGNAME_WIDTH); 199 } 200 201 static const char *prg_cache_get(long inode) 202 { 203 unsigned hi = PRG_HASHIT(inode); 204 struct prg_node *pn; 205 206 for (pn = prg_hash[hi]; pn; pn = pn->next) 207 if (pn->inode == inode) 208 return pn->name; 209 return "-"; 210 } 211 212 #if ENABLE_FEATURE_CLEAN_UP 213 static void prg_cache_clear(void) 214 { 215 struct prg_node **pnp, *pn; 216 217 for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++) { 218 while ((pn = *pnp) != NULL) { 219 *pnp = pn->next; 220 free(pn); 221 } 222 } 223 } 224 #else 225 #define prg_cache_clear() ((void)0) 226 #endif 227 228 static long extract_socket_inode(const char *lname) 229 { 230 long inode = -1; 231 232 if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { 233 /* "socket:[12345]", extract the "12345" as inode */ 234 inode = bb_strtoul(lname + sizeof("socket:[")-1, (char**)&lname, 0); 235 if (*lname != ']') 236 inode = -1; 237 } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { 238 /* "[0000]:12345", extract the "12345" as inode */ 239 inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0); 240 if (errno) /* not NUL terminated? */ 241 inode = -1; 242 } 243 244 #if 0 /* bb_strtol returns all-ones bit pattern on ERANGE anyway */ 245 if (errno == ERANGE) 246 inode = -1; 247 #endif 248 return inode; 249 } 250 251 static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, 252 struct stat *statbuf UNUSED_PARAM, 253 void *pid_slash_progname, 254 int depth UNUSED_PARAM) 255 { 256 char *linkname; 257 long inode; 258 259 linkname = xmalloc_readlink(fileName); 260 if (linkname != NULL) { 261 inode = extract_socket_inode(linkname); 262 free(linkname); 263 if (inode >= 0) 264 prg_cache_add(inode, (char *)pid_slash_progname); 265 } 266 return TRUE; 267 } 268 269 static int FAST_FUNC dir_act(const char *fileName, 270 struct stat *statbuf UNUSED_PARAM, 271 void *userData UNUSED_PARAM, 272 int depth) 273 { 274 const char *pid; 275 char *pid_slash_progname; 276 char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3]; 277 char cmdline_buf[512]; 278 int n, len; 279 280 if (depth == 0) /* "/proc" itself */ 281 return TRUE; /* continue looking one level below /proc */ 282 283 pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ 284 if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */ 285 return SKIP; 286 287 len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName); 288 n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1); 289 if (n < 0) 290 return FALSE; 291 cmdline_buf[n] = '\0'; 292 293 /* go through all files in /proc/PID/fd and check whether they are sockets */ 294 strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd"); 295 pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ 296 n = recursive_action(proc_pid_fname, 297 ACTION_RECURSE | ACTION_QUIET, 298 add_to_prg_cache_if_socket, 299 NULL, 300 (void *)pid_slash_progname, 301 0); 302 free(pid_slash_progname); 303 304 if (!n) 305 return FALSE; /* signal permissions error to caller */ 306 307 return SKIP; /* caller should not recurse further into this dir */ 308 } 309 310 static void prg_cache_load(void) 311 { 312 int load_ok; 313 314 prg_cache_loaded = 1; 315 load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET, 316 NULL, dir_act, NULL, 0); 317 if (load_ok) 318 return; 319 320 if (prg_cache_loaded == 1) 321 bb_error_msg("can't scan /proc - are you root?"); 322 else 323 bb_error_msg("showing only processes with your user ID"); 324 } 325 326 #else 327 328 #define prg_cache_clear() ((void)0) 329 330 #endif //ENABLE_FEATURE_NETSTAT_PRG 93 331 94 332 … … 103 341 &in6.s6_addr32[2], &in6.s6_addr32[3]); 104 342 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); 105 inet_pton(AF_INET6, addr6, (struct sockaddr *)&localaddr->sin6_addr);343 inet_pton(AF_INET6, addr6, &localaddr->sin6_addr); 106 344 107 345 localaddr->sin6_family = AF_INET6; … … 109 347 #endif 110 348 111 #if ENABLE_FEATURE_IPV6112 static void build_ipv4_addr(char* local_addr, struct sockaddr_in6* localaddr)113 #else114 349 static void build_ipv4_addr(char* local_addr, struct sockaddr_in* localaddr) 115 #endif 116 { 117 sscanf(local_addr, "%X", 118 &((struct sockaddr_in *) localaddr)->sin_addr.s_addr); 119 ((struct sockaddr *) localaddr)->sa_family = AF_INET; 350 { 351 sscanf(local_addr, "%X", &localaddr->sin_addr.s_addr); 352 localaddr->sin_family = AF_INET; 120 353 } 121 354 … … 135 368 static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric) 136 369 { 137 enum { salen = USE_FEATURE_IPV6(sizeof(struct sockaddr_in6)) SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in)) };138 370 char *host, *host_port; 139 371 140 /* Code which used "*" for INADDR_ANY is removed: it's ambiguous in IPv6,141 * while "0.0.0.0" is not. */372 /* Code which used "*" for INADDR_ANY is removed: it's ambiguous 373 * in IPv6, while "0.0.0.0" is not. */ 142 374 143 375 host = numeric ? xmalloc_sockaddr2dotted_noport(addr) … … 149 381 } 150 382 151 st atic void tcp_do_one(int lnr, const char *line)152 { 153 char local_addr[64], rem_addr[64];154 char more[512];155 int num, local_port, rem_port, d, state, timer_run, uid, timeout;383 struct inet_params { 384 int local_port, rem_port, state, uid; 385 union { 386 struct sockaddr sa; 387 struct sockaddr_in sin; 156 388 #if ENABLE_FEATURE_IPV6 157 struct sockaddr_in6 localaddr, remaddr; 158 #else 159 struct sockaddr_in localaddr, remaddr; 160 #endif 161 unsigned long rxq, txq, time_len, retr, inode; 162 163 if (lnr == 0) 164 return; 165 166 more[0] = '\0'; 389 struct sockaddr_in6 sin6; 390 #endif 391 } localaddr, remaddr; 392 unsigned long rxq, txq, inode; 393 }; 394 395 static int scan_inet_proc_line(struct inet_params *param, char *line) 396 { 397 int num; 398 /* IPv6 /proc files use 32-char hex representation 399 * of IPv6 address, followed by :PORT_IN_HEX 400 */ 401 char local_addr[33], rem_addr[33]; /* 32 + 1 for NUL */ 402 167 403 num = sscanf(line, 168 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 169 &d, local_addr, &local_port, 170 rem_addr, &rem_port, &state, 171 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 404 "%*d: %32[0-9A-Fa-f]:%X " 405 "%32[0-9A-Fa-f]:%X %X " 406 "%lX:%lX %*X:%*X " 407 "%*X %d %*d %ld ", 408 local_addr, ¶m->local_port, 409 rem_addr, ¶m->rem_port, ¶m->state, 410 ¶m->txq, ¶m->rxq, 411 ¶m->uid, ¶m->inode); 412 if (num < 9) { 413 return 1; /* error */ 414 } 172 415 173 416 if (strlen(local_addr) > 8) { 174 417 #if ENABLE_FEATURE_IPV6 175 build_ipv6_addr(local_addr, & localaddr);176 build_ipv6_addr(rem_addr, & remaddr);418 build_ipv6_addr(local_addr, ¶m->localaddr.sin6); 419 build_ipv6_addr(rem_addr, ¶m->remaddr.sin6); 177 420 #endif 178 421 } else { 179 build_ipv4_addr(local_addr, & localaddr);180 build_ipv4_addr(rem_addr, & remaddr);181 } 182 183 if (num < 10) { 184 bb_error_msg("warning, got bogus tcp line"); 185 return; 186 }187 188 if (( rem_port&& (flags & NETSTAT_CONNECTED))189 || (! rem_port&& (flags & NETSTAT_LISTENING))422 build_ipv4_addr(local_addr, ¶m->localaddr.sin); 423 build_ipv4_addr(rem_addr, ¶m->remaddr.sin); 424 } 425 return 0; 426 } 427 428 static void print_inet_line(struct inet_params *param, 429 const char *state_str, const char *proto, int is_connected) 430 { 431 if ((is_connected && (flags & NETSTAT_CONNECTED)) 432 || (!is_connected && (flags & NETSTAT_LISTENING)) 190 433 ) { 191 434 char *l = ip_port_str( 192 (struct sockaddr *) &localaddr,local_port,193 "tcp", flags & NETSTAT_NUMERIC);435 ¶m->localaddr.sa, param->local_port, 436 proto, flags & NETSTAT_NUMERIC); 194 437 char *r = ip_port_str( 195 (struct sockaddr *) &remaddr, rem_port, 196 "tcp", flags & NETSTAT_NUMERIC); 197 printf(net_conn_line, 198 "tcp", rxq, txq, l, r, tcp_state[state]); 438 ¶m->remaddr.sa, param->rem_port, 439 proto, flags & NETSTAT_NUMERIC); 440 printf(FMT_NET_CONN_DATA, 441 proto, param->rxq, param->txq, 442 IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l, 443 IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r, 444 state_str); 445 #if ENABLE_FEATURE_NETSTAT_PRG 446 if (option_mask32 & OPT_prg) 447 printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); 448 #endif 449 bb_putchar('\n'); 199 450 free(l); 200 451 free(r); … … 202 453 } 203 454 204 static void udp_do_one(int lnr, const char *line) 205 { 206 char local_addr[64], rem_addr[64]; 207 const char *state_str; 208 char more[512]; 209 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 455 static int FAST_FUNC tcp_do_one(char *line) 456 { 457 struct inet_params param; 458 459 memset(¶m, 0, sizeof(param)); 460 if (scan_inet_proc_line(¶m, line)) 461 return 1; 462 463 print_inet_line(¶m, tcp_state[param.state], "tcp", param.rem_port); 464 return 0; 465 } 466 210 467 #if ENABLE_FEATURE_IPV6 211 struct sockaddr_in6 localaddr, remaddr; 212 #else 213 struct sockaddr_in localaddr, remaddr; 214 #endif 215 unsigned long rxq, txq, time_len, retr, inode; 216 217 if (lnr == 0) 218 return; 219 220 more[0] = '\0'; 221 num = sscanf(line, 222 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 223 &d, local_addr, &local_port, 224 rem_addr, &rem_port, &state, 225 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 226 227 if (strlen(local_addr) > 8) { 228 #if ENABLE_FEATURE_IPV6 229 /* Demangle what the kernel gives us */ 230 build_ipv6_addr(local_addr, &localaddr); 231 build_ipv6_addr(rem_addr, &remaddr); 232 #endif 233 } else { 234 build_ipv4_addr(local_addr, &localaddr); 235 build_ipv4_addr(rem_addr, &remaddr); 236 } 237 238 if (num < 10) { 239 bb_error_msg("warning, got bogus udp line"); 240 return; 241 } 242 switch (state) { 243 case TCP_ESTABLISHED: 244 state_str = "ESTABLISHED"; 245 break; 246 case TCP_CLOSE: 247 state_str = ""; 248 break; 249 default: 250 state_str = "UNKNOWN"; 251 break; 252 } 253 254 #if ENABLE_FEATURE_IPV6 255 # define notnull(A) ( \ 256 ( (A.sin6_family == AF_INET6) \ 257 && (A.sin6_addr.s6_addr32[0] | A.sin6_addr.s6_addr32[1] | \ 258 A.sin6_addr.s6_addr32[2] | A.sin6_addr.s6_addr32[3]) \ 259 ) || ( \ 260 (A.sin6_family == AF_INET) \ 261 && ((struct sockaddr_in*)&A)->sin_addr.s_addr \ 262 ) \ 468 # define NOT_NULL_ADDR(A) ( \ 469 ( (A.sa.sa_family == AF_INET6) \ 470 && (A.sin6.sin6_addr.s6_addr32[0] | A.sin6.sin6_addr.s6_addr32[1] | \ 471 A.sin6.sin6_addr.s6_addr32[2] | A.sin6.sin6_addr.s6_addr32[3]) \ 472 ) || ( \ 473 (A.sa.sa_family == AF_INET) \ 474 && A.sin.sin_addr.s_addr != 0 \ 475 ) \ 263 476 ) 264 477 #else 265 # define notnull(A) (A.sin_addr.s_addr) 266 #endif 267 { 268 int have_remaddr = notnull(remaddr); 269 if ((have_remaddr && (flags & NETSTAT_CONNECTED)) 270 || (!have_remaddr && (flags & NETSTAT_LISTENING)) 271 ) { 272 char *l = ip_port_str( 273 (struct sockaddr *) &localaddr, local_port, 274 "udp", flags & NETSTAT_NUMERIC); 275 char *r = ip_port_str( 276 (struct sockaddr *) &remaddr, rem_port, 277 "udp", flags & NETSTAT_NUMERIC); 278 printf(net_conn_line, 279 "udp", rxq, txq, l, r, state_str); 280 free(l); 281 free(r); 282 } 283 } 284 } 285 286 static void raw_do_one(int lnr, const char *line) 287 { 288 char local_addr[64], rem_addr[64]; 289 char more[512]; 290 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 291 #if ENABLE_FEATURE_IPV6 292 struct sockaddr_in6 localaddr, remaddr; 293 #else 294 struct sockaddr_in localaddr, remaddr; 295 #endif 296 unsigned long rxq, txq, time_len, retr, inode; 297 298 if (lnr == 0) 299 return; 300 301 more[0] = '\0'; 302 num = sscanf(line, 303 "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", 304 &d, local_addr, &local_port, 305 rem_addr, &rem_port, &state, 306 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 307 308 if (strlen(local_addr) > 8) { 309 #if ENABLE_FEATURE_IPV6 310 build_ipv6_addr(local_addr, &localaddr); 311 build_ipv6_addr(rem_addr, &remaddr); 312 #endif 313 } else { 314 build_ipv4_addr(local_addr, &localaddr); 315 build_ipv4_addr(rem_addr, &remaddr); 316 } 317 318 if (num < 10) { 319 bb_error_msg("warning, got bogus raw line"); 320 return; 321 } 322 323 { 324 int have_remaddr = notnull(remaddr); 325 if ((have_remaddr && (flags & NETSTAT_CONNECTED)) 326 || (!have_remaddr && (flags & NETSTAT_LISTENING)) 327 ) { 328 char *l = ip_port_str( 329 (struct sockaddr *) &localaddr, local_port, 330 "raw", flags & NETSTAT_NUMERIC); 331 char *r = ip_port_str( 332 (struct sockaddr *) &remaddr, rem_port, 333 "raw", flags & NETSTAT_NUMERIC); 334 printf(net_conn_line, 335 "raw", rxq, txq, l, r, itoa(state)); 336 free(l); 337 free(r); 338 } 339 } 340 } 341 342 static void unix_do_one(int nr, const char *line) 343 { 344 static smallint has_inode = 0; 345 346 char path[PATH_MAX], ss_flags[32]; 478 # define NOT_NULL_ADDR(A) (A.sin.sin_addr.s_addr) 479 #endif 480 481 static int FAST_FUNC udp_do_one(char *line) 482 { 483 int have_remaddr; 484 const char *state_str; 485 struct inet_params param; 486 487 memset(¶m, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */ 488 if (scan_inet_proc_line(¶m, line)) 489 return 1; 490 491 state_str = "UNKNOWN"; 492 switch (param.state) { 493 case TCP_ESTABLISHED: 494 state_str = "ESTABLISHED"; 495 break; 496 case TCP_CLOSE: 497 state_str = ""; 498 break; 499 } 500 501 have_remaddr = NOT_NULL_ADDR(param.remaddr); 502 print_inet_line(¶m, state_str, "udp", have_remaddr); 503 return 0; 504 } 505 506 static int FAST_FUNC raw_do_one(char *line) 507 { 508 int have_remaddr; 509 struct inet_params param; 510 511 if (scan_inet_proc_line(¶m, line)) 512 return 1; 513 514 have_remaddr = NOT_NULL_ADDR(param.remaddr); 515 print_inet_line(¶m, itoa(param.state), "raw", have_remaddr); 516 return 0; 517 } 518 519 static int FAST_FUNC unix_do_one(char *line) 520 { 521 unsigned long refcnt, proto, unix_flags; 522 unsigned long inode; 523 int type, state; 524 int num, path_ofs; 347 525 const char *ss_proto, *ss_state, *ss_type; 348 int num, state, type, inode; 349 void *d; 350 unsigned long refcnt, proto, unix_flags; 351 352 if (nr == 0) { 353 if (strstr(line, "Inode")) 354 has_inode = 1; 355 return; 356 } 357 path[0] = '\0'; 358 num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s", 359 &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path); 526 char ss_flags[32]; 527 528 /* 2.6.15 may report lines like "... @/tmp/fam-user-^@^@^@^@^@^@^@..." 529 * Other users report long lines filled by NUL bytes. 530 * (those ^@ are NUL bytes too). We see them as empty lines. */ 531 if (!line[0]) 532 return 0; 533 534 path_ofs = 0; /* paranoia */ 535 num = sscanf(line, "%*p: %lX %lX %lX %X %X %lu %n", 536 &refcnt, &proto, &unix_flags, &type, &state, &inode, &path_ofs); 360 537 if (num < 6) { 361 bb_error_msg("warning, got bogus unix line"); 362 return; 363 } 364 if (!has_inode) 365 sprintf(path, "%d", inode); 366 538 return 1; /* error */ 539 } 367 540 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) != (NETSTAT_LISTENING|NETSTAT_CONNECTED)) { 368 541 if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) { 369 542 if (!(flags & NETSTAT_LISTENING)) 370 return ;543 return 0; 371 544 } else { 372 545 if (!(flags & NETSTAT_CONNECTED)) 373 return ;546 return 0; 374 547 } 375 548 } … … 440 613 strcat(ss_flags, "]"); 441 614 442 printf("%-5s %-6ld %-11s %-10s %-13s ", 443 ss_proto, refcnt, ss_flags, ss_type, ss_state); 444 if (has_inode) 445 printf("%-6d ", inode); 446 else 447 printf("- "); 448 puts(path); 449 } 450 451 #define _PATH_PROCNET_UDP "/proc/net/udp" 452 #define _PATH_PROCNET_UDP6 "/proc/net/udp6" 453 #define _PATH_PROCNET_TCP "/proc/net/tcp" 454 #define _PATH_PROCNET_TCP6 "/proc/net/tcp6" 455 #define _PATH_PROCNET_RAW "/proc/net/raw" 456 #define _PATH_PROCNET_RAW6 "/proc/net/raw6" 457 #define _PATH_PROCNET_UNIX "/proc/net/unix" 458 459 static void do_info(const char *file, const char *name, void (*proc)(int, const char *)) 460 { 461 int lnr = 0; 615 printf("%-5s %-6ld %-11s %-10s %-13s %6lu ", 616 ss_proto, refcnt, ss_flags, ss_type, ss_state, inode 617 ); 618 619 #if ENABLE_FEATURE_NETSTAT_PRG 620 if (option_mask32 & OPT_prg) 621 printf("%-"PROGNAME_WIDTH_STR"s", prg_cache_get(inode)); 622 #endif 623 624 /* TODO: currently we stop at first NUL byte. Is it a problem? */ 625 line += path_ofs; 626 *strchrnul(line, '\n') = '\0'; 627 while (*line) 628 fputc_printable(*line++, stdout); 629 bb_putchar('\n'); 630 return 0; 631 } 632 633 static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) 634 { 635 int lnr; 462 636 FILE *procinfo; 463 464 procinfo = fopen(file, "r"); 637 char *buffer; 638 639 /* _stdin is just to save "r" param */ 640 procinfo = fopen_or_warn_stdin(file); 465 641 if (procinfo == NULL) { 466 if (errno != ENOENT) {467 bb_perror_msg("%s", file);468 } else {469 bb_error_msg("no support for '%s' on this system", name);470 }471 642 return; 472 643 } 473 do { 474 char *buffer = xmalloc_fgets(procinfo); 475 if (buffer) { 476 (proc)(lnr++, buffer); 477 free(buffer); 478 } 479 } while (!feof(procinfo)); 644 lnr = 0; 645 /* Why xmalloc_fgets_str? because it doesn't stop on NULs */ 646 while ((buffer = xmalloc_fgets_str(procinfo, "\n")) != NULL) { 647 /* line 0 is skipped */ 648 if (lnr && proc(buffer)) 649 bb_error_msg("%s: bogus data on line %d", file, lnr + 1); 650 lnr++; 651 free(buffer); 652 } 480 653 fclose(procinfo); 481 654 } 482 655 483 /* 484 * Our main function. 485 */ 486 487 int netstat_main(int argc, char **argv); 488 int netstat_main(int argc, char **argv) 489 { 490 const char *net_conn_line_header = PRINT_NET_CONN_HEADER; 656 int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 657 int netstat_main(int argc UNUSED_PARAM, char **argv) 658 { 491 659 unsigned opt; 492 #if ENABLE_FEATURE_IPV6 493 smallint inet = 1; 494 smallint inet6 = 1; 495 #else 496 enum { inet = 1, inet6 = 0 }; 497 #endif 660 661 INIT_G(); 498 662 499 663 /* Option string must match NETSTAT_xxx constants */ 500 664 opt = getopt32(argv, NETSTAT_OPTS); 501 if (opt & 0x1) { // -l665 if (opt & OPT_sock_listen) { // -l 502 666 flags &= ~NETSTAT_CONNECTED; 503 667 flags |= NETSTAT_LISTENING; 504 668 } 505 if (opt & 0x2) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a 506 //if (opt & 0x4) // -e 507 if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n 508 //if (opt & 0x10) // -t: NETSTAT_TCP 509 //if (opt & 0x20) // -u: NETSTAT_UDP 510 //if (opt & 0x40) // -w: NETSTAT_RAW 511 //if (opt & 0x80) // -x: NETSTAT_UNIX 512 if (opt & OPT_showroute) { // -r 669 if (opt & OPT_sock_all) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a 670 //if (opt & OPT_extended) // -e 671 if (opt & OPT_noresolve) flags |= NETSTAT_NUMERIC; // -n 672 //if (opt & OPT_sock_tcp) // -t: NETSTAT_TCP 673 //if (opt & OPT_sock_udp) // -u: NETSTAT_UDP 674 //if (opt & OPT_sock_raw) // -w: NETSTAT_RAW 675 //if (opt & OPT_sock_unix) // -x: NETSTAT_UNIX 513 676 #if ENABLE_ROUTE 677 if (opt & OPT_route) { // -r 514 678 bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); 515 679 return 0; 516 #else 517 bb_show_usage(); 518 #endif 519 } 520 521 if (opt & OPT_widedisplay) { // -W 522 net_conn_line = PRINT_NET_CONN_WIDE; 523 net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; 524 } 680 } 681 #endif 682 #if ENABLE_FEATURE_NETSTAT_WIDE 683 G.addr_width = ADDR_NORMAL_WIDTH; 684 if (opt & OPT_wide) { // -W 685 G.addr_width = ADDR_WIDE; 686 } 687 #endif 688 #if ENABLE_FEATURE_NETSTAT_PRG 689 progname_banner = ""; 690 if (opt & OPT_prg) { // -p 691 progname_banner = PROGNAME_BANNER; 692 prg_cache_load(); 693 } 694 #endif 525 695 526 696 opt &= NETSTAT_ALLPROTO; … … 530 700 } 531 701 if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) { 532 printf("Active Internet connections "); 702 printf("Active Internet connections "); /* xxx */ 533 703 534 704 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) … … 538 708 else 539 709 printf("(w/o servers)"); 540 printf(net_conn_line_header, "Local Address", "Foreign Address"); 541 } 542 if (inet && flags & NETSTAT_TCP) 543 do_info(_PATH_PROCNET_TCP, "AF INET (tcp)", tcp_do_one); 710 printf(FMT_NET_CONN_HEADER, 711 IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address", 712 IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address", 713 progname_banner 714 ); 715 } 716 if (flags & NETSTAT_TCP) { 717 do_info("/proc/net/tcp", tcp_do_one); 544 718 #if ENABLE_FEATURE_IPV6 545 if (inet6 && flags & NETSTAT_TCP)546 do_info(_PATH_PROCNET_TCP6, "AF INET6 (tcp)", tcp_do_one); 547 #endif 548 if ( inet && flags & NETSTAT_UDP)549 do_info( _PATH_PROCNET_UDP, "AF INET (udp)", udp_do_one);719 do_info("/proc/net/tcp6", tcp_do_one); 720 #endif 721 } 722 if (flags & NETSTAT_UDP) { 723 do_info("/proc/net/udp", udp_do_one); 550 724 #if ENABLE_FEATURE_IPV6 551 if (inet6 && flags & NETSTAT_UDP)552 do_info(_PATH_PROCNET_UDP6, "AF INET6 (udp)", udp_do_one); 553 #endif 554 if ( inet && flags & NETSTAT_RAW)555 do_info( _PATH_PROCNET_RAW, "AF INET (raw)", raw_do_one);725 do_info("/proc/net/udp6", udp_do_one); 726 #endif 727 } 728 if (flags & NETSTAT_RAW) { 729 do_info("/proc/net/raw", raw_do_one); 556 730 #if ENABLE_FEATURE_IPV6 557 if (inet6 && flags & NETSTAT_RAW)558 do_info(_PATH_PROCNET_RAW6, "AF INET6 (raw)", raw_do_one); 559 #endif 731 do_info("/proc/net/raw6", raw_do_one); 732 #endif 733 } 560 734 if (flags & NETSTAT_UNIX) { 561 735 printf("Active UNIX domain sockets "); … … 566 740 else 567 741 printf("(w/o servers)"); 568 printf("\nProto RefCnt Flags Type State I-Node Path\n"); 569 do_info(_PATH_PROCNET_UNIX, "AF UNIX", unix_do_one); 570 } 742 printf("\nProto RefCnt Flags Type State I-Node %sPath\n", progname_banner); 743 do_info("/proc/net/unix", unix_do_one); 744 } 745 prg_cache_clear(); 571 746 return 0; 572 747 }
Note:
See TracChangeset
for help on using the changeset viewer.