netstat.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini netstat implementation(s) for busybox
  4. * based in part on the netstat implementation from net-tools.
  5. *
  6. * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. *
  22. * 2002-04-20
  23. * IPV6 support added by Bart Visscher <magick@linux-fan.com>
  24. */
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <stdarg.h>
  29. #include <signal.h>
  30. #include <errno.h>
  31. #include <sys/stat.h>
  32. #include <dirent.h>
  33. #include <unistd.h>
  34. #include "inet_common.h"
  35. #include "busybox.h"
  36. #include "pwd_.h"
  37. #ifdef CONFIG_ROUTE
  38. extern void displayroutes(int noresolve, int netstatfmt);
  39. #endif
  40. #define NETSTAT_CONNECTED 0x01
  41. #define NETSTAT_LISTENING 0x02
  42. #define NETSTAT_NUMERIC 0x04
  43. #define NETSTAT_TCP 0x10
  44. #define NETSTAT_UDP 0x20
  45. #define NETSTAT_RAW 0x40
  46. #define NETSTAT_UNIX 0x80
  47. static int flags = NETSTAT_CONNECTED |
  48. NETSTAT_TCP | NETSTAT_UDP | NETSTAT_RAW | NETSTAT_UNIX;
  49. #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
  50. #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
  51. #define PROGNAME_WIDTH2(s) #s
  52. #define PRG_HASH_SIZE 211
  53. enum {
  54. TCP_ESTABLISHED = 1,
  55. TCP_SYN_SENT,
  56. TCP_SYN_RECV,
  57. TCP_FIN_WAIT1,
  58. TCP_FIN_WAIT2,
  59. TCP_TIME_WAIT,
  60. TCP_CLOSE,
  61. TCP_CLOSE_WAIT,
  62. TCP_LAST_ACK,
  63. TCP_LISTEN,
  64. TCP_CLOSING /* now a valid state */
  65. };
  66. static const char * const tcp_state[] =
  67. {
  68. "",
  69. "ESTABLISHED",
  70. "SYN_SENT",
  71. "SYN_RECV",
  72. "FIN_WAIT1",
  73. "FIN_WAIT2",
  74. "TIME_WAIT",
  75. "CLOSE",
  76. "CLOSE_WAIT",
  77. "LAST_ACK",
  78. "LISTEN",
  79. "CLOSING"
  80. };
  81. typedef enum {
  82. SS_FREE = 0, /* not allocated */
  83. SS_UNCONNECTED, /* unconnected to any socket */
  84. SS_CONNECTING, /* in process of connecting */
  85. SS_CONNECTED, /* connected to socket */
  86. SS_DISCONNECTING /* in process of disconnecting */
  87. } socket_state;
  88. #define SO_ACCEPTCON (1<<16) /* performed a listen */
  89. #define SO_WAITDATA (1<<17) /* wait data to read */
  90. #define SO_NOSPACE (1<<18) /* no space to write */
  91. static char *itoa(unsigned int i)
  92. {
  93. /* 21 digits plus null terminator, good for 64-bit or smaller ints */
  94. static char local[22];
  95. char *p = &local[21];
  96. *p-- = '\0';
  97. do {
  98. *p-- = '0' + i % 10;
  99. i /= 10;
  100. } while (i > 0);
  101. return p + 1;
  102. }
  103. static char *get_sname(int port, const char *proto, int num)
  104. {
  105. char *str=itoa(ntohs(port));
  106. if (num) {
  107. } else {
  108. struct servent *se=getservbyport(port,proto);
  109. if (se)
  110. str=se->s_name;
  111. }
  112. if (!port) {
  113. str="*";
  114. }
  115. return str;
  116. }
  117. static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int port, char *proto, int numeric)
  118. {
  119. char *port_name;
  120. #ifdef CONFIG_FEATURE_IPV6
  121. if (addr->sa_family == AF_INET6) {
  122. INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
  123. (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
  124. } else
  125. #endif
  126. {
  127. INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
  128. 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
  129. 0xffffffff);
  130. }
  131. port_name=get_sname(htons(port), proto, numeric);
  132. if ((strlen(ip_port) + strlen(port_name)) > 22)
  133. ip_port[22 - strlen(port_name)] = '\0';
  134. ip_port+=strlen(ip_port);
  135. strcat(ip_port, ":");
  136. strcat(ip_port, port_name);
  137. }
  138. static void tcp_do_one(int lnr, const char *line)
  139. {
  140. char local_addr[64], rem_addr[64];
  141. const char *state_str;
  142. char more[512];
  143. int num, local_port, rem_port, d, state, timer_run, uid, timeout;
  144. #ifdef CONFIG_FEATURE_IPV6
  145. struct sockaddr_in6 localaddr, remaddr;
  146. char addr6[INET6_ADDRSTRLEN];
  147. struct in6_addr in6;
  148. #else
  149. struct sockaddr_in localaddr, remaddr;
  150. #endif
  151. unsigned long rxq, txq, time_len, retr, inode;
  152. if (lnr == 0)
  153. return;
  154. more[0] = '\0';
  155. num = sscanf(line,
  156. "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
  157. &d, local_addr, &local_port,
  158. rem_addr, &rem_port, &state,
  159. &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
  160. if (strlen(local_addr) > 8) {
  161. #ifdef CONFIG_FEATURE_IPV6
  162. sscanf(local_addr, "%08X%08X%08X%08X",
  163. &in6.s6_addr32[0], &in6.s6_addr32[1],
  164. &in6.s6_addr32[2], &in6.s6_addr32[3]);
  165. inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
  166. inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
  167. sscanf(rem_addr, "%08X%08X%08X%08X",
  168. &in6.s6_addr32[0], &in6.s6_addr32[1],
  169. &in6.s6_addr32[2], &in6.s6_addr32[3]);
  170. inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
  171. inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
  172. localaddr.sin6_family = AF_INET6;
  173. remaddr.sin6_family = AF_INET6;
  174. #endif
  175. } else {
  176. sscanf(local_addr, "%X",
  177. &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
  178. sscanf(rem_addr, "%X",
  179. &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
  180. ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
  181. ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
  182. }
  183. if (num < 10) {
  184. bb_error_msg("warning, got bogus tcp line.");
  185. return;
  186. }
  187. state_str = tcp_state[state];
  188. if ((rem_port && (flags&NETSTAT_CONNECTED)) ||
  189. (!rem_port && (flags&NETSTAT_LISTENING)))
  190. {
  191. snprint_ip_port(local_addr, sizeof(local_addr),
  192. (struct sockaddr *) &localaddr, local_port,
  193. "tcp", flags&NETSTAT_NUMERIC);
  194. snprint_ip_port(rem_addr, sizeof(rem_addr),
  195. (struct sockaddr *) &remaddr, rem_port,
  196. "tcp", flags&NETSTAT_NUMERIC);
  197. printf("tcp %6ld %6ld %-23s %-23s %-12s\n",
  198. rxq, txq, local_addr, rem_addr, state_str);
  199. }
  200. }
  201. static void udp_do_one(int lnr, const char *line)
  202. {
  203. char local_addr[64], rem_addr[64];
  204. char *state_str, more[512];
  205. int num, local_port, rem_port, d, state, timer_run, uid, timeout;
  206. #ifdef CONFIG_FEATURE_IPV6
  207. struct sockaddr_in6 localaddr, remaddr;
  208. char addr6[INET6_ADDRSTRLEN];
  209. struct in6_addr in6;
  210. #else
  211. struct sockaddr_in localaddr, remaddr;
  212. #endif
  213. unsigned long rxq, txq, time_len, retr, inode;
  214. if (lnr == 0)
  215. return;
  216. more[0] = '\0';
  217. num = sscanf(line,
  218. "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
  219. &d, local_addr, &local_port,
  220. rem_addr, &rem_port, &state,
  221. &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
  222. if (strlen(local_addr) > 8) {
  223. #ifdef CONFIG_FEATURE_IPV6
  224. /* Demangle what the kernel gives us */
  225. sscanf(local_addr, "%08X%08X%08X%08X",
  226. &in6.s6_addr32[0], &in6.s6_addr32[1],
  227. &in6.s6_addr32[2], &in6.s6_addr32[3]);
  228. inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
  229. inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
  230. sscanf(rem_addr, "%08X%08X%08X%08X",
  231. &in6.s6_addr32[0], &in6.s6_addr32[1],
  232. &in6.s6_addr32[2], &in6.s6_addr32[3]);
  233. inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
  234. inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
  235. localaddr.sin6_family = AF_INET6;
  236. remaddr.sin6_family = AF_INET6;
  237. #endif
  238. } else {
  239. sscanf(local_addr, "%X",
  240. &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
  241. sscanf(rem_addr, "%X",
  242. &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
  243. ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
  244. ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
  245. }
  246. if (num < 10) {
  247. bb_error_msg("warning, got bogus udp line.");
  248. return;
  249. }
  250. switch (state) {
  251. case TCP_ESTABLISHED:
  252. state_str = "ESTABLISHED";
  253. break;
  254. case TCP_CLOSE:
  255. state_str = "";
  256. break;
  257. default:
  258. state_str = "UNKNOWN";
  259. break;
  260. }
  261. #ifdef CONFIG_FEATURE_IPV6
  262. # define notnull(A) (((A.sin6_family == AF_INET6) && \
  263. ((A.sin6_addr.s6_addr32[0]) || \
  264. (A.sin6_addr.s6_addr32[1]) || \
  265. (A.sin6_addr.s6_addr32[2]) || \
  266. (A.sin6_addr.s6_addr32[3]))) || \
  267. ((A.sin6_family == AF_INET) && \
  268. ((struct sockaddr_in *) &A)->sin_addr.s_addr))
  269. #else
  270. # define notnull(A) (A.sin_addr.s_addr)
  271. #endif
  272. if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
  273. (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
  274. {
  275. snprint_ip_port(local_addr, sizeof(local_addr),
  276. (struct sockaddr *) &localaddr, local_port,
  277. "udp", flags&NETSTAT_NUMERIC);
  278. snprint_ip_port(rem_addr, sizeof(rem_addr),
  279. (struct sockaddr *) &remaddr, rem_port,
  280. "udp", flags&NETSTAT_NUMERIC);
  281. printf("udp %6ld %6ld %-23s %-23s %-12s\n",
  282. rxq, txq, local_addr, rem_addr, state_str);
  283. }
  284. }
  285. static void raw_do_one(int lnr, const char *line)
  286. {
  287. char local_addr[64], rem_addr[64];
  288. char *state_str, more[512];
  289. int num, local_port, rem_port, d, state, timer_run, uid, timeout;
  290. #ifdef CONFIG_FEATURE_IPV6
  291. struct sockaddr_in6 localaddr, remaddr;
  292. char addr6[INET6_ADDRSTRLEN];
  293. struct in6_addr in6;
  294. #else
  295. struct sockaddr_in localaddr, remaddr;
  296. #endif
  297. unsigned long rxq, txq, time_len, retr, inode;
  298. if (lnr == 0)
  299. return;
  300. more[0] = '\0';
  301. num = sscanf(line,
  302. "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n",
  303. &d, local_addr, &local_port,
  304. rem_addr, &rem_port, &state,
  305. &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
  306. if (strlen(local_addr) > 8) {
  307. #ifdef CONFIG_FEATURE_IPV6
  308. sscanf(local_addr, "%08X%08X%08X%08X",
  309. &in6.s6_addr32[0], &in6.s6_addr32[1],
  310. &in6.s6_addr32[2], &in6.s6_addr32[3]);
  311. inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
  312. inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
  313. sscanf(rem_addr, "%08X%08X%08X%08X",
  314. &in6.s6_addr32[0], &in6.s6_addr32[1],
  315. &in6.s6_addr32[2], &in6.s6_addr32[3]);
  316. inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
  317. inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
  318. localaddr.sin6_family = AF_INET6;
  319. remaddr.sin6_family = AF_INET6;
  320. #endif
  321. } else {
  322. sscanf(local_addr, "%X",
  323. &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
  324. sscanf(rem_addr, "%X",
  325. &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr);
  326. ((struct sockaddr *) &localaddr)->sa_family = AF_INET;
  327. ((struct sockaddr *) &remaddr)->sa_family = AF_INET;
  328. }
  329. if (num < 10) {
  330. bb_error_msg("warning, got bogus raw line.");
  331. return;
  332. }
  333. state_str=itoa(state);
  334. #ifdef CONFIG_FEATURE_IPV6
  335. # define notnull(A) (((A.sin6_family == AF_INET6) && \
  336. ((A.sin6_addr.s6_addr32[0]) || \
  337. (A.sin6_addr.s6_addr32[1]) || \
  338. (A.sin6_addr.s6_addr32[2]) || \
  339. (A.sin6_addr.s6_addr32[3]))) || \
  340. ((A.sin6_family == AF_INET) && \
  341. ((struct sockaddr_in *) &A)->sin_addr.s_addr))
  342. #else
  343. # define notnull(A) (A.sin_addr.s_addr)
  344. #endif
  345. if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
  346. (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
  347. {
  348. snprint_ip_port(local_addr, sizeof(local_addr),
  349. (struct sockaddr *) &localaddr, local_port,
  350. "raw", flags&NETSTAT_NUMERIC);
  351. snprint_ip_port(rem_addr, sizeof(rem_addr),
  352. (struct sockaddr *) &remaddr, rem_port,
  353. "raw", flags&NETSTAT_NUMERIC);
  354. printf("raw %6ld %6ld %-23s %-23s %-12s\n",
  355. rxq, txq, local_addr, rem_addr, state_str);
  356. }
  357. }
  358. #define HAS_INODE 1
  359. static void unix_do_one(int nr, const char *line)
  360. {
  361. static int has = 0;
  362. char path[PATH_MAX], ss_flags[32];
  363. char *ss_proto, *ss_state, *ss_type;
  364. int num, state, type, inode;
  365. void *d;
  366. unsigned long refcnt, proto, unix_flags;
  367. if (nr == 0) {
  368. if (strstr(line, "Inode"))
  369. has |= HAS_INODE;
  370. return;
  371. }
  372. path[0] = '\0';
  373. num = sscanf(line, "%p: %lX %lX %lX %X %X %d %s",
  374. &d, &refcnt, &proto, &unix_flags, &type, &state, &inode, path);
  375. if (num < 6) {
  376. bb_error_msg("warning, got bogus unix line.");
  377. return;
  378. }
  379. if (!(has & HAS_INODE))
  380. snprintf(path,sizeof(path),"%d",inode);
  381. if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))!=(NETSTAT_LISTENING|NETSTAT_CONNECTED)) {
  382. if ((state == SS_UNCONNECTED) && (unix_flags & SO_ACCEPTCON)) {
  383. if (!(flags&NETSTAT_LISTENING))
  384. return;
  385. } else {
  386. if (!(flags&NETSTAT_CONNECTED))
  387. return;
  388. }
  389. }
  390. switch (proto) {
  391. case 0:
  392. ss_proto = "unix";
  393. break;
  394. default:
  395. ss_proto = "??";
  396. }
  397. switch (type) {
  398. case SOCK_STREAM:
  399. ss_type = "STREAM";
  400. break;
  401. case SOCK_DGRAM:
  402. ss_type = "DGRAM";
  403. break;
  404. case SOCK_RAW:
  405. ss_type = "RAW";
  406. break;
  407. case SOCK_RDM:
  408. ss_type = "RDM";
  409. break;
  410. case SOCK_SEQPACKET:
  411. ss_type = "SEQPACKET";
  412. break;
  413. default:
  414. ss_type = "UNKNOWN";
  415. }
  416. switch (state) {
  417. case SS_FREE:
  418. ss_state = "FREE";
  419. break;
  420. case SS_UNCONNECTED:
  421. /*
  422. * Unconnected sockets may be listening
  423. * for something.
  424. */
  425. if (unix_flags & SO_ACCEPTCON) {
  426. ss_state = "LISTENING";
  427. } else {
  428. ss_state = "";
  429. }
  430. break;
  431. case SS_CONNECTING:
  432. ss_state = "CONNECTING";
  433. break;
  434. case SS_CONNECTED:
  435. ss_state = "CONNECTED";
  436. break;
  437. case SS_DISCONNECTING:
  438. ss_state = "DISCONNECTING";
  439. break;
  440. default:
  441. ss_state = "UNKNOWN";
  442. }
  443. strcpy(ss_flags, "[ ");
  444. if (unix_flags & SO_ACCEPTCON)
  445. strcat(ss_flags, "ACC ");
  446. if (unix_flags & SO_WAITDATA)
  447. strcat(ss_flags, "W ");
  448. if (unix_flags & SO_NOSPACE)
  449. strcat(ss_flags, "N ");
  450. strcat(ss_flags, "]");
  451. printf("%-5s %-6ld %-11s %-10s %-13s ",
  452. ss_proto, refcnt, ss_flags, ss_type, ss_state);
  453. if (has & HAS_INODE)
  454. printf("%-6d ",inode);
  455. else
  456. printf("- ");
  457. puts(path);
  458. }
  459. #define _PATH_PROCNET_UDP "/proc/net/udp"
  460. #define _PATH_PROCNET_UDP6 "/proc/net/udp6"
  461. #define _PATH_PROCNET_TCP "/proc/net/tcp"
  462. #define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
  463. #define _PATH_PROCNET_RAW "/proc/net/raw"
  464. #define _PATH_PROCNET_RAW6 "/proc/net/raw6"
  465. #define _PATH_PROCNET_UNIX "/proc/net/unix"
  466. static void do_info(const char *file, const char *name, void (*proc)(int, const char *))
  467. {
  468. char buffer[8192];
  469. int lnr = 0;
  470. FILE *procinfo;
  471. procinfo = fopen(file, "r");
  472. if (procinfo == NULL) {
  473. if (errno != ENOENT) {
  474. perror(file);
  475. } else {
  476. bb_error_msg("no support for `%s' on this system.", name);
  477. }
  478. } else {
  479. do {
  480. if (fgets(buffer, sizeof(buffer), procinfo))
  481. (proc)(lnr++, buffer);
  482. } while (!feof(procinfo));
  483. fclose(procinfo);
  484. }
  485. }
  486. /*
  487. * Our main function.
  488. */
  489. int netstat_main(int argc, char **argv)
  490. {
  491. int opt;
  492. int new_flags=0;
  493. int showroute = 0, extended = 0;
  494. #ifdef CONFIG_FEATURE_IPV6
  495. int inet=1;
  496. int inet6=1;
  497. #else
  498. # define inet 1
  499. # define inet6 0
  500. #endif
  501. while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
  502. switch (opt) {
  503. case 'l':
  504. flags &= ~NETSTAT_CONNECTED;
  505. flags |= NETSTAT_LISTENING;
  506. break;
  507. case 'a':
  508. flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED;
  509. break;
  510. case 'n':
  511. flags |= NETSTAT_NUMERIC;
  512. break;
  513. case 'r':
  514. showroute = 1;
  515. break;
  516. case 'e':
  517. extended = 1;
  518. break;
  519. case 't':
  520. new_flags |= NETSTAT_TCP;
  521. break;
  522. case 'u':
  523. new_flags |= NETSTAT_UDP;
  524. break;
  525. case 'w':
  526. new_flags |= NETSTAT_RAW;
  527. break;
  528. case 'x':
  529. new_flags |= NETSTAT_UNIX;
  530. break;
  531. default:
  532. bb_show_usage();
  533. }
  534. if ( showroute ) {
  535. #ifdef CONFIG_ROUTE
  536. displayroutes ( flags & NETSTAT_NUMERIC, !extended );
  537. return 0;
  538. #else
  539. bb_error_msg_and_die( "-r (display routing table) is not compiled in." );
  540. #endif
  541. }
  542. if (new_flags) {
  543. flags &= ~(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW|NETSTAT_UNIX);
  544. flags |= new_flags;
  545. }
  546. if (flags&(NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
  547. printf("Active Internet connections "); /* xxx */
  548. if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
  549. printf("(servers and established)");
  550. else {
  551. if (flags&NETSTAT_LISTENING)
  552. printf("(only servers)");
  553. else
  554. printf("(w/o servers)");
  555. }
  556. printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
  557. }
  558. if (inet && flags&NETSTAT_TCP)
  559. do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
  560. #ifdef CONFIG_FEATURE_IPV6
  561. if (inet6 && flags&NETSTAT_TCP)
  562. do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
  563. #endif
  564. if (inet && flags&NETSTAT_UDP)
  565. do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
  566. #ifdef CONFIG_FEATURE_IPV6
  567. if (inet6 && flags&NETSTAT_UDP)
  568. do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
  569. #endif
  570. if (inet && flags&NETSTAT_RAW)
  571. do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
  572. #ifdef CONFIG_FEATURE_IPV6
  573. if (inet6 && flags&NETSTAT_RAW)
  574. do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
  575. #endif
  576. if (flags&NETSTAT_UNIX) {
  577. printf("Active UNIX domain sockets ");
  578. if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
  579. printf("(servers and established)");
  580. else {
  581. if (flags&NETSTAT_LISTENING)
  582. printf("(only servers)");
  583. else
  584. printf("(w/o servers)");
  585. }
  586. printf("\nProto RefCnt Flags Type State I-Node Path\n");
  587. do_info(_PATH_PROCNET_UNIX,"AF UNIX",unix_do_one);
  588. }
  589. return 0;
  590. }