ifconfig工具源码分析

ifconfig是linux中用于显示或配置网络设备(网络接口卡)的命令,英文全称是network interfaces configuring。

同netstat一样,ifconfig源码也位于net-tools中。

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

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

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

       下面一起来看下ifconfig的源码。

1.1.1 编译

直接通过命令make ifconfig就可以编译ifconfig。

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

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));

1.1.2 程序主逻辑

从main主函数开始,先获取程序输入参数,因为支持多如输入参数例如:ifconfig eth0 192.168.1.2,根据上一个参数以及下一个参数来调用相关的函数。

       第一个循环是判断参数是否为-a,-s,-v,-V,-version,-?,-h,-help,--help,如果是其他例如-x ,那么就直接报错后退出。

       如果参数没问题,则往下执行sockets_open函数(最后调用socket函数),打开内核支持的所有协议套接字,

       如果没有参数,则if_print函数打印所有网卡设备信息,如果有指定则显示指定的网口信息。

       获取下一个参数,是地址族名字(如果不是协议族名字,默认就是ipv4)或者是一个选项(如up)。然后处理剩下的参数。例如是否是-arp,media,port,up,down等。

       如果是开关参数,就调用set_flag或clr_flag函数。

       如果是功能参数,调用ioctl函数处理。

例如函数ioctl(skfd, SIOCSIFTXQLEN, &ifr)

其中skfd为本地域套接字,SIOCGIFFLAGS为传给内核的cmd,ifr接收从内核返回的数据。SIOCSIFTXQLEN定义在include/uapi/linux/sockios.h文件中。

#define SIOCSIFTXQLEN   0x8943          /* Set the tx queue length      */

       我们来看下某些函数。

1.1.3 if_print

该函数的入参为ifname是个字符串指针,如果为空的话就会调用函数for_all_interfaces打印系统中所有网卡信息。

       如果不为空,则调用lookup_interface函数获取接口结构体,接着调用do_if_fetch函数来获取,最后调用ife_print函数来打印。

   来看下位lib/interface.c文件中的函数for_all_interfaces:

int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie)

{

    struct interface *ife;   

 

    if (!int_list && (if_readlist() < 0))

        return -1;      

    for (ife = int_list; ife; ife = ife->next) {

        int err = doit(ife, cookie);

        if (err)

            return err;

    } 

    return 0;

}

       其第一参数为会回调函数,第二个会cookie。接口是一个双向链表(见下方结构体源码),所以全部打印的工作其实就是遍历接口结构体的工作,每次都调用doit回调函数。

       其中interface结构体如下,位于include/interface.h文件中:

struct interface {

    struct interface *next, *prev;

    char name[IFNAMSIZ];        /* interface name        */

    short type;                 /* if type               */

    short flags;                /* various flags         */

    int metric;                 /* routing metric        */

    int mtu;                    /* MTU value             */

    int tx_queue_len;           /* transmit queue length */

    struct ifmap map;           /* hardware setup        */

    struct sockaddr addr;       /* IP address            */

    struct sockaddr dstaddr;    /* P-P IP address        */

    struct sockaddr broadaddr;  /* IP broadcast address  */

    struct sockaddr netmask;    /* IP network mask       */

    struct sockaddr ipxaddr_bb; /* IPX network address   */

    struct sockaddr ipxaddr_sn; /* IPX network address   */

    struct sockaddr ipxaddr_e3; /* IPX network address   */

    struct sockaddr ipxaddr_e2; /* IPX network address   */

    struct sockaddr ddpaddr;    /* Appletalk DDP address */

    struct sockaddr ecaddr;     /* Econet address        */

    int has_ip;

    int has_ipx_bb;

    int has_ipx_sn;

    int has_ipx_e3;

    int has_ipx_e2;

    int has_ax25;

    int has_ddp;

    int has_econet;

    char hwaddr[32];            /* HW address            */

    int statistics_valid;      

    struct user_net_device_stats stats;         /* statistics            */

    int keepalive;              /* keepalive value for SLIP */

    int outfill;                /* outfill value for SLIP */

}; 

在函数执行过程中会打印/proc/net/dev文件,其中列出了网络设备的其属性状态和收发包情况。ifconfig会open这个设备查找匹配信息。

       最后根据ife_short变量,来调用ife_print_short函数或者ife_print_long函数。把interface结构体中的内容打印出来。

       当然这个结构体是ifconfig源码定义的,只是个容器它需要从内核中去获取实际的内容,这个会在打印之前由if_fetch函数来实现。

 

1.1.4 调试代码

如果愿意,可以修改ifconfig代码,来定制你自己的工具。

例如在源码中加入如下,其中第一列为行号,不用加入,此处只为显示:

419         if (!strcmp(*spp, "testxxx")) {

 420             goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));

 421             spp++;

 422             continue;

 423         } 

编译后,执行如下命令就可以将端口up了。

# ./ifconfig eth0 testxxx

       可以让testxxx起到是up一样的功效了。

最后祝大家玩得愉快。

1.1.5 参数

 最后附上相关的参数:

add<地址>:设置网络设备IPv6的ip地址;

del<地址>:删除网络设备IPv6的IP地址;

down:关闭指定的网络设备;

<hw<网络设备类型><硬件地址>:设置网络设备的类型与硬件地址;

io_addr<I/O地址>:设置网络设备的I/O地址;

irq<IRQ地址>:设置网络设备的IRQ;

media<网络媒介类型>:设置网络设备的媒介类型;

mem_start<内存地址>:设置网络设备在主内存所占用的起始地址;

metric<数目>:指定在计算数据包的转送次数时,所要加上的数目;

mtu<字节>:设置网络设备的MTU;

netmask<子网掩码>:设置网络设备的子网掩码;

tunnel<地址>:建立IPv4与IPv6之间的隧道通信地址;

up:启动指定的网络设备;

-broadcast<地址>:将要送往指定地址的数据包当成广播数据包来处理;

-pointopoint<地址>:与指定地址的网络设备建立直接连线,此模式具有保密功能;

-promisc:关闭或启动指定网络设备的promiscuous模式;

IP地址:指定网络设备的IP地址;

网络设备:指定网络设备的名称。

上一篇:接触vsto,开发word插件的利器


下一篇:HDFS源码分析EditLog之获取编辑日志输入流