我不使用XDP_TX接收数据包

发布于 2025-01-26 17:37:51 字数 5445 浏览 4 评论 0原文

// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA

#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>

#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"

#include <stdint.h>

__attribute__((__always_inline__))
static inline __u16 csum_fold_helper(__u64 csum) {
    int i;
#pragma unroll
    for (i = 0; i < 4; i++) {
        if (csum >> 16)
            csum = (csum & 0xffff) + (csum >> 16);
    }
    return ~csum;
}

__attribute__((__always_inline__))
static inline void ipv4_csum(void* data_start, int data_size, __u64* csum) {
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

__attribute__((__always_inline__))
static inline void ipv4_l4_csum(void* data_start, __u32 data_size,
    __u64* csum, struct iphdr* iph) {
    __u32 tmp = 0;
    *csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
    *csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
    tmp = __builtin_bswap32((__u32)(iph->protocol));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    tmp = __builtin_bswap32((__u32)(data_size));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md* ctx)
{
    void* data_end = (void*)(long)ctx->data_end;
    void* data = (void*)(long)ctx->data;
    struct ethhdr* eth = data;

    if (data + sizeof(*eth) > data_end) {
        return XDP_PASS;
    }

    uint16_t h_proto = eth->h_proto;

    if (h_proto == htons(ETH_P_IP)) {
        struct iphdr* iph = data + sizeof(*eth);
        if (data + sizeof(*eth) + sizeof(*iph) > data_end) {
            return XDP_PASS;
        }

        if (iph->protocol != IPPROTO_TCP) {
            return XDP_PASS;
        }

        struct tcphdr* tcph = data + sizeof(*eth) + sizeof(*iph);
        if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end) {
            return XDP_PASS;
        }

        __u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);

        if (tcp_len > 2000) {
            return XDP_DROP;
        }

        if (tcph->dest == htons(65535)) {
            unsigned char gateway[ETH_ALEN];
            gateway[0] = 0x92; gateway[1] = 0x10;
            gateway[2] = 0x95; gateway[3] = 0x86;
            gateway[4] = 0x26; gateway[5] = 0xbf;
            __builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
            __builtin_memcpy(eth->h_dest, gateway, ETH_ALEN);

            bpf_debug("MAC Source: %i:%i:%i", eth->h_source[0], eth->h_source[1], eth->h_source[2]);
            bpf_debug("%i:%i:%i\n", eth->h_source[3], eth->h_source[4], eth->h_source[5]);

            bpf_debug("MAC Destin: %i:%i:%i", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2]);
            bpf_debug("%i:%i:%i\n", eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);

            iph->saddr = iph->daddr;
            iph->daddr = htonl(4266428307);

            __u64 csum = 0;
            iph->check = 0;
            ipv4_csum(iph, sizeof(struct iphdr), &csum);
            iph->check = csum;

            csum = 0;
            tcph->check = 0;
            ipv4_l4_csum(tcph, tcp_len, &csum, iph);
            tcph->check = csum;

            bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);

            return XDP_TX;
        }
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

奇怪的是,我没有在目标服务器上接收TCP数据包 *(147.135.76.254 | 4266428307),而且在本地服务器上,数据包没有出现在TCPDUMP -I ETH0 DST端口65535中,

我在做错什么?如果是,我该如何修复代码。

目的是:在服务器端口本地接收数据包:65535,然后重定向到目标:65535


