天天看點

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位址;

網絡裝置:指定網絡裝置的名稱。

繼續閱讀