- 论坛徽章:
- 0
|
系统工具ifconfig源代码阅读路线图2(OpenBSD5.3)
/* 作者 老董 dz0212@foxmail.com */
“阅读代码时,应该尽可能地利用任何能够得到的文档。阅读一小时代码所得到的信息只不过相当于阅读一分钟文档”
----Diomidis Spinellis 《CODE Reading》
0x05 分析getifaddrs()
没见过这个函数?那就man一下。
$ man getifaddrs
NAME
getifaddrs - get interface addresses
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
int
getifaddrs(struct ifaddrs **ifap);
void
freeifaddrs(struct ifaddrs *ifap);
DESCRIPTION
The getifaddrs() function stores a reference to a linked list of the
network interfaces on the local machine in the memory referenced by ifap.
The list consists of ifaddrs structures, as defined in the include file
<ifaddrs.h>. The ifaddrs structure contains at least the following
entries:
struct ifaddrs *ifa_next; /* Pointer to next struct */
char *ifa_name; /* Interface name */
u_int ifa_flags; /* Interface flags */
struct sockaddr *ifa_addr; /* Interface address */网络接口地址,应重点关注,status()调用使用此结构
struct sockaddr *ifa_netmask; /* Interface netmask */
struct sockaddr *ifa_broadaddr; /* Interface broadcast address */
struct sockaddr *ifa_dstaddr; /* P2P interface destination */
void *ifa_data; /* Address specific data */
耐心看就很清楚了,OpenBSD就像是一座金矿,需要不断的发掘。getifaddrs(struct ifaddrs **ifap)调用后,ifap指向一个链表,链表包含所有的本地网络接口信息。
0x06 分析status()
第一步分析printif()调用status()前后的关键程序段,并理清楚相关结构体类型定义:
在printif()中,整理出一下关键代码段
919 struct if_data *ifdata;
943 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
978 ifdata = ifa->ifa_data;
979 status(1, (struct sockaddr_dl *)ifa->ifa_addr, ifdata->ifi_link_state);
1007 }
要理清楚(struct sockaddr_dl *)ifa->ifa_addr和ifdata->ifi_link_state
ifa->ifa_addr为网络接口地址,前段注释已讲清楚;
通过查头文件if_dl.h可知struct sockaddr_dl定义:
$ more /usr/include/net/if_dl.h
/*
* Structure of a Link-Level sockaddr:
*/
struct sockaddr_dl {
u_char sdl_len; /* Total length of sockaddr */
u_char sdl_family; /* AF_LINK */
u_int16_t sdl_index; /* if != 0, system given index for interface */
u_char sdl_type; /* interface type */
u_char sdl_nlen; /* interface name length, no trailing 0 reqd. */
u_char sdl_alen; /* link level address length */
u_char sdl_slen; /* link layer selector length, mostly 0 */
char sdl_data[24]; /* minimum work area, can be larger;
contains both if name and ll address;
big enough for IFNAMSIZ plus 8byte ll addr */
};
通过查if.h头文件,可知ifdata->ifi_link_state为接口连接状态(通俗说网线是否插上了)
$ more /usr/include/net/if.h
/*
* Structure defining statistics and other data kept regarding a network
* interface.
*/
struct if_data {
/* generic interface information */
u_char ifi_type; /* ethernet, tokenring, etc. */
u_char ifi_addrlen; /* media address length */
u_char ifi_hdrlen; /* media header length */
u_char ifi_link_state; /* current link state */网络接口连接状态,应重点关注,status()调用使用此结构
u_int32_t ifi_mtu; /* maximum transmission unit */
u_int32_t ifi_metric; /* routing metric (external only) */
u_int32_t ifi_pad;
u_int64_t ifi_baudrate; /* linespeed */
/* volatile statistics */
u_int64_t ifi_ipackets; /* packets received on interface */
u_int64_t ifi_ierrors; /* input errors on interface */
u_int64_t ifi_opackets; /* packets sent on interface */
u_int64_t ifi_oerrors; /* output errors on interface */
u_int64_t ifi_collisions; /* collisions on csma interfaces */
u_int64_t ifi_ibytes; /* total number of octets received */
u_int64_t ifi_obytes; /* total number of octets sent */
u_int64_t ifi_imcasts; /* packets received via multicast */
u_int64_t ifi_omcasts; /* packets sent via multicast */
u_int64_t ifi_iqdrops; /* dropped on input, this interface */
u_int64_t ifi_noproto; /* destined for unsupported protocol */
u_int32_t ifi_capabilities; /* interface capabilities */
struct timeval ifi_lastchange; /* last operational state change */
struct mclpool ifi_mclpool[MCLPOOLS];
};
第二步:解构status(),仍以输出信息为线索,理出输出变量,再查看该变量值的获取程序段
看status():
2759 /*
2760 * Print the status of the interface. If an address family was
2761 * specified, show it and it only; otherwise, show them all.
2762 */
2763 void
2764 status(int link, struct sockaddr_dl *sdl, int ls)
2765 {
......
2775 printf("%s: ", name);
2776 printb("flags", flags | (xflags << 16), IFFBITS);
2777 if (rdomainid)
2778 printf(" rdomain %i", rdomainid);
2779 if (metric)
2780 printf(" metric %lu", metric);
2781 if (mtu)
2782 printf(" mtu %lu", mtu);
2783 putchar('\n');
......
2929 }
呵呵,以上看到的基本都是输出语句,2775行猜是显示网络接口名(如em0,dc0等),对不对?可以实验,将2275行输出加个记号,如改为printf("dz%s: ", name);(为啥要标记dz,呵呵,本人名字第一个字母),然后编译链接运行,看效果
$ ./ifconfig
dzem0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 08:00:27:37:0e:6b
priority: 0
media: Ethernet autoselect (1000baseT full-duplex)
status: active
inet6 fe80::a00:27ff:fe37:e6b%em0 prefixlen 64 scopeid 0x1
inet 192.168.56.101 netmask 0xffffff00 broadcast 192.168.56.255
在网络接口名称em0前已经有dz标记了,说明猜测正确。即变量name中保存的是网卡接口名称,该值是如何获得的?查看status()函数无与name变量相关语句,这时在翻看上层函数printif()
971 strlcpy(name, ifa->ifa_name, sizeof(name));
0x05分析了ifa结构变量的获得,而ifa->ifa_name为接口名,971行将接口变量名复制给了变量name,继续查看代码可知
125 char name[IFNAMSIZ];/*name被定义为全局变量*/
故在status()函数中直接使用。
|
|