更新:

  1. 该程序似乎正常工作,我收到消息“接收到!”。在cat/sys/bernel/debug/tracing/trace_pipe

  2. 中,数据包未到达目标服务器

  3. (Windows)中的目标服务器

    ,我正在使用TCP校验和验证禁用的Wireshark,这意味着中间没有过滤器可以防止使用无效校验和的数据包,示例:< /p>

    在源服务器(Linux)上,我发送Hping3 147.135.76.254 -P 65535- badcksum并在Wireshark(DEST Server)中接收所有数据包(带有无效的校验和)

  4. ,当我执行时:TCPDUMP -I ETH0 TCP端口65535,我没有接收任何数据包。

    >

    注意:我使用EthTool -K eth0 tx off禁用卸载 / chksum < / p>

  5. 如果将XDP_TX更改为XDP_Pass,我可以在TCPDUMP中接收此数据包(上面的命令):
    14:38:10.964195 IP D2-2-US-VA-1.39698&gt; 147.135.76.254.65535:旗帜[S],SEQ 3962643128,WIN 14600,选项[MSS 1460,Sackok,TS Val 2414158903 ECR 0,NOP,NOP,WSCALE 9]

  6. In ethtool -S eth0 shows rx/tx正确地

  7. 我会收到此响应。 147.135.76.254.65535:旗帜[S],CKSUM 0x41C3(正确),SEQ 2996104997,WIN 14600,选项[MSS 1460,Sackok,TS Val 2614058020 ECR 0 &amp; IP计算正常工作

  8. 我更新了正确通知MAC地址,并且问题仍在继续。


执行命令:

[root@d2-2-us-east-va-1〜]#arp -a _gateway(135.148.232.1)在92:10:10:95:86:26:eth0上的bf [ether

]地址 FA:16:3E:0E:CF:A4

[root@d2-2-us-east-va-1〜]#ifconfig ...(确认MAC地址)

// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA

#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>

#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"

#include <stdint.h>

__attribute__((__always_inline__))
static inline __u16 csum_fold_helper(__u64 csum) {
    int i;
#pragma unroll
    for (i = 0; i < 4; i++) {
        if (csum >> 16)
            csum = (csum & 0xffff) + (csum >> 16);
    }
    return ~csum;
}

__attribute__((__always_inline__))
static inline void ipv4_csum(void* data_start, int data_size, __u64* csum) {
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

__attribute__((__always_inline__))
static inline void ipv4_l4_csum(void* data_start, __u32 data_size,
    __u64* csum, struct iphdr* iph) {
    __u32 tmp = 0;
    *csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
    *csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
    tmp = __builtin_bswap32((__u32)(iph->protocol));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    tmp = __builtin_bswap32((__u32)(data_size));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md* ctx)
{
    void* data_end = (void*)(long)ctx->data_end;
    void* data = (void*)(long)ctx->data;
    struct ethhdr* eth = data;

    if (data + sizeof(*eth) > data_end) {
        return XDP_PASS;
    }

    uint16_t h_proto = eth->h_proto;

    if (h_proto == htons(ETH_P_IP)) {
        struct iphdr* iph = data + sizeof(*eth);
        if (data + sizeof(*eth) + sizeof(*iph) > data_end) {
            return XDP_PASS;
        }

        if (iph->protocol != IPPROTO_TCP) {
            return XDP_PASS;
        }

        struct tcphdr* tcph = data + sizeof(*eth) + sizeof(*iph);
        if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end) {
            return XDP_PASS;
        }

        __u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);

        if (tcp_len > 2000) {
            return XDP_DROP;
        }

        if (tcph->dest == htons(65535)) {
            unsigned char gateway[ETH_ALEN];
            gateway[0] = 0x92; gateway[1] = 0x10;
            gateway[2] = 0x95; gateway[3] = 0x86;
            gateway[4] = 0x26; gateway[5] = 0xbf;
            __builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
            __builtin_memcpy(eth->h_dest, gateway, ETH_ALEN);

            bpf_debug("MAC Source: %i:%i:%i", eth->h_source[0], eth->h_source[1], eth->h_source[2]);
            bpf_debug("%i:%i:%i\n", eth->h_source[3], eth->h_source[4], eth->h_source[5]);

            bpf_debug("MAC Destin: %i:%i:%i", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2]);
            bpf_debug("%i:%i:%i\n", eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);

            iph->saddr = iph->daddr;
            iph->daddr = htonl(4266428307);

            __u64 csum = 0;
            iph->check = 0;
            ipv4_csum(iph, sizeof(struct iphdr), &csum);
            iph->check = csum;

            csum = 0;
            tcph->check = 0;
            ipv4_l4_csum(tcph, tcp_len, &csum, iph);
            tcph->check = csum;

            bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);

            return XDP_TX;
        }
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

