我的路由表中有以下条目:
tecik:ihsan $ netstat -rn -f inet6 | grep 2400:3700:61:4::/64
2400:3700:61:4::/64 2400:3700:60:4::2 UG gif104我通过路由套接字发出了一个RTM_GET请求,并且我设法正确地获取了RTA_DST信息,但是RTA_NETMASK总是返回0,尽管路由表显示它是/64。
如何获取正确的网络掩码条目。
代码:
/* fill in request header */
pid = getpid();
buf = calloc(0, sizeof(char) * buflen);
rtm = (struct rt_msghdr *) buf;
rtm->rtm_version = RTM_VERSION;
rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
rtm->rtm_addrs = RTA_DST | RTA_NETMASK;
rtm->rtm_type = RTM_GET;
rtm->rtm_pid = pid;
rtm->rtm_seq = seq;
/* take the dst AFI and assume the rest are of the same AFI */
if (dst->sa_family == AF_INET6) {
sin6 = (struct sockaddr_in6 *) (rtm + 1);
memcpy(sin6, dst, sizeof(struct sockaddr_in6));
sin6 = (struct sockaddr_in6 *) ((char *) sin6 + alignsa(sizeof(struct sockaddr_in6)));
memcpy(sin6, mask, sizeof(struct sockaddr_in6));
sin6 = (struct sockaddr_in6 *) ((char *) sin6 + alignsa(sizeof(struct sockaddr_in6)));
rtm->rtm_msglen = (char *) sin6 - buf;
}
/* write to routing socket */
write(s, rtm, rtm->rtm_msglen);
/* now read the reply */
do {
n = read(s, rtm, buflen);
} while (rtm->rtm_type != RTM_GET || rtm->rtm_seq != seq || rtm->rtm_pid != pid);
close(s);
/* cycle through all routing replies, checking for expected sockaddr */
rtm = (struct rt_msghdr *) buf;
sin6 = (struct sockaddr_in6 *) (rtm + 1);
for (rtax = 0; rtax < RTAX_MAX; rtax++) {
if (rtm->rtm_addrs & (1 << rtax)) {
sa = (struct sockaddr *) sin6;
if (rtax == RTAX_DST) {
al->rt = malloc(sizeof(char) * MAX_ADDRSTR);
getaddrstr(al->rt, sa);
}
else if (rtax == RTAX_NETMASK) {
sa->sa_family = AF_INET6;
al->rtplen = getcidr(sa);
}
sin6 = (struct sockaddr_in6 *) (char *) sin6 + alignsa(sizeof(struct sockaddr_in6));
}
}
if (al->rtplen == 0)
def = 1;
if (def)
debug("%s has default route, ignoring..", al->ifname);
else
debug("%s has route %s/%u", al->ifname, al->rt, al->rtplen);
free(buf);alignsa()为:
size_t
alignsa(size_t s)
{
return (1 + (((s) - 1) | (sizeof(size_t) - 1)));
}getcidr()是
/* all zeros netmask */
if (sa->sa_len == 0)
return(plen);
switch (sa->sa_family) {
case AF_INET:
break;
case AF_INET6:
s = (uint8_t *) &((struct sockaddr_in6 *)sa)->sin6_addr;
if (*s == 0)
break;
for (i = 0; ((i < 16) && (*s == 0xff)); i++, s++)
plen += 8;
break;
default:
return(-1);
}
return(plen);如果我打印出al->rt的值,则输出为2400:3700:61:4::,但rtplen始终为0。
如果我打印出网络掩码的sockaddr_in6,结果完全是ffff::或/64,所以不知何故我认为对于RTA_NETMASK,sin6_len是0,但我不明白为什么。
发布于 2013-02-28 20:24:20
EDIT:这个答案是错误的,因为它只适用于netlink RTM_GETROUTE。操作员询问有关路由套接字的信息。
我假设你指的是RTM_GETROUTE,即使你的主题是RTM_GET。RTM_GETROUTE返回的信息与netstat -6 -rn显示的信息不同。该命令可以返回缓存的路由。也许更令人惊讶的是,RTM_GETROUTE可以在路由缓存中创建路由。
这来自iproute2文档(在我的Ubuntu上,它列在man8ip-route中):
Note that this operation is not equivalent to ip route show. show shows existing routes. get resolves them and creates new clones if necessary. Essentially, get is equivalent to sending a packet along this path. If the iif argument is not given, the kernel creates a route to output packets towards the requested destination. This is equivalent to pinging the destination with a subsequent ip route ls cache, however, no packets are actually sent. With the iif argument, the kernel pretends that a packet arrived from this interface and searches for a path to forward the packet.
在您的示例中,您可以比较ip -6route show table all和ip -6route get 2400:3700:60:4::123的输出。它们可能会略有不同,因为ip route get版本在末尾包含cached一词。
我当前所在的位置没有IPv6连接,但此本地路由说明了我的意思:
thuovila@glx:~$ ip -6 r l table all |grep ff00::/8
ff00::/8设备eth1表本地指标256
thuovila@glx:~$ ip r get ff00::/8
ff00::from ::via ff00::dev eth1源fe80::21b:b1ff:fe48:1a75公制0高速缓存
正如您注意到的,缓存的路由不包含目的地址长度(网络掩码)。
为了解决你的问题(如何获得网络掩码),我建议研究一下过滤netlink消息。您必须转储与您的条件匹配的路由,并过滤克隆的路由,而不是单个RTM_GET请求。例如,iproute2工具在带有函数static int filter_nlmsg的iproute.c模块中执行此操作。除了其他内容之外,它还包含一行说明if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))的行,该行删除克隆的(即源自高速缓存的)路由。它由route_print()调用以限制显示的路由。在ip route list命令中,通过调用libnetlink函数rtnl_dump_filter()来转储路由。
有关如何使用netlink的更多提示,请查看iproute2的源代码,特别是ip/iproute.c和lib/libnetlink.c模块。
发布于 2013-02-28 21:48:16
我已经设法解决了这个问题,结果是我没有正确地将缓冲区转换回main函数上的sockaddr_in6:
sin6 = (struct sockaddr_in6 *) (char *) sin6 + alignsa(sizeof(struct sockaddr_in6));而它本应该是:
sin6 = (struct sockaddr_in6 *) ((char *) sin6 + alignsa(sizeof(struct sockaddr_in6)));通过将所有内容转换为第一个sockaddr_in6类型转换的右侧,并从rt_msghdr结构中删除RTA_NETMASK请求,我成功地返回了正确的网络掩码信息。
所以现在一切都好了。
https://stackoverflow.com/questions/15126757
复制相似问题