netstat工具源码剖析——网络诊断必备

简介:

netstat工具源码剖析

netstat是监控TCP/IP网络的工具,可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息。用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。

网上关于netstat工具使用的文章多如牛毛,但是针对工具剖析的却没有,一篇难找。古人说:工欲善其事必先利其器。那么我们一起来分析吧。

netstat的源码位于net-tools工具包中,这是linux网络的基本工具包,此外还包括arp,hostname,route等命令。

  项目链接:http://net-tools.sourceforge.net/

            下载地址:https://sourceforge.net/projects/net-tools/files/latest/download

1.1.1 编译

下载后解压,可以直接进行编译了。

make netstat;可以进行netstat编译。

make ifconfig;可以编译ifconfig。

编译过程中可以选择部分选项,例如需要使用-M参数,那么在config.h文件中将#define HAVE_FW_MASQUERADE 0,如果要编译就设置为1就好了。

编译时候出错需要进行如下修改:

1、在lib/inet_src.c中,108行加入break;

    107     default:

108        break;

2、在lib/x25_sr.c  

80 memcpy(&rt.address, &sx25.sx25_addr, sizeof(x25_address));

为:

memcpy(&rt.address, &sx25.sx25_addr, sizeof(sx25.sx25_addr));

     我们查看makefile文件如下:

NET_LIB = $(NET_LIB_PATH)/lib$(NET_LIB_NAME).a

NET_LIB_PATH = lib

NET_LIB_NAME = net-tools

CC      = gcc

LDFLAGS = $(LOPTS) -L$(NET_LIB_PATH)

netstat:        $(NET_LIB) netstat.o statistics.o

                $(CC) $(LDFLAGS) -o netstat netstat.o statistics.o $(NLIB) $(RESLIB)

     其主要两个程序文件是statistics.cnetstat.c

     当然还有一些相关的函数都是位于lib文件夹中的。

     相关的系统文件目录在lib/pathnames.h文件中

     打印伪链接信息的实现函数位于lib/masq_info.c中,有print_masq函数、read_masqinfo函数、ip_masq_info函数三个函数。

1.1.2 statistics数据结构和部分函数

statistics.c文件中定义了统计信息相关的数据结构和函数,提供为netstat.c文件使用。

enum State {

    number = 0, opt_number, i_forward, i_inp_icmp, i_outp_icmp, i_rto_alg,

    MaxState

};

struct entry {

    char *title;

    char *out;

    enum State type;

};

struct statedesc {

    int indent;

    char *title;

};

struct entry Iptab[]

struct entry Icmptab[]

struct entry Tcptab[]

struct entry Udptab[]

struct entry Tcpexttab[]

tabtab结构体,合入了entry

struct tabtab {

    char *title;

    struct entry *tab;

    size_t size;

    int *flag;

};

struct tabtab snmptabs[]tabtab结构体的数组。

struct tabtab snmptabs[] =

{

    {"Ip", Iptab, sizeof(Iptab), &f_raw},

    {"Icmp", Icmptab, sizeof(Icmptab), &f_raw},

    {"Tcp", Tcptab, sizeof(Tcptab), &f_tcp},

    {"Udp", Udptab, sizeof(Udptab), &f_udp},

    {"TcpExt", Tcpexttab, sizeof(Tcpexttab), &f_tcp},

    {NULL}

};

 

414dedb2b421d406118a75c9ee78abe88ac73f07

1.1.2.1  函数

inittab函数通过qsort函数将IptabIcmptab,Tcptab,Udptab,Tcpexttab进行排序.

Parsesnmp函数入参为三个整数,主要用于打开/proc/net/snmp文件和/proc/net/netstat,将句柄交给process_fd函数进行处理。通过/proc/net/snmp文件可以得到各层网络协议的收发包的情况。

     Printval函数将值进行打印.

1.1.3 main主程序逻辑

位于netstat.c文件的main函数中,

     先定义了一个选择结构体数组,结构体由系统提供:

struct option

{

  const char *name;

  /* has_arg can't be an enum because some compilers complain about

     type mismatches in all the code that assumes it is an int.  */

  int has_arg;

  int *flag;

  int val;

};

然后通过getopt_long函数来获取命令行参数。设置相关变量,例如flag_tcp++,flag_udp++等等。