Strangely I'm not receiving TCP packets on my destination server *(147.135.76.254 | 4266428307), and also on the local server the packet doesn't appear in tcpdump -i eth0 dst port 65535

Am I doing something wrong? If yes, how can I fix the code.

The purpose is: Receive packet on server port LOCAL:65535, and redirect to DESTINATION:65535


Updates:

  1. The program seems to work correctly, I'm getting the message "Received!" in cat /sys/kernel/debug/tracing/trace_pipe

  2. The packet did not reach the destination server

  3. In the destination server (Windows), i'm running Wireshark with TCP Checksum verification disabled, this means that there is no filter in the middle that prevents packets with invalid checksum, example:

    On source server (linux), i send hping3 147.135.76.254 -p 65535 --
    badcksum and receive all packets (with invalid checksums) in wireshark (dest server)

  4. In source server (XDP), when i execute: tcpdump -i eth0 tcp port 65535, i'm not receiving any packets.

    Note: I used ethtool -K eth0 tx off to disable offload / chksum

  5. If i change XDP_TX to XDP_PASS i can receive this packet in tcpdump (command above):
    14:38:10.964195 IP d2-2-us-east-va-1.39698 > 147.135.76.254.65535: Flags [S], seq 3962643128, win 14600, options [mss 1460,sackOK,TS val 2414158903 ecr 0,nop,wscale 9], length 0

  6. In ethtool -S eth0 shows rx/tx correctly

  7. If i change from "XDP_TX" to "XDP_PASS" i receive this response in tcpdump: 135.148.232.155.58062 > 147.135.76.254.65535: Flags [S], cksum 0x41c3 (correct), seq 2996104997, win 14600, options [mss 1460,sackOK,TS val 2614058020 ecr 0,nop,wscale 9], length 0, that means my TCP Checksum & IP Calculation is working correcly

  8. I updated informing the MAC Address correctly and the problem continues.


The commands executed:

[root@d2-2-us-east-va-1 ~]# arp -a
_gateway (135.148.232.1) at 92:10:95:86:26:bf [ether] on eth0

[root@d2-2-us-east-va-1 ~]# cat /sys/class/net/eth0/address
fa:16:3e:0e:cf:a4

[root@d2-2-us-east-va-1 ~]# ifconfig
... (to confirm mac address)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

温暖的光 2025-02-02 17:37:51

您没有更新以太网层的源和目标MAC地址。如果源Mac与NIC的配置Mac不匹配,则一些NIC,特别是虚拟化的数据包。

如果将数据包反射回本地网络(本地计算机或路由器/默认网关)上的同一台物理机器,则可以简单地交换SRC和DST地址。

我更新了您的代码以添加以下内容:

// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA

#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>

#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"

#include <stdint.h>

__attribute__((__always_inline__)) static inline __u16 csum_fold_helper(__u64 csum)
{
    int i;
#pragma unroll
    for (i = 0; i < 4; i++)
    {
        if (csum >> 16)
            csum = (csum & 0xffff) + (csum >> 16);
    }
    return ~csum;
}

__attribute__((__always_inline__)) static inline void ipv4_csum(void *data_start, int data_size, __u64 *csum)
{
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

__attribute__((__always_inline__)) static inline void ipv4_l4_csum(void *data_start, __u32 data_size,
                                                                   __u64 *csum, struct iphdr *iph)
{
    __u32 tmp = 0;
    *csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
    *csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
    tmp = __builtin_bswap32((__u32)(iph->protocol));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    tmp = __builtin_bswap32((__u32)(data_size));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md *ctx)
{
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth = data;

    if (data + sizeof(*eth) > data_end)
    {
        return XDP_PASS;
    }

    uint16_t h_proto = eth->h_proto;

    if (h_proto == htons(ETH_P_IP))
    {
        struct iphdr *iph = data + sizeof(*eth);
        if (data + sizeof(*eth) + sizeof(*iph) > data_end)
        {
            return XDP_PASS;
        }

        if (iph->protocol != IPPROTO_TCP)
        {
            return XDP_PASS;
        }

        struct tcphdr *tcph = data + sizeof(*eth) + sizeof(*iph);
        if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end)
        {
            return XDP_PASS;
        }

        __u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);

        if (tcp_len > 2000)
        {
            return XDP_DROP;
        }

        if (tcph->dest == htons(65535))
        {
            bpf_debug("Checksum Old: %i | %i\n", iph->check, tcph->check);

            unsigned char tmp[ETH_ALEN];
            __builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
            __builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
            __builtin_memcpy(eth->h_dest, tmp);

            iph->saddr = iph->daddr;
            iph->daddr = htonl(4266428307);

            __u64 csum = 0;

            iph->check = 0;
            ipv4_csum(iph, sizeof(struct iphdr), &csum);
            iph->check = csum;

            csum = 0;
            tcph->check = 0;
            ipv4_l4_csum(tcph, tcp_len, &csum, iph);
            tcph->check = csum;

            bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);

            return XDP_TX;
        }
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

