linux - 通过 sk_buff 将以太网数据包重定向到本地主机

标签 linux networking kernel

我正在编写一个 Linux 内核模块,它将数据包重定向到本地主机网络服务器,该数据包最初是通过这台机器使用网桥转发的。它还重定向以回复客户端。客户端忘记了重定向。所以有2个部分 1. 所有通过网桥转发到外部网络服务器的数据包都被重定向到本地网络服务器。

  1. 本地网络服务器的输出被传送到原始客户端

我可以通过 nf_hook NF_INET_LOCAL_OUT 完成第二部分

unsigned int snoop_hook_reply( unsigned int hooknum, struct sk_buff *skb,
    const struct net_device *in, const struct net_device *out,
    int(*okfn)( struct sk_buff * ) )
{
    int offset, len;
    struct ethhdr *ethh;
    struct iphdr *iph;
    struct tcphdr *tcph;
    bool flag = false;
    struct net_device *eth1_dev , *lo_dev;

    if (!skb) return NF_ACCEPT;
    iph = ip_hdr(skb);
    if (!iph) return NF_ACCEPT;
    skb_set_transport_header(skb, iph->ihl * 4);
    tcph = tcp_hdr(skb);
    /* skip lo packets */
    if (iph->saddr == iph->daddr) return NF_ACCEPT;
    if (tcph->dest == htons(80))
            flag=true;
    if(flag != true)
            return NF_ACCEPT;

    // correct the IP checksum
    iph->check = 0;
    ip_send_check (iph);

    //correct the TCP checksum
    offset = skb_transport_offset(skb);
    len = skb->len - offset;
    tcph->check = 0;
    if(skb->len > 60){
    tcph->check  = csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_TCP, csum_partial((unsigned char *)tcph,len,0));
    }
    else{
    tcph->check  = ~csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_TCP, 0);
    }

    //send to dev
    eth1_dev = dev_get_by_name(&init_net,"eth1");
    lo_dev = dev_get_by_name(&init_net,"lo");
    skb->dev = eth1_dev;
    ethh = (struct ethhdr *) skb_push(skb, ETH_HLEN);
    skb_reset_mac_header(skb);
    skb->protocol = ethh->h_proto = htons(ETH_P_IP);
    memcpy (ethh->h_source,eth1_dev->dev_addr , ETH_ALEN);
    memcpy (ethh->h_dest, d_mac, ETH_ALEN); // d_mac is mac of the gateway
    dev_queue_xmit(skb);

    return NF_STOLEN;
}

上面的代码非常适合我。一个问题是稍后我会破坏数据包,因此可能需要创建一个新的 sk_buff。

我无法通过 NF_INET_PRE_ROUTING 完成第一部分,我无法通过 TCP/IP 堆栈将数据包/sk_buff 推送到网络服务器进程。我尝试将 dev_queue_xmit() 函数与 skb->dev 一起用作 eth1 和 lo 。我看到数据包通过 tcpdump 命中 lo 或 eth1。但是数据包没有到达本地主机网络服务器。任何人都可以帮助我解决这个问题或指出一些类似的已回答问题。我相信我需要调用一些接收函数而不是 dev_queue_xmit()。此外,当数据包到达 NF_INET_PREROUTING 时,我的以太网 header 已经存在,所以我没有形成它。 我已经通过多种方式完成了上述任务,首先使用原始套接字,然后使用 nf_queue,现在我想通过这种方法查看性能。 谢谢

最佳答案

如果你想在本地接收数据包,你不能在 eth1 上调用 dev_queue_xmit(),因为它会被发送出去。在将 skb->dev 指向 eth1/lo 之后,您可能需要调用 netif_rx()。

还有一点,如果dest-ip不是你本地的host ip,那么你需要再次避免路由,否则你的拦截就没有用了。 为此,您需要将数据包的目标 ip 修改为 eth1/lo IP 或 通过使用 skb_dst_set() 设置“rth->dst.input= ip_local_deliver”来欺骗 IP 层,使数据包被接受为本地数据包。

关于linux - 通过 sk_buff 将以太网数据包重定向到本地主机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32759533/

相关文章:

c - 使用 netfilter hook 时打印 skb 数据会使计算机崩溃

c - WDK : get processId by name. 可执行文件

linux - 如何在禁用 tty 时输出子 shell

linux - linux挂载应用程序如何修改源端口

linux - xfrm_replay_state_esn 字段是什么意思?

http - Wireshark 的简单 Http 替代方案

linux - 为什么要包装函数?

c - 为笨蛋生成一个 makefile

linux - 我们如何在 Linux 内核的第 2 层(使用 MAC 地址)发送/接收帧

networking - 网络: Longest prefix matching