判断变量设置合理性,有些参数不能同时设置,例如flag_int flag_rouflag_masflag_sta分别是接口表、路由表、伪ip、静态统计数据等。

    if (flag_int + flag_rou + flag_mas + flag_sta > 1)

        usage();

     然后根据这些相关变量,执行对应的函数。

     例如:

    if (flag_int) {

        for (;;) {

            i = iface_info();

            if (!flag_cnt || i)

                break;

            sleep(1);

        }   

        return (i);

    }  

     每个变量判断其是否被设置,最后会去系统的相应路径文件中获取信息。

#define _PATH_PROCNET_IGMP              "/proc/net/igmp"

#define _PATH_PROCNET_IGMP6             "/proc/net/igmp6"

#define _PATH_PROCNET_TCP               "/proc/net/tcp"

#define _PATH_PROCNET_TCP6              "/proc/net/tcp6"

#define _PATH_PROCNET_UDP               "/proc/net/udp"

#define _PATH_PROCNET_UDP6              "/proc/net/udp6"

#define _PATH_PROCNET_RAW               "/proc/net/raw"

#define _PATH_PROCNET_RAW6              "/proc/net/raw6"

#define _PATH_PROCNET_UNIX              "/proc/net/unix"

#define _PATH_PROCNET_ROUTE             "/proc/net/route"

#define _PATH_PROCNET_ROUTE6            "/proc/net/ipv6_route"

#define _PATH_PROCNET_RTCACHE           "/proc/net/rt_cache"

#define _PATH_PROCNET_AX25_ROUTE        "/proc/net/ax25_route"

#define _PATH_PROCNET_NR                "/proc/net/nr"

#define _PATH_PROCNET_NR_NEIGH          "/proc/net/nr_neigh"

#define _PATH_PROCNET_NR_NODES          "/proc/net/nr_nodes"

#define _PATH_PROCNET_ARP               "/proc/net/arp"

#define _PATH_PROCNET_AX25              "/proc/net/ax25"

#define _PATH_PROCNET_IPX               "/proc/net/ipx"

#define _PATH_PROCNET_IPX_ROUTE         "/proc/net/ipx_route"

#define _PATH_PROCNET_ATALK             "/proc/net/appletalk"

#define _PATH_PROCNET_IP_BLK            "/proc/net/ip_block"

#define _PATH_PROCNET_IP_FWD            "/proc/net/ip_forward"

#define _PATH_PROCNET_IP_ACC            "/proc/net/ip_acct"

#define _PATH_PROCNET_IP_MASQ           "/proc/net/ip_masquerade"

#define _PATH_PROCNET_NDISC             "/proc/net/ndisc"

#define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"

#define _PATH_PROCNET_DEV               "/proc/net/dev"

#define _PATH_PROCNET_RARP              "/proc/net/rarp"

#define _PATH_ETHERS                    "/etc/ethers"

#define _PATH_PROCNET_ROSE_ROUTE        "/proc/net/rose_routes"

#define _PATH_PROCNET_X25              "/proc/net/x25"

#define _PATH_PROCNET_X25_ROUTE                "/proc/net/x25_routes"

#define _PATH_PROCNET_DEV_MCAST         "/proc/net/dev_mcast"

/* pathname for the netlink device */

#define _PATH_DEV_ROUTE "/dev/route"

1.1.4 tcp链接显示

以netstat中-t参数为例,在main函数中看到是tcp_info()函数,我们调试下这个函数,为其添加打印信息:

static int tcp_info(void)

{

    printf("xxxdebug: tcp_info\n");

    INFO_GUTS6(_PATH_PROCNET_TCP, _PATH_PROCNET_TCP6, "AF INET (tcp)",

               tcp_do_one);

}

其打开的路径为_PATH_PROCNET_TCP_PATH_PROCNET_TCP6,其中tcp_do_one为回调函数。

#define _PATH_PROCNET_TCP               "/proc/net/tcp"

函数INFO_GUTS6定义如下:

#define INFO_GUTS6(file,file6,name,proc)                \

 char buffer[8192];                                     \

 int rc = 0;                                            \

 int lnr = 0;                                           \

 if (!flag_arg || flag_inet) {                          \

    INFO_GUTS1(file,name,proc)                          \

 }                                                      \

 if (!flag_arg || flag_inet6) {                         \

    INFO_GUTS2(file6,proc)                              \

 }                                                      \

 INFO_GUTS3

根据变量情况,调用INFO_GUTS1或者INFO_GUTS2。

 最后调用tcp_do_one函数。

在 tcp_do_one函数最后加入一行打印:

printf("xxxdebug: tcp_do_one\n");

