问题描述
我正在尝试修改从客户端接收到的 UDP 有效负载,以克隆和重定向数据包以响应它。交换MAC和IP地址已经完成,以及克隆,但我不知道如何修改UDP负载。
我想将包含以下 3 个字节的负载发送回客户端:0x1a 0x31 0x0f,通过创建新的负载(更好)并在数据包中替换它或替换。我该怎么做?
这是我目前的代码:
根据评论更新(现在只需要重新计算校验和):
int pingpong(struct __sk_buff *skb)
{
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct ethhdr *eth = data;
struct iphdr *ip;
struct udphdr *udpdata;
if ((void *)eth + sizeof(*eth) > data_end) {
return TC_ACT_UNSPEC;
}
ip = data + sizeof(*eth);
if ((void *)ip + sizeof(*ip) > data_end) {
return TC_ACT_UNSPEC;
}
udpdata = (void *)ip + sizeof(*ip);
if ((void *)udpdata + sizeof(*udpdata) > data_end) {
return TC_ACT_UNSPEC;
}
if (eth->h_proto != htons(ETH_P_IP)) {
return TC_ACT_UNSPEC;
}
if (ip->protocol != IPPROTO_UDP) {
return TC_ACT_UNSPEC;
}
unsigned int payload_size;
unsigned char *payload;
payload_size = ntohs(udpdata->len) - sizeof(*udpdata);
payload = (unsigned char *)udpdata + sizeof(*udpdata);
if ((void *)payload + payload_size > data_end) {
return TC_ACT_UNSPEC;
}
// 1. Swap the MACs
__u8 tmp_mac[ETH_ALEN];
memcpy(tmp_mac,eth->h_dest,ETH_ALEN);
memcpy(eth->h_dest,eth->h_source,ETH_ALEN);
memcpy(eth->h_source,tmp_mac,ETH_ALEN);
// 2. Swap the IPs
if (eth->h_proto == htons(ETH_P_IP)) {
__u32 tmp_ip = ip->saddr;
ip->saddr = ip->daddr;
ip->daddr = tmp_ip;
}
// 3. Swap the ports
udpdata->source = port;
udpdata->dest = srcport;
// 4. Change the payload to be 0x1a 0x31 0x0f
bpf_skb_adjust_room(skb,-1,BPF_ADJ_ROOM_NET,0);
uint8_t byte1 = 0x1a;
uint8_t byte2 = 0x31;
uint8_t byte3 = 0x0f;
int ret = bpf_skb_store_bytes(skb,payload_offset,&byte1,sizeof(byte1),0);
ret = bpf_skb_store_bytes(skb,payload_offset+1,&byte2,sizeof(byte2),payload_offset+2,&byte3,sizeof(byte3),0);
// Re-calculate the checksum
bpf_l4_csum_replace(skb,L4_CSUM_OFF,datap[0],byte1,0);
bpf_l4_csum_replace(skb,datap[1],byte2,datap[2],byte3,0);
// Not working!
// Final: Redirect to be sent
bpf_clone_redirect(skb,skb->ifindex,0);
}
如果我只是更改负载而不使用 adjust_room 函数删除 1 个字节,它会被发送,但最后一个字节是 00。我想删除它。
请问有什么建议吗?谢谢!
解决方法
根据@Qeole 的建议,您可以使用以下内容来更改 UDP 负载的大小和内容:
// Remove 1 byte after IP header.
bpf_skb_adjust_room(ctx,-1,BPF_ADJ_ROOM_NET,0);
... re-check packet pointers or verifier will complain ...
// Need to rewrite the UDP header as the extra space was added before it.
*new_udphdr = *old_udphdr;
// Write payload.
udp_payload[0] = 0x1a
udp_payload[1] = 0x31
udp_payload[2] = 0x0f