天天看点

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的源码。

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

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

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

    107     default:

108        break;

2、在<b>lib/x25_sr.c   </b>

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

为:

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

从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, &amp;ifr)

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

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

       我们来看下某些函数。

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

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

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

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

{

    struct interface *ife;   

    if (!int_list &amp;&amp; (if_readlist() &lt; 0))

        return -1;      

    for (ife = int_list; ife; ife = ife-&gt;next) {

        int err = doit(ife, cookie);

        if (err)

            return err;

    } 

    return 0;

}

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

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

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

    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函数来实现。

如果愿意,可以修改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一样的功效了。

最后祝大家玩得愉快。

 最后附上相关的参数:

add&lt;地址&gt;:设置网络设备IPv6的ip地址;

del&lt;地址&gt;:删除网络设备IPv6的IP地址;

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

&lt;hw&lt;网络设备类型&gt;&lt;硬件地址&gt;:设置网络设备的类型与硬件地址;

io_addr&lt;I/O地址&gt;:设置网络设备的I/O地址;

irq&lt;IRQ地址&gt;:设置网络设备的IRQ;

media&lt;网络媒介类型&gt;:设置网络设备的媒介类型;

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

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

mtu&lt;字节&gt;:设置网络设备的MTU;

netmask&lt;子网掩码&gt;:设置网络设备的子网掩码;

tunnel&lt;地址&gt;:建立IPv4与IPv6之间的隧道通信地址;

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

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

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

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

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

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

继续阅读