编译后运行:#netstat -t

# ./netstat -t

Active Internet connections (w/o servers)

Proto Recv-Q Send-Q Local Address           Foreign Address         State     

xxxdebug: tcp_info

xxxdebug: tcp_do_one

xxxdebug: tcp_do_one

xxxdebug: tcp_do_one

tcp      401      0 xxxxxxxxxx    CLOSE_WAIT 

xxxdebug: tcp_do_one

tcp        0      0 xxxxxxxxxxx     ESTABLISHED

xxxdebug: tcp_do_one

tcp        0      0 xxxxxxxxxxxx    ESTABLISHED

xxxdebug: tcp_do_one

tcp        0      0 xxxxxxxxxxxx      ESTABLISHED

xxxdebug: tcp_do_one

tcp      361      0 xxxxxxxxxxxx      CLOSE_WAIT 

xxxdebug: tcp_do_one

这里看到tcp_do_one执行了8次,因为在/proc/net/tcp文件有8行,

# cat /proc/net/tcp

  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                    

   0: 0100007F:0CEA 00000000:0000 0A 00000000:00000000 00:00000000 00000000   110        0 32096415 1 ffff880078c04000 100 0 0 10 0                 

   1: 00000000:006F 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 47126999 1 ffff880078ef0780 100 0 0 10 0                 

   2: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 35410755 1 ffff88000477f480 100 0 0 10 0                 

   3: 98CD13AC:E05A CD8CCD8C:0050 08 00000000:00000191 00:00000000 00000000     0        0 63139333 1 ffff8800369ac780 20 4 28 10 -1                 

   4: 98CD13AC:0016 FF47643A:C8FA 01 00000000:00000000 02:0007E41B 00000000     0        0 63635147 3 ffff88007c1e4f00 22 4 29 10 7                 

   5: 98CD13AC:0016 FF47643A:C6B8 01 00000000:00000000 02:0006FDB5 00000000     0        0 63634584 2 ffff88007c1e4000 21 4 27 6 4                  

   6: 98CD13AC:C88E 0D440B6A:0050 01 00000000:00000000 00:00000000 00000000     0        0 63158811 1 ffff8800369af480 20 4 31 10 18                

   7: 98CD13AC:DF24 0D440B6A:0050 08 00000000:00000169 00:00000000 00000000     0        0 17490053 1 ffff880005547480 20 4 28 10 13 

而在INFO_GUTS1函数中会根据/proc/net/tcp内容进行循环:

#define INFO_GUTS1(file,name,proc)                      \

  procinfo = fopen((file), "r");                        \

  if (procinfo == NULL) {                               \

    if (errno != ENOENT) {                              \

      perror((file));                                   \

      return -1;                                        \

    }                                                   \

    if (flag_arg || flag_ver)                           \

      ESYSNOT("netstat", (name));                       \

    if (flag_arg)                                       \

      rc = 1;                                           \

  } else {                                              \

    do {                                                \

      if (fgets(buffer, sizeof(buffer), procinfo))      \

        (proc)(lnr++, buffer);                          \

    } while (!feof(procinfo));                          \

    fclose(procinfo);                                   \

  }

            好了,后面大家有对某个参数感兴趣的也可以同理的去查看源码,看看执行路径。

            netstat主要是对/proc/net/下面的文件进行解析显示,让人可以更加直观的看到当前网络的使用情况。

1.1.5 参数选项

最后将netstat常用的参数附上。具体详细的使用下一章会继续。

-a或--all:显示所有连线中的Socket;

-A<网络类型>或--<网络类型>:列出该网络类型连线中的相关地址;

-c或--continuous:持续列出网络状态;

-C或--cache:显示路由器配置的快取信息;

-e或--extend:显示网络其他相关信息;

-F或--fib:显示FIB;

-g或--groups:显示多重广播功能群组组员名单;

-h或--help:在线帮助;

-i或--interfaces:显示网络界面信息表单;

-l或--listening:显示监控中的服务器的Socket;

-M或--masquerade:显示伪装的网络连线;

-n或--numeric:直接使用ip地址,而不通过域名服务器;

-N或--netlink或--symbolic:显示网络硬件外围设备的符号连接名称;

-o或--timers:显示计时器;

-p或--programs:显示正在使用Socket的程序识别码和程序名称;

-r或--route:显示Routing Table;

-s或--statistice:显示网络工作信息统计表;

-t或--tcp:显示TCP传输协议的连线状况;

