免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1521 | 回复: 0
打印 上一主题 下一主题

[OpenBSD] 系统工具ifconfig源代码阅读路线图2(OpenBSD5.3) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-10-11 19:56 |只看该作者 |倒序浏览
系统工具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()函数中直接使用。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP