1/* netstat.c - Display Linux networking subsystem. 2 * 3 * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com> 4 * Copyright 2013 Kyungwan Han <asura321@gmail.com> 5 * 6 * Not in SUSv4. 7 * 8USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN)) 9config NETSTAT 10 bool "netstat" 11 default n 12 help 13 usage: netstat [-pWrxwutneal] 14 15 Display networking information. 16 17 -r Display routing table. 18 -a Display all sockets (Default: Connected). 19 -l Display listening server sockets. 20 -t Display TCP sockets. 21 -u Display UDP sockets. 22 -w Display Raw sockets. 23 -x Display Unix sockets. 24 -e Display other/more information. 25 -n Don't resolve names. 26 -W Wide Display. 27 -p Display PID/Program name for sockets. 28*/ 29 30#define FOR_netstat 31#include "toys.h" 32#include <net/route.h> 33 34typedef union _iaddr { 35 unsigned u; 36 unsigned char b[4]; 37} iaddr; 38 39typedef union _iaddr6 { 40 struct { 41 unsigned a; 42 unsigned b; 43 unsigned c; 44 unsigned d; 45 } u; 46 unsigned char b[16]; 47} iaddr6; 48 49#define ADDR_LEN (INET6_ADDRSTRLEN + 1 + 5 + 1) //IPv6 addr len + : + port + '\0' 50 51//For unix states 52enum { 53 SOCK_ACCEPTCON = (1 << 16), //performed a listen. 54 SOCK_WAIT_DATA = (1 << 17), //wait data to read. 55 SOCK_NO_SPACE = (1 << 18), //no space to write. 56}; 57 58#define SOCK_NOT_CONNECTED 1 59//For PID/Progrma Name 60#define PROGRAM_NAME "PID/Program Name" 61#define PROGNAME_LEN 21 62 63typedef struct _pidlist { 64 struct _pidlist *next; 65 long inode; 66 char name[PROGNAME_LEN]; 67} PID_LIST; 68PID_LIST *pid_list = NULL; 69 70/* 71 * Get base name from the input name. 72 */ 73static const char *get_basename(char *name) 74{ 75 const char *c = strrchr(name, '/'); 76 if (c) return c + 1; 77 return name; 78} 79 80/* 81 * locate character in string. 82 */ 83static char *strchr_nul(char *s, int c) 84{ 85 while(*s != '\0' && *s != c) s++; 86 return (char*)s; 87} 88 89// Find out if the last character of a string matches with the given one. 90// Don't underrun the buffer if the string length is 0. 91static char *find_last_char(char *str, int c) 92{ 93 if (str && *str) { 94 size_t sz = strlen(str) - 1; 95 str += sz; 96 if ( (unsigned char)*str == c) return (char*)str; 97 } 98 return NULL; 99} 100/* 101 * Concat path and the file name. 102 */ 103static char *append_pathandfile(char *path, char *fname) 104{ 105 char *c; 106 if (!path) path = ""; 107 c = find_last_char(path, '/'); 108 while (*fname == '/') fname++; 109 return xmprintf("%s%s%s", path, (c)? "" : "/", fname); 110} 111/* 112 * Concat sub-path and the file name. 113 */ 114static char *append_subpathandfile(char *path, char *fname) 115{ 116#define ISDOTORDOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2]))) 117 if(!fname) return NULL; 118 if(ISDOTORDOTDOT(fname)) return NULL; 119 return append_pathandfile(path, fname); 120#undef ISDOTORDOTDOT 121} 122/* 123 * used to converts string into int and validate the input str for invalid int value or out-of-range. 124 */ 125static unsigned get_strtou(char *str, char **endp, int base) 126{ 127 unsigned long uli; 128 char *endptr; 129 130 if (!isalnum(str[0])) { 131 errno = ERANGE; 132 return UINT_MAX; 133 } 134 errno = 0; 135 uli = strtoul(str, &endptr, base); 136 if (uli > UINT_MAX) { 137 errno = ERANGE; 138 return UINT_MAX; 139 } 140 141 if (endp) *endp = endptr; 142 if (endptr[0]) { 143 if (isalnum(endptr[0]) || errno) { //"123abc" or out-of-range 144 errno = ERANGE; 145 return UINT_MAX; 146 } 147 errno = EINVAL; 148 } 149 return uli; 150} 151/* 152 * used to retrive pid name from pid list. 153 */ 154static const char *get_pid_name(unsigned long inode) 155{ 156 PID_LIST *tmp; 157 for (tmp = pid_list; tmp; tmp = tmp->next) 158 if (tmp->inode == inode) return tmp->name; 159 return "-"; 160} 161/* 162 * For TCP/UDP/RAW display data. 163 */ 164static void display_data(unsigned rport, char *label, unsigned rxq, unsigned txq, char *lip, char *rip, unsigned state, unsigned long inode) 165{ 166 char *ss_state = "UNKNOWN", buf[12]; 167 char *state_label[] = {"", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2", 168 "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING", "UNKNOWN"}; 169 if (!strcmp(label, "tcp")) { 170 int sz = ARRAY_LEN(state_label); 171 if (!state || state >= sz) state = sz-1; 172 ss_state = state_label[state]; 173 } 174 else if (!strcmp(label, "udp")) { 175 if (state == 1) ss_state = state_label[state]; 176 else if (state == 7) ss_state = ""; 177 } 178 else if (!strcmp(label, "raw")) sprintf(ss_state = buf, "%u", state); 179 180 if ( (toys.optflags & FLAG_W) && (toys.optflags & FLAG_p)) 181 xprintf("%3s %6d %6d %-51s %-51s %-12s%s\n", label, rxq, txq, lip, rip, ss_state, get_pid_name(inode)); 182 else if (toys.optflags & FLAG_W) 183 xprintf("%3s %6d %6d %-51s %-51s %-12s\n", label, rxq, txq, lip, rip, ss_state); 184 else if (toys.optflags & FLAG_p) 185 xprintf("%3s %6d %6d %-23s %-23s %-12s%s\n", label, rxq, txq, lip, rip, ss_state, get_pid_name(inode)); 186 else xprintf("%3s %6d %6d %-23s %-23s %-12s\n", label, rxq, txq, lip, rip, ss_state); 187} 188/* 189 * For TCP/UDP/RAW show data. 190 */ 191static void show_data(unsigned rport, char *label, unsigned rxq, unsigned txq, char *lip, char *rip, unsigned state, unsigned long inode) 192{ 193 if (toys.optflags & FLAG_l) { 194 if (!rport && (state && 0xA)) display_data(rport, label, rxq, txq, lip, rip, state, inode); 195 } else if (toys.optflags & FLAG_a) display_data(rport, label, rxq, txq, lip, rip, state, inode); 196 //rport && (TCP | UDP | RAW) 197 else if (rport && (0x10 | 0x20 | 0x40)) display_data(rport, label, rxq, txq, lip, rip, state, inode); 198} 199/* 200 * used to get service name. 201 */ 202static char *get_servname(int port, char *label) 203{ 204 int lport = htons(port); 205 if (!lport) return xmprintf("%s", "*"); 206 struct servent *ser = getservbyport(lport, label); 207 if (ser) return xmprintf("%s", ser->s_name); 208 return xmprintf("%u", (unsigned)ntohs(lport)); 209} 210/* 211 * used to convert address into text format. 212 */ 213static void addr2str(int af, void *addr, unsigned port, char *buf, char *label) 214{ 215 char ip[ADDR_LEN] = {0,}; 216 if (!inet_ntop(af, addr, ip, ADDR_LEN)) { 217 *buf = '\0'; 218 return; 219 } 220 size_t iplen = strlen(ip); 221 if (!port) { 222 strncat(ip+iplen, ":*", ADDR_LEN-iplen-1); 223 memcpy(buf, ip, ADDR_LEN); 224 return; 225 } 226 227 if (!(toys.optflags & FLAG_n)) { 228 struct addrinfo hints, *result, *rp; 229 230 memset(&hints, 0, sizeof(struct addrinfo)); 231 hints.ai_family = af; 232 233 if (!getaddrinfo(ip, NULL, &hints, &result)) { 234 char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,}; 235 socklen_t sock_len; 236 char *sname = NULL; 237 int plen = 0; 238 239 if (af == AF_INET) sock_len = sizeof(struct sockaddr_in); 240 else sock_len = sizeof(struct sockaddr_in6); 241 242 for (rp = result; rp; rp = rp->ai_next) 243 if (!getnameinfo(rp->ai_addr, sock_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICSERV)) 244 break; 245 246 freeaddrinfo(result); 247 sname = get_servname(port, label); 248 plen = strlen(sname); 249 if (*hbuf) { 250 memset(ip, 0, ADDR_LEN); 251 memcpy(ip, hbuf, (ADDR_LEN - plen - 2)); 252 iplen = strlen(ip); 253 } 254 snprintf(ip + iplen, ADDR_LEN-iplen, ":%s", sname); 255 free(sname); 256 } 257 } 258 else snprintf(ip+iplen, ADDR_LEN-iplen, ":%d", port); 259 memcpy(buf, ip, ADDR_LEN); 260} 261/* 262 * display ipv4 info for TCP/UDP/RAW. 263 */ 264static void show_ipv4(char *fname, char *label) 265{ 266 FILE *fp = fopen((char *)fname, "r"); 267 if (!fp) { 268 perror_msg("'%s'", fname); 269 return; 270 } 271 fgets(toybuf, sizeof(toybuf), fp); //skip header. 272 while (fgets(toybuf, sizeof(toybuf), fp)) { 273 char lip[ADDR_LEN] = {0,}, rip[ADDR_LEN] = {0,}; 274 iaddr laddr, raddr; 275 unsigned lport, rport, state, txq, rxq, num, uid; 276 unsigned long inode; 277 278 int nitems = sscanf(toybuf, " %d: %x:%x %x:%x %x %x:%x %*X:%*X %*X %d %*d %ld", 279 &num, &laddr.u, &lport, &raddr.u, &rport, &state, &txq, &rxq, &uid, &inode); 280 if (nitems == 10) { 281 addr2str(AF_INET, &laddr, lport, lip, label); 282 addr2str(AF_INET, &raddr, rport, rip, label); 283 show_data(rport, label, rxq, txq, lip, rip, state, inode); 284 } 285 }//End of While 286 fclose(fp); 287} 288/* 289 * display ipv6 info for TCP/UDP/RAW. 290 */ 291static void show_ipv6(char *fname, char *label) 292{ 293 FILE *fp = fopen((char *)fname, "r"); 294 if (!fp) { 295 perror_msg("'%s'", fname); 296 return; 297 } 298 fgets(toybuf, sizeof(toybuf), fp); //skip header. 299 while (fgets(toybuf, sizeof(toybuf), fp)) { 300 char lip[ADDR_LEN] = {0,}, rip[ADDR_LEN] = {0,}; 301 iaddr6 laddr6, raddr6; 302 unsigned lport, rport, state, txq, rxq, num, uid; 303 unsigned long inode; 304 int nitems = sscanf(toybuf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x %*X:%*X %*X %d %*d %ld", 305 &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport, &raddr6.u.a, &raddr6.u.b, 306 &raddr6.u.c, &raddr6.u.d, &rport, &state, &txq, &rxq, &uid, &inode); 307 if (nitems == 16) { 308 addr2str(AF_INET6, &laddr6, lport, lip, label); 309 addr2str(AF_INET6, &raddr6, rport, rip, label); 310 show_data(rport, label, rxq, txq, lip, rip, state, inode); 311 } 312 }//End of While 313 fclose(fp); 314} 315/* 316 * display unix socket info. 317 */ 318static void show_unix_sockets(char *fname, char *label) 319{ 320 FILE *fp = fopen((char *)fname, "r"); 321 if (!fp) { 322 perror_msg("'%s'", fname); 323 return; 324 } 325 fgets(toybuf, sizeof(toybuf), fp); //skip header. 326 while (fgets(toybuf, sizeof(toybuf), fp)) { 327 unsigned long int refcount, label, flags, inode; 328 int nitems = 0, path_offset = 0, type, state; 329 char sock_flags[32] = {0,}, *sock_type, *sock_state, *bptr = toybuf; 330 331 if (!toybuf[0]) continue; 332 nitems = sscanf(toybuf, "%*p: %lX %lX %lX %X %X %lu %n", 333 &refcount, &label, &flags, &type, &state, &inode, &path_offset); 334 //for state one less 335 if (nitems < 6) break; 336 if (toys.optflags & FLAG_l) { 337 if ( !((state == SOCK_NOT_CONNECTED) && (flags & SOCK_ACCEPTCON)) ) continue; 338 } else if (!(toys.optflags & FLAG_a)) { 339 if ((state == SOCK_NOT_CONNECTED) && (flags & SOCK_ACCEPTCON)) continue; 340 } 341 342 //prepare socket type, state and flags. 343 { 344 char *ss_type[] = { "", "STREAM", "DGRAM", "RAW", "RDM", "SEQPACKET", "UNKNOWN"}; 345 char *ss_state[] = { "FREE", "LISTENING", "CONNECTING", "CONNECTED", "DISCONNECTING", "UNKNOWN"}; 346 347 int sz = ARRAY_LEN(ss_type);//sizeof(ss_type)/sizeof(ss_type[0]); 348 if ( (type < SOCK_STREAM) || (type > SOCK_SEQPACKET) ) sock_type = ss_type[sz-1]; 349 else sock_type = ss_type[type]; 350 351 sz = ARRAY_LEN(ss_state);//sizeof(ss_state)/sizeof(ss_state[0]); 352 if ((state < 0) || (state > sz-2)) sock_state = ss_state[sz-1]; 353 else if (state == SOCK_NOT_CONNECTED) { 354 if (flags & SOCK_ACCEPTCON) sock_state = ss_state[state]; 355 else sock_state = " "; 356 } else sock_state = ss_state[state]; 357 358 strcpy(sock_flags, "[ "); 359 if (flags & SOCK_ACCEPTCON) strcat(sock_flags, "ACC "); 360 if (flags & SOCK_WAIT_DATA) strcat(sock_flags, "W "); 361 if (flags & SOCK_NO_SPACE) strcat(sock_flags, "N "); 362 strcat(sock_flags, "]"); 363 } 364 xprintf("%-5s %-6ld %-11s %-10s %-13s %6lu ", (!label ? "unix" : "??"), refcount, sock_flags, sock_type, sock_state, inode); 365 if (toys.optflags & FLAG_p) xprintf("%-20s", get_pid_name(inode)); 366 367 bptr += path_offset; 368 *strchr_nul(bptr, '\n') = '\0'; 369 xprintf("%s\n", bptr); 370 }//End of while 371 fclose(fp); 372} 373/* 374 * extract inode value from the link. 375 */ 376static long ss_inode(char *link) 377{ 378 long inode = -1; 379 //"link = socket:[12345]", get "12345" as inode. 380 if (!strncmp(link, "socket:[", sizeof("socket:[")-1)) { 381 inode = get_strtou(link + sizeof("socket:[")-1, (char**)&link, 0); 382 if (*link != ']') inode = -1; 383 } 384 //"link = [0000]:12345", get "12345" as inode. 385 else if (!strncmp(link, "[0000]:", sizeof("[0000]:")-1)) { 386 inode = get_strtou(link + sizeof("[0000]:")-1, NULL, 0); 387 //if not NULL terminated. 388 if (errno) inode = -1; 389 } 390 return inode; 391} 392/* 393 * add inode and progname in the pid list. 394 */ 395static void add2list(long inode, char *progname) 396{ 397 PID_LIST *node = pid_list; 398 for(; node; node = node->next) { 399 if(node->inode == inode) 400 return; 401 } 402 PID_LIST *new = (PID_LIST *)xzalloc(sizeof(PID_LIST)); 403 new->inode = inode; 404 xstrncpy(new->name, progname, PROGNAME_LEN); 405 new->next = pid_list; 406 pid_list = new; 407} 408/* 409 * add pid info in the list. 410 */ 411static void extract_inode(char *path, char *progname) 412{ 413 DIR *dp; 414 struct dirent *entry; 415 416 if (!(dp = opendir(path))) { 417 if (errno == EACCES) return; 418 else perror_exit("%s", path); 419 } 420 while ((entry = readdir(dp))) { 421 char *link = NULL, *fname = append_subpathandfile(path, entry->d_name); 422 if (!fname) continue; 423 link = xreadlink(fname); 424 if (link) { 425 long inode = ss_inode(link); 426 free(link); 427 if (inode != -1) add2list(inode, progname); 428 } 429 free(fname); 430 }//end of while. 431 closedir(dp); 432} 433/* 434 * prepare the list for all pids in /proc directory. 435 */ 436static void get_pid_list(void) 437{ 438 DIR *dp; 439 struct dirent *entry; 440 char path[64] = {0,}; 441 uid_t uid = geteuid(); 442 443 if (!(dp = opendir("/proc"))) perror_exit("opendir"); 444 445 while ((entry = readdir(dp))) { 446 int fd, nitems = 0, length = 0; 447 char *pid, *progname; 448 449 if (!isdigit(*entry->d_name)) continue; 450 pid = entry->d_name; 451 length = snprintf(path, sizeof(path), "/proc/%s/cmdline", entry->d_name); 452 if (sizeof(path) <= length) continue; 453 454 fd = xopen(path, O_RDONLY); 455 nitems = readall(fd, toybuf, sizeof(toybuf) - 1); 456 xclose(fd); 457 if (nitems < 1) continue; 458 toybuf[nitems] = '\0'; 459 strcpy(path + length - (sizeof("cmdline")-1), "fd"); 460 progname = append_pathandfile(pid, (char *)get_basename(toybuf)); //e.g. progname = 2054/gnome-keyring-daemon 461 extract_inode(path, progname); 462 free(progname); 463 }//end of while. 464 closedir(dp); 465 466 if (uid) fprintf(stderr, "(Not all processes could be identified, non-owned process info " 467 "will not be shown, you would have to be root to see it all.)\n"); 468} 469/* 470 * Dealloc pid list. 471 */ 472static void clean_pid_list(void) 473{ 474 PID_LIST *tmp; 475 while (pid_list) { 476 tmp = pid_list->next; 477 free(pid_list); 478 pid_list = tmp; 479 } 480} 481/* 482 * For TCP/UDP/RAW show the header. 483 */ 484static void show_header(void) 485{ 486 if ((toys.optflags & FLAG_W) && (toys.optflags & FLAG_p)) 487 xprintf("\nProto Recv-Q Send-Q %-51s %-51s %-12s%s\n", "Local Address", "Foreign Address", "State", PROGRAM_NAME); 488 else if (toys.optflags & FLAG_p) 489 xprintf("\nProto Recv-Q Send-Q %-23s %-23s %-12s%s\n", "Local Address", "Foreign Address", "State", PROGRAM_NAME); 490 else if (toys.optflags & FLAG_W) 491 xprintf("\nProto Recv-Q Send-Q %-51s %-51s State \n", "Local Address", "Foreign Address"); 492 else xprintf("\nProto Recv-Q Send-Q %-23s %-23s State \n", "Local Address", "Foreign Address"); 493} 494/* 495 * used to get the flag values for route command. 496 */ 497static void get_flag_value(char **flagstr, int flags) 498{ 499 int i = 0; 500 char *str = *flagstr; 501 static const char flagchars[] = "GHRDMDAC"; 502 static const unsigned flagarray[] = { 503 RTF_GATEWAY, 504 RTF_HOST, 505 RTF_REINSTATE, 506 RTF_DYNAMIC, 507 RTF_MODIFIED, 508 RTF_DEFAULT, 509 RTF_ADDRCONF, 510 RTF_CACHE 511 }; 512 *str++ = 'U'; 513 while ( (*str = flagchars[i]) ) { 514 if (flags & flagarray[i++]) ++str; 515 } 516} 517/* 518 * extract inet4 route info from /proc/net/route file and display it. 519 */ 520static void display_routes(int is_more_info, int notresolve) 521{ 522#define IPV4_MASK (RTF_GATEWAY|RTF_HOST|RTF_REINSTATE|RTF_DYNAMIC|RTF_MODIFIED) 523 unsigned long dest, gate, mask; 524 int flags, ref, use, metric, mss, win, irtt; 525 char iface[64]={0,}; 526 char *flag_val = xzalloc(10); //there are 9 flags "UGHRDMDAC" for route. 527 528 FILE *fp = xfopen("/proc/net/route", "r"); 529 xprintf("Kernel IP routing table\n" 530 "Destination Gateway Genmask Flags %s Iface\n", 531 is_more_info ? " MSS Window irtt" : "Metric Ref Use"); 532 fgets(toybuf, sizeof(toybuf), fp); //skip 1st line. 533 while (fgets(toybuf, sizeof(toybuf), fp)) { 534 int nitems = 0; 535 char *destip = NULL, *gateip = NULL, *maskip = NULL; 536 memset(flag_val, 0, 10); 537 538 nitems = sscanf(toybuf, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n", 539 iface, &dest, &gate, &flags, &ref, &use, &metric, &mask, &mss, &win, &irtt); 540 if (nitems != 11) {//EOF with no (nonspace) chars read. 541 if ((nitems < 0) && feof(fp)) break; 542 perror_exit("sscanf"); 543 } 544 //skip down interfaces. 545 if (!(flags & RTF_UP)) continue; 546 547 if (dest) {//For Destination 548 if (inet_ntop(AF_INET, &dest, toybuf, sizeof(toybuf)) ) destip = xstrdup(toybuf); 549 } else { 550 if (!notresolve) destip = xstrdup("default"); 551 else destip = xstrdup("0.0.0.0"); 552 } 553 if (gate) {//For Gateway 554 if (inet_ntop(AF_INET, &gate, toybuf, sizeof(toybuf)) ) gateip = xstrdup(toybuf); 555 } else { 556 if (!notresolve) gateip = xstrdup("*"); 557 else gateip = xstrdup("0.0.0.0"); 558 } 559 //For Mask 560 if (inet_ntop(AF_INET, &mask, toybuf, sizeof(toybuf)) ) maskip = xstrdup(toybuf); 561 562 //Get flag Values 563 get_flag_value(&flag_val, (flags & IPV4_MASK)); 564 if (flags & RTF_REJECT) flag_val[0] = '!'; 565 xprintf("%-15.15s %-15.15s %-16s%-6s", destip, gateip, maskip, flag_val); 566 if (destip) free(destip); 567 if (gateip) free(gateip); 568 if (maskip) free(maskip); 569 if (is_more_info) xprintf("%5d %-5d %6d %s\n", mss, win, irtt, iface); 570 else xprintf("%-6d %-2d %7d %s\n", metric, ref, use, iface); 571 }//end of while. 572 fclose(fp); 573 if (flag_val) free(flag_val); 574#undef IPV4_MASK 575 return; 576} 577/* 578 * netstat utily main function. 579 */ 580void netstat_main(void) 581{ 582#define IS_NETSTAT_PROTO_FLAGS_UP (toys.optflags & (FLAG_t | FLAG_u | FLAG_w | FLAG_x)) 583 int flag_listen_and_all = 0; 584 if (!toys.optflags) toys.optflags = FLAG_t | FLAG_u | FLAG_w | FLAG_x; 585 586 //When a is set 587 if (toys.optflags & FLAG_a) flag_listen_and_all = 1; 588 //when a and l both are set 589 if ( (toys.optflags & FLAG_a) && (toys.optflags & FLAG_l) ) 590 toys.optflags &= ~FLAG_l; 591 //when only a is set 592 if ( (toys.optflags & FLAG_a) && (!IS_NETSTAT_PROTO_FLAGS_UP) ) 593 toys.optflags |= FLAG_t | FLAG_u | FLAG_w | FLAG_x; 594 //when only l is set 595 if ( (toys.optflags & FLAG_l) && (!IS_NETSTAT_PROTO_FLAGS_UP) ) 596 toys.optflags |= FLAG_t | FLAG_u | FLAG_w | FLAG_x; 597 //when only e/n is set 598 if( ((toys.optflags & FLAG_e) || (toys.optflags & FLAG_n)) && (!IS_NETSTAT_PROTO_FLAGS_UP) ) 599 toys.optflags |= FLAG_t | FLAG_u | FLAG_w | FLAG_x; 600 //when W is set 601 if ( (toys.optflags & FLAG_W) && (!IS_NETSTAT_PROTO_FLAGS_UP) ) 602 toys.optflags |= FLAG_t | FLAG_u | FLAG_w | FLAG_x; 603 //when p is set 604 if ( (toys.optflags & FLAG_p) && (!IS_NETSTAT_PROTO_FLAGS_UP) ) 605 toys.optflags |= FLAG_t | FLAG_u | FLAG_w | FLAG_x; 606 607 //Display routing table. 608 if (toys.optflags & FLAG_r) { 609 display_routes(!(toys.optflags & FLAG_e), (toys.optflags & FLAG_n)); 610 return; 611 } 612 613 if (toys.optflags & FLAG_p) get_pid_list(); 614 615 //For TCP/UDP/RAW. 616 if ( (toys.optflags & FLAG_t) || (toys.optflags & FLAG_u) || (toys.optflags & FLAG_w) ) { 617 xprintf("Active Internet connections "); 618 619 if (flag_listen_and_all) xprintf("(servers and established)"); 620 else if (toys.optflags & FLAG_l) xprintf("(only servers)"); 621 else xprintf("(w/o servers)"); 622 623 show_header(); 624 if (toys.optflags & FLAG_t) {//For TCP 625 show_ipv4("/proc/net/tcp", "tcp"); 626 show_ipv6("/proc/net/tcp6", "tcp"); 627 } 628 if (toys.optflags & FLAG_u) {//For UDP 629 show_ipv4("/proc/net/udp", "udp"); 630 show_ipv6("/proc/net/udp6", "udp"); 631 } 632 if (toys.optflags & FLAG_w) {//For raw 633 show_ipv4("/proc/net/raw", "raw"); 634 show_ipv6("/proc/net/raw6", "raw"); 635 } 636 } 637 if (toys.optflags & FLAG_x) {//For UNIX. 638 xprintf("Active UNIX domain sockets "); 639 if (flag_listen_and_all) xprintf("(servers and established)"); 640 else if (toys.optflags & FLAG_l) xprintf("(only servers)"); 641 else xprintf("(w/o servers)"); 642 643 if (toys.optflags & FLAG_p) xprintf("\nProto RefCnt Flags Type State I-Node %s Path\n", PROGRAM_NAME); 644 else xprintf("\nProto RefCnt Flags Type State I-Node Path\n"); 645 show_unix_sockets("/proc/net/unix", "unix"); 646 } 647 if (toys.optflags & FLAG_p) clean_pid_list(); 648 if (toys.exitval) toys.exitval = 0; 649#undef IS_NETSTAT_PROTO_FLAGS_UP 650} 651