-u或--udp:显示UDP传输协议的连线状况;

-v或--verbose:显示指令执行过程;

-V或--version:显示版本信息;

-w或--raw:显示RAW传输协议的连线状况;

-x或--unix:此参数的效果和指定"-A unix"参数相同;

--ip --inet :此参数的效果和指定 "-A inet" 参数相同。
目录
相关文章
|
2月前
|
Linux 网络性能优化 网络安全
Linux(openwrt)下iptables+tc工具实现网络流量限速控制(QoS)
通过以上步骤,您可以在Linux(OpenWrt)系统中使用iptables和tc工具实现网络流量限速控制(QoS)。这种方法灵活且功能强大,可以帮助管理员有效管理网络带宽,确保关键业务的网络性能。希望本文能够为您提供有价值的参考。
177 28
|
2月前
|
数据采集 人工智能 自然语言处理
FireCrawl:开源 AI 网络爬虫工具,自动爬取网站及子页面内容,预处理为结构化数据
FireCrawl 是一款开源的 AI 网络爬虫工具,专为处理动态网页内容、自动爬取网站及子页面而设计,支持多种数据提取和输出格式。
591 19
FireCrawl:开源 AI 网络爬虫工具,自动爬取网站及子页面内容,预处理为结构化数据
|
2月前
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
66 11
|
3月前
|
存储 安全 物联网
浅析Kismet:无线网络监测与分析工具
Kismet是一款开源的无线网络监测和入侵检测系统(IDS),支持Wi-Fi、Bluetooth、ZigBee等协议,具备被动监听、实时数据分析、地理定位等功能。广泛应用于安全审计、网络优化和频谱管理。本文介绍其安装配置、基本操作及高级应用技巧,帮助用户掌握这一强大的无线网络安全工具。
161 9
浅析Kismet:无线网络监测与分析工具
|
2月前
|
网络协议 安全 测试技术
Nping工具详解:网络工程师的瑞士军刀
### Nping工具详解:网络工程师的瑞士军刀 Nping是Nmap项目的一部分,支持TCP、UDP、ICMP和ARP等多种协议,用于生成和分析网络数据包。它提供灵活的命令行界面,适用于网络探测、安全测试和故障排除。本文介绍Nping的基础与高级用法,包括发送不同类型的网络请求、自定义TCP标志位、路由跟踪等,并通过实战案例展示其应用。掌握Nping有助于更好地理解和管理网络环境。 (239字符)
130 9
|
4月前
|
安全 Windows
【Azure Cloud Service】在Windows系统中抓取网络包 ( 不需要另外安全抓包工具)
通常,在生产环境中,为了保证系统环境的安全和纯粹,是不建议安装其它软件或排查工具(如果可以安装,也是需要走审批流程)。 本文将介绍一种,不用安装Wireshark / tcpdump 等工具,使用Windows系统自带的 netsh trace 命令来获取网络包的步骤
112 32
|
3月前
|
域名解析 运维 网络协议
网络诊断指南:网络故障排查步骤与技巧
网络诊断指南:网络故障排查步骤与技巧
890 7
|
4月前
|
安全 网络安全 数据安全/隐私保护
访问控制列表(ACL)是网络安全管理的重要工具,用于定义和管理网络资源的访问权限。
访问控制列表(ACL)是网络安全管理的重要工具,用于定义和管理网络资源的访问权限。ACL 可应用于路由器、防火墙等设备,通过设定规则控制访问。其类型包括标准、扩展、基于时间和基于用户的ACL,广泛用于企业网络和互联网安全中,以增强安全性、实现精细管理和灵活调整。然而,ACL 也存在管理复杂和可能影响性能的局限性。未来,ACL 将趋向智能化和自动化,与其他安全技术结合,提供更全面的安全保障。
266 4
|
5月前
|
运维 监控 网络协议
|
4月前
|
机器学习/深度学习 数据采集 算法
机器学习在医疗诊断中的前沿应用,包括神经网络、决策树和支持向量机等方法,及其在医学影像、疾病预测和基因数据分析中的具体应用
医疗诊断是医学的核心,其准确性和效率至关重要。本文探讨了机器学习在医疗诊断中的前沿应用,包括神经网络、决策树和支持向量机等方法,及其在医学影像、疾病预测和基因数据分析中的具体应用。文章还讨论了Python在构建机器学习模型中的作用,面临的挑战及应对策略,并展望了未来的发展趋势。
309 1

热门文章

最新文章