gpt4 book ai didi

c - 路由套接字 RTM_GET RTA_NETMASK 与路由表条目不匹配

转载 作者:行者123 更新时间:2023-12-01 13:57:50 29 4
gpt4 key购买 nike

我的路由表中有以下条目:

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:ffff:ffff:ffff::或/64,所以我认为对于 RTA_NETMASK,sin6_len 是 0,但我不明白为什么。

最佳答案

编辑:这个答案是错误的,因为它只适用于 netlink RTM_GETROUTE。该操作询问路由套接字。

我假设您指的是 RTM_GETROUTE,即使您的主题说的是 RTM_GET。 RTM_GETROUTE 不返回由 netstat -6 -rn 显示的相同信息。该命令可以返回缓存的路由。也许更令人惊讶的是,RTM_GETROUTE 可以在路由缓存中创建路由。

这是来自 iproute2 文档(在我的 Ubuntu 上,它在 man 8 ip-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 -6 route show table allip -6 route get 2400:3700:60:4::123 的输出.它们可能会略有不同,ip route get 版本的末尾包含单词 cached

我目前所在的位置没有 IPv6 连接,但这条本地路由说明了我的意思:

thuovila@glx:~$ ip -6 r l table all |grep ff00::/8

ff00::/8 dev eth1 table local metric 256

thuovila@glx:~$ ip r get ff00::/8

ff00:: from :: via ff00:: dev eth1 src fe80::21b:b1ff:fe48:1a75 metric 0 cache

如您所见,缓存的路由不包含目标地址长度(网络掩码)。

为了解决您的问题,(如何获取网络掩码)我建议研究过滤网络链接消息。而不是单个 RTM_GET 请求,您将不得不转储符合您的条件的路由并过滤克隆路由。 iproute2 工具在例如iproute.c具有函数 static int filter_nlmsg 的模块。其中,它包含一行 if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED)) 删除克隆(即源自缓存)路由。它由 route_print() 调用以限制显示的路线。在 ip route list 命令中,通过调用 libnetlink 函数 rtnl_dump_filter() 转储路由。

有关如何使用 netlink 的更多提示,请检查 iproute2 的源代码,尤其是 ip/iproute.clib/libnetlink.c 模块。

关于c - 路由套接字 RTM_GET RTA_NETMASK 与路由表条目不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15126757/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com