Android的从源码中看的netstat命令
上一篇中介绍了android通过命令netstat查看应用访问过的ip和端口。这篇通过源码来分析nestat是如何实现的。在源码中找到/external/toybox/toys/pending/netstat.c。先来看看主函数
void netstat_main(void) { int tuwx = FLAG_t|FLAG_u|FLAG_w|FLAG_x; char *type = "w/o"; TT.wpad = (toys.optflags&FLAG_W) ? 51 : 23; if (!(toys.optflags&(FLAG_r|tuwx))) toys.optflags |= tuwx; if (toys.optflags & FLAG_r) display_routes(); if (!(toys.optflags&tuwx)) return; if (toys.optflags & FLAG_a) type = "established and"; else if (toys.optflags & FLAG_l) type = "only"; if (toys.optflags & FLAG_p) dirtree_read("/proc", scan_pids); if (toys.optflags&(FLAG_t|FLAG_u|FLAG_w)) { printf("Active %s (%s servers)\n", "Internet connections", type); printf("Proto Recv-Q Send-Q %*s %*s State ", -TT.wpad, "Local Address", -TT.wpad, "Foreign Address"); if (toys.optflags & FLAG_e) printf(" User Inode "); if (toys.optflags & FLAG_p) printf(" PID/Program Name"); xputc('\n'); if (toys.optflags & FLAG_t) { show_ip("/proc/net/tcp"); show_ip("/proc/net/tcp6"); } if (toys.optflags & FLAG_u) { show_ip("/proc/net/udp"); show_ip("/proc/net/udp6"); } if (toys.optflags & FLAG_w) { show_ip("/proc/net/raw"); show_ip("/proc/net/raw6"); } } if (toys.optflags & FLAG_x) { printf("Active %s (%s servers)\n", "UNIX domain sockets", type); printf("Proto RefCnt Flags\t Type\t State\t %s Path\n", (toys.optflags&FLAG_p) ? "PID/Program Name" : "I-Node"); show_unix_sockets(); } if ((toys.optflags & FLAG_p) && CFG_TOYBOX_FREE) llist_traverse(TT.inodes, free); toys.exitval = 0; }
从主函数中,netstat命令可以打印出3种类型的数据,分别是TCP,UDP,RAW。然后调用了show_ip函数,接下来我们看看show_ip
// Display info for tcp/udp/raw static void show_ip(char *fname) { char *ss_state = "UNKNOWN", buf[12], *s, *label = strrchr(fname, '/')+1; char *state_label[] = {"", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2", "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING", "UNKNOWN"}; struct passwd *pw; FILE *fp = fopen(fname, "r"); if (!fp) { perror_msg("'%s'", fname); return; } if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header. while (fgets(toybuf, sizeof(toybuf), fp)) { char lip[256], rip[256]; union { struct {unsigned u; unsigned char b[4];} i4; struct {struct {unsigned a, b, c, d;} u; unsigned char b[16];} i6; } laddr, raddr; unsigned lport, rport, state, txq, rxq, num, uid, nitems; unsigned long inode; // Try ipv6, then try ipv4 nitems = sscanf(toybuf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x %*X:%*X %*X %d %*d %ld", &num, &laddr.i6.u.a, &laddr.i6.u.b, &laddr.i6.u.c, &laddr.i6.u.d, &lport, &raddr.i6.u.a, &raddr.i6.u.b, &raddr.i6.u.c, &raddr.i6.u.d, &rport, &state, &txq, &rxq, &uid, &inode); if (nitems!=16) { nitems = sscanf(toybuf, " %d: %x:%x %x:%x %x %x:%x %*X:%*X %*X %d %*d %ld", &num, &laddr.i4.u, &lport, &raddr.i4.u, &rport, &state, &txq, &rxq, &uid, &inode); if (nitems!=10) continue; nitems = AF_INET; } else nitems = AF_INET6; // Should we display this? (listening or all or TCP/UDP/RAW) if (!((toys.optflags & FLAG_l) && (!rport && (state & 0xA))) && !(toys.optflags & FLAG_a) && !(rport & (0x10 | 0x20 | 0x40))) continue; addr2str(nitems, &laddr, lport, lip, TT.wpad, label); addr2str(nitems, &raddr, rport, rip, TT.wpad, label); // Display data s = label; if (strstart(&s, "tcp")) { int sz = ARRAY_LEN(state_label); if (!state || state >= sz) state = sz-1; ss_state = state_label[state]; } else if (strstart(&s, "udp")) { if (state == 1) ss_state = state_label[state]; else if (state == 7) ss_state = ""; } else if (strstart(&s, "raw")) sprintf(ss_state = buf, "%u", state); if (!(toys.optflags & FLAG_n) && (pw = bufgetpwuid(uid))) snprintf(toybuf, sizeof(toybuf), "%s", pw->pw_name); else snprintf(toybuf, sizeof(toybuf), "%d", uid); printf("%-6s%6d%7d ", label, rxq, txq); printf("%*.*s %*.*s ", -TT.wpad, TT.wpad, lip, -TT.wpad, TT.wpad, rip); printf("%-11s", ss_state); if ((toys.optflags & FLAG_e)) printf(" %-10s %-11ld", toybuf, inode); if ((toys.optflags & FLAG_p)) { struct num_cache *nc = get_num_cache(TT.inodes, inode); printf(" %s", nc ? nc->data : "-"); } xputc('\n'); } fclose(fp); }
从show_ip函数中,netstat通过读取以下系统文件来获取数据,然后通过sscanf函数,将各个项的数据读取出来。最后通过传入main函数中的参数,过滤出需要显示的数据
/proc/net/tcp
/proc/net/tcp6
/proc/net/udp"
/proc/net/udp6"
/proc/net/raw"
/proc/net/raw6"
那么以上文件中都有哪些项,在终端中输入adb shell,然后输入cat /proc/net/tcp。

从截图中,可以看到有本地地址和端口,远程地址和端口,应用UID还有其他的信息详细参考:https://blog.youkuaiyun.com/justlinux2010/article/details/21028797
上一篇:android通过命令netstat查看应用访问过的ip和端口
下一篇:android如何通过代码来获取每个应用访问过的ip和端口