我正在研究内核模块代码,在这里我需要查看
路由表以获取我的daddr
的ARP表条目:
|--------------------------------------------------|
-------+ enp0s1 192.168.2.0/24 192.168.3.0/24 enp0s2 +-----
|--------------------------------------------------|
例如,我需要获取192.168.3.111的neighbour
条目,并且该条目已永久添加到表中:
% ip neigh add 192.168.3.111 lladdr 00:11:22:33:44:55 dev enp0s2 nud permanent
% ip neigh sh
...
192.168.3.111 dev enp0s2 lladdr 00:11:22:33:44:55 PERMANENT
% ip route show
...
192.168.3.0/24 dev enp0s2 proto kernel scope link src 192.168.3.2
我想到了以下代码:
struct rtable *rt;
struct flowi4 fl4;
struct dst_entry dst;
struct neighbour *neigh;
u8 mac[ETH_ALEN];
...
memset(&fl4, 0, sizeof fl4);
fl4.daddr = daddr;
fl4.flowi4_proto = IPPROTO_UDP;
rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt))
goto err;
...
dst = rt->dst;
neigh = dst_neigh_lookup(&dst, &fl4.daddr);
if (!neigh) {
...
}
neigh_ha_snapshot(mac, neigh, neigh->dev);
neigh_release(neigh);
ip_rt_put(rt);
但是neigh_ha_snapshot
没有返回正确的MAC
地址,实际上我认为它返回了垃圾,有时返回ff:ff:ff:ff:ff:ff
,有时返回多播01:xx:xx:xx:xx:xx
。
我在做什么错了?
答案 0 :(得分:0)
此问题已解决,如下所示:
neigh = dst_neigh_lookup(&rt->dst, &fl4.daddr);
因此,与其在堆栈上没有struct dst_entry
对象,而是从rt
分配一个值并在dst_neigh_lookup()
中传递一个指向它的指针,而是将指针传递给dst
成员在当前rt
对象中。
原因是使用以下代码:
static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr)
{
struct neighbour *n = dst->ops->neigh_lookup(dst, NULL, daddr);
return IS_ERR(n) ? NULL : n;
}
其中neigh_lookup
初始化为ipv4_neigh_lookup()
中定义的功能net/ipv4/route.c
:
static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
struct sk_buff *skb,
const void *daddr)
{
struct net_device *dev = dst->dev;
const __be32 *pkey = daddr;
const struct rtable *rt;
struct neighbour *n;
rt = (const struct rtable *) dst;
...
}
从这一点出发,rt
是伪造的,其余都是伪造的。