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地址;
网络设备:指定网络设备的名称。