`
bcyy
  • 浏览: 1830919 次
文章分类
社区版块
存档分类
最新评论

UNIX路由表源码的错误修改

 
阅读更多

最近研究了通过sysctl方法获取路由表的UNIX源码(FreeBSD http://www.oschina.net/code/explore/freebsd/sbin/route/route.c),收获不少。


其中找出一段错误如下:

代码1:

L1:        if (ifm->ifm_type == RTM_IFINFO) {
L2:            get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
L3:            printf("  %-15s", sock_ntop(sa, sa->sa_len));

这是用来打印路由对应的Interface ,但是却打印出这个结果:


代码2:

Routing table:
--------------
Destination        Gateway            Flags       Netif             Use
default            27.17.172.1        UGSc        ppp07.172.1       0
default/0          192.168.1.1        UGSc        en1.168.1.1       0
27.17.172.1        27.17.175.111      UH          ppp07.175.111     0

本来NetIf部分是由代码1输出的,但现在看起来却像一个结构体被错误的使用带来的后果。

在代码1的L3设置断点,得到sa的数据:

sa_data char [14][14]
0 char 8 '\b'
1 char 0 '\000'
2 char 23 '\027'
3 char 4 '\004'
4 char 0 '\000'
5 char 0 '\000'
6 char 112 'p'
7 char 112 'p'
8 char 112 'p'
9 char 48 '0'
10 char 0 '\000'
11 char 0 '\000'
12 char 0 '\000'
13 char 0 '\000'

可以看到,我们需要的数据是6、7、8、9,也就是对应ppp0,10之后都是'\000' 字符串的结束,说明Interface信息在这里是正常的,经过sock_ntop处理后返回的值出错了。


现在来看,sock_ntop做了一个选择器的工作,就是把socket数据进行识别,就是判断struct sock_addr *的sa_family,然后返回对应family的值。

sa_family对应有 AF_LINK AF_INET 等等。我们这里获取的是接口数据,所以当然是这部分的代码:


代码3:

        case AF_LINK: {
            struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
            
            if (sdl->sdl_len > 0) {
L1:                bcopy(&sdl->sdl_data[0], str, sdl->sdl_nlen);
L2:                str[sdl->sdl_len] = '\0';
            } else 
                snprintf(str, sizeof(str), "link#%d", sdl->sdl_index);
            
            return (str);
        } 

我们要观察的是str这块buffer,因为最终我们得到的函数返回是str

断点设在代码3的L1,此时str还保留前一次取ip的数据。bcopy完成了将sdl中长度为 sdl->nlen 的数据拷贝到 str 这个buffer中,然后L2是为这儿buffer加上字符串结束标记。

显然这里出现了问题:我们拷贝了sdl->nlen长度的数据,却在sdl_len处结束字符串,所以这个应该是接口数据多出来的原因。


到文件 net/if_dl.h 中查看 struct sockaddr_dl * :

/*
 * Structure of a Link-Level sockaddr:
 */
struct sockaddr_dl {
	u_char	sdl_len;	/* Total length of sockaddr */
	u_char	sdl_family;	/* AF_LINK */
	u_short	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 */
	char	sdl_data[12];	/* minimum work area, can be larger;
				   contains both if name and ll address */
#ifndef __APPLE__
	/* For TokenRing */
	u_short	sdl_rcf;	/* source routing control */
	u_short	sdl_route[16];	/* source routing information */
#endif
};

我们需要的数据长度显然是sdl_nlen , sdl_len 是整块sockaddr的长度,这样标记肯定会继续输出str中未被socket数据覆盖的部分,也就是之前使用过的ip。


回头看看代码2,也就是输出的部分路由表,可以发现每一行Netif的后半段和Gateway的数据是相同的,这也证明了这一点:str使用完之后没有被清空。这是不太好的做法,要么就在正确位置加上字符串结束符‘\0’,要么就每次使用完str就清空一次 —— 呃,以UNIX源码的风格,我想大部分会是前一种 —— 但是我也不知道为何这些程序员都能保持头脑清醒。



===================================

本文来自:http://blog.csdn.net/zh405123507

tags:UNIX Routing Debug Socket



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics