#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/udp.h>
#include <linux/in.h>
#include <linux/if_arp.h>
#define IFINDEX_2 2 // ifindex for enp129s0f0
#define IFINDEX_3 3 // ifindex for enp129s0f1
SEC("xdp_redirect")
int xdp_redirect_prog(struct xdp_md *ctx)
{
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
// Check packet boundaries
if ((void *)(eth + 1) > data_end)
return XDP_DROP;
// Check if the packet is ARP
if (eth->h_proto == bpf_htons(ETH_P_ARP)) {
if (ctx->ingress_ifindex == IFINDEX_2) {
return bpf_redirect(IFINDEX_3, 0);
} else if (ctx->ingress_ifindex == IFINDEX_3) {
return bpf_redirect(IFINDEX_2, 0)
}
}
if (eth->h_proto == bpf_htons(ETH_P_IP)) {
// Determine incoming interface and redirect accordingly
if (ctx->ingress_ifindex == IFINDEX_2) {
return bpf_redirect(IFINDEX_3, 0);
} else if (ctx->ingress_ifindex == IFINDEX_3) {
return bpf_redirect(IFINDEX_2, 0);
}
}
return XDP_PASS;
服务器配置:
server1(192.168.1.1)<->server2<-> server3(192.168.1.2)
enp129s0f3(192.168.1.1) <-> enp129s0f0np0 / enp129s0f1np1 <-> enp129s0f3(192.168.1.2)
如上图,
server1
和server2
相连,server2
和server3
相连。
此时我想从
ARP
通过TCP
向UDP
发送server1
、server3
、server2
等数据包,以及ARP
、TCP
等数据包、UDP
等,从server3
到server1
到server2
。这时候我想从XDP
通过server2
双向重定向数据包,但是不行。
例如,当
server1
发送ARP REQUEST
时,会经过server2
,发送到server3
,但是存在一个现象,来自ARP REPLY
的server3
没有发送到server1
.
我怀疑您遇到的问题是由于您没有更新 MAC 地址。
通常,NIC 会过滤/忽略不是其配置的 MAC 地址或广播地址 (FF:FF:FF:FF:FF:FF) 的数据包。
由于 ARP 就是将 IP 转换为 MAC,因此 ARP 请求将发送到广播地址,因此
server2
和 server3
NIC 都会接受它。但是,在这种情况下,回复将发送到发送者的 MAC 地址server1
。因此 server2
上的 NIC 将丢弃它。
有两种方法可以处理这个问题。首先,添加 XDP 逻辑来执行正确的 MAC 转换。因此,每当您将数据包从
server1
转发到 server3
时,您都将源 MAC 更改为 enp129s0f1np1
上的 MAC,将目标更改为 server3
/enp129s0f3
上的 MAC。在另一个方向上,将源设置为 enp129s0f1np0
,将目标设置为 server1
/enp129s0f3
。对于 ARP,您不仅需要更新以太网标头,还需要更新 ARP 消息中的字段,因为根据我的经验,“发送者”字段将用于设置回复中的目标 MAC。
处理此问题的第二种方法是在
server2
的两个接口上启用混杂模式。为此,您执行ip link set <interface-name> promisc on
。这将告诉 NIC 始终传递所有数据包,无论 MAC 地址如何。您必须记住每次重新启动时都执行此操作。