更改的行是:

unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);

请注意,如果您要切换数据包(将其发送到其他物理设备),则该行不起作用,在这种情况下,您需要使用ARP获取正确的Mac或硬码。

You are not updating the source and destination MAC addresses of the ethernet layer. Some NICs especially virtualized ones will drop outgoing packets if the source MAC does not match the configured MAC of the NIC.

If you are reflecting the packets back to the same physical machine on your local network(local machine or router/default gateway) you can simply swap the src and dst addresses.

I updated your code to add this:

// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA

#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>

#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"

#include <stdint.h>

__attribute__((__always_inline__)) static inline __u16 csum_fold_helper(__u64 csum)
{
    int i;
#pragma unroll
    for (i = 0; i < 4; i++)
    {
        if (csum >> 16)
            csum = (csum & 0xffff) + (csum >> 16);
    }
    return ~csum;
}

__attribute__((__always_inline__)) static inline void ipv4_csum(void *data_start, int data_size, __u64 *csum)
{
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

__attribute__((__always_inline__)) static inline void ipv4_l4_csum(void *data_start, __u32 data_size,
                                                                   __u64 *csum, struct iphdr *iph)
{
    __u32 tmp = 0;
    *csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
    *csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
    tmp = __builtin_bswap32((__u32)(iph->protocol));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    tmp = __builtin_bswap32((__u32)(data_size));
    *csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
    *csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
    *csum = csum_fold_helper(*csum);
}

SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md *ctx)
{
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth = data;

    if (data + sizeof(*eth) > data_end)
    {
        return XDP_PASS;
    }

    uint16_t h_proto = eth->h_proto;

    if (h_proto == htons(ETH_P_IP))
    {
        struct iphdr *iph = data + sizeof(*eth);
        if (data + sizeof(*eth) + sizeof(*iph) > data_end)
        {
            return XDP_PASS;
        }

        if (iph->protocol != IPPROTO_TCP)
        {
            return XDP_PASS;
        }

        struct tcphdr *tcph = data + sizeof(*eth) + sizeof(*iph);
        if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end)
        {
            return XDP_PASS;
        }

        __u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);

        if (tcp_len > 2000)
        {
            return XDP_DROP;
        }

        if (tcph->dest == htons(65535))
        {
            bpf_debug("Checksum Old: %i | %i\n", iph->check, tcph->check);

            unsigned char tmp[ETH_ALEN];
            __builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
            __builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
            __builtin_memcpy(eth->h_dest, tmp);

            iph->saddr = iph->daddr;
            iph->daddr = htonl(4266428307);

            __u64 csum = 0;

            iph->check = 0;
            ipv4_csum(iph, sizeof(struct iphdr), &csum);
            iph->check = csum;

            csum = 0;
            tcph->check = 0;
            ipv4_l4_csum(tcph, tcp_len, &csum, iph);
            tcph->check = csum;

            bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);

            return XDP_TX;
        }
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

The changed lines being:

unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);

Please note that the this does not work if you are switching the packet(sending it to a different physical device) in which case you need to use ARP to get the correct MAC or hardcode it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文