【问题标题】:eBPF: modifying UDP payload and responding to clienteBPF:修改 UDP 有效负载并响应客户端
【发布时间】:2021-01-18 01:21:22
【问题描述】:

我正在尝试修改从客户端接收到的 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), 0);
    ret = bpf_skb_store_bytes(skb, 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, L4_CSUM_OFF, datap[1], byte2, 0);
    bpf_l4_csum_replace(skb, L4_CSUM_OFF, datap[2], byte3, 0);
    // Not working!

    // Final: Redirect to be sent
    bpf_clone_redirect(skb, skb->ifindex, 0);   
}

如果我只是更改有效负载而不使用 adjust_room 函数删除 1 字节,则会发送它,但最后一个字节是 00。我想删除它。

请问有什么建议吗?谢谢!

【问题讨论】:

  • 您是否提前知道现有 UDP 有效负载的大小?
  • @pchaigno 不幸的是没有。但有可能算不出来吗? (payload_length)
  • @pchaigno 实际上它应该是 4 个字节(我的答案应该是 3 个字节),但是最好有一个不需要知道的更通用的解决方案。
  • 你看过bpf_skb_adjust_room() 助手吗?您应该能够将有效负载大小缩小payload_size - <sizeof(new_payload)>? (注意:另请参阅bpf_l3_csum_replace()/bpf_l4_csum_replace() 以重新计算您的校验和)
  • @Qeole 谢谢,对于“bpf_skb_adjust_room”,我收到“警告:函数 'bpf_skb_adjust_room' 的隐式声明在 C99 中无效”

标签: c linux-kernel kernel bpf ebpf


【解决方案1】:

根据@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

【讨论】:

  • 谢谢你,我只是不确定如何让 udp_payload 变量/指针在我提供的示例代码中进行修改,你能分享一下技巧吗?
  • 另外,对于“bpf_skb_adjust_room”,我收到警告:函数“bpf_skb_adjust_room”的隐式声明在 C99 中无效
  • 好的,我刚刚通过复制不同的 bpf_helpers.h 解决了这个问题,我已经在问题中更新了我的代码,现在我认为我只需要重新计算校验和,你能给我一些关于如何用我的代码中的结构来做到这一点?谢谢
  • 以上有什么建议吗?谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-06
  • 1970-01-01
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 2018-05-23
  • 1970-01-01
相关资源
最近更新 更多