以编程方式将数据包注入虚拟接口

时间:2017-11-22 16:10:53

标签: linux networking libpcap

我们目前正在开发一款旨在“桥接”的原型。 Linux中的本地虚拟接口,用于使用专有硬件发送/接收以太网数据包的API。最终的想法是使用这种专有硬件透明地使用标准库和工具。

作为确保我们想做的事情确实可行的第一步,我们制作了第一个版本的原型,使用libpcap将虚拟接口桥接到实际的以太网接口。以下是我们的所作所为:

  • 在PC1上使用MAC / IP地址(192.168.0.1)
  • 创建本地虚拟接口
  • 在同一网络(192.168.0.2)上配置具有IP的PC2
  • 使用PC1上未配置的接口链接PC1和PC2
  • 使用一个简单的桥梁' PC1上的程序,用libpcap开发,在一个接口上侦听并在第二个接口上注入数据包(使用pcap_sendpacket),反之,桥接虚拟接口和实际以太网接口
  • 从PC1到PC2启动ping

当监视PC1上的虚拟接口时,我们会观察到ICMP请求和响应,因此桥接程序可以正常工作,但ping工具无法在应用程序级别获得ICMP响应。

我猜测我们在内核路由过程中太晚注入数据包......或其他什么。

你知道如何正确地做到这一点吗?也许使用替代类型的虚拟接口? (bridge,tun / tap ...)它不能是一个完整的系统/命令行解决方案,因为最终我们想要将数据包桥接到专有API而不是以太网接口,所以我们需要以编程方式访问数据包(因此libpcap的)。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

Linux中的虚拟模块接口无法实现这一点。它们只能从内核向网络硬件设备“向下”传输数据包。并且,与虚拟接口的情况一样,没有硬件设备,当数据包到达此路径的底部时(dummy_xmit函数),数据包将被丢弃。您可以将其视为单向接收器。

这是调用图:

                          [applications]
                          [tcp/ip stack]  
                                 |
                                 |
                                 v
pcap_sendpacket -> tpacket_snd -> dev_queue_xmit -> dev_hard_start_xmit -> xmit_one -> netdev_start_xmit -> ndo_start_xmit -> dummy_xmit -> dev_kfree_skb
                                                                                    |
                                                                                    |
pcap_next <- tpacket_rcv <- prot_hook.func <- deliver_skb <-dev_queue_xmit_nit <-----

因此,在您的情况下,来自ping应用程序的ping请求进入设备传输路径。它们在此路径的末尾被丢弃,但在此之前,它们被复制并且这些副本将被传递到在接口上侦听的pcap桥。 Bridge应用程序将它们转发到PC2。 PC2应答ping请求并将响应发送回桥接应用程序。桥接应用程序将这些响应注入设备传输路径,它们向下传输并被丢弃。但在此之前,它们被复制到所有pcap监听器,包括用于间谍和观察流量的tcpdump,但不包括注入它们的桥接应用程序:

++ net/core/dev.c
@@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
    ...
    /* Never send packets back to the socket
     * they originated from - MvS (miquels@drinkel.ow.org)
     */
    if (skb_loop_sk(ptype, skb))
        continue;

这就是您看到请求和响应的原因。但是响应没有传递给内核TCP / IP堆栈和ping应用程序,因为虚拟接口无法做到这一点。它们向下传输到dummy_xmit并被丢弃。

因此,在您的情况下,您应该使用TAP接口,或者,如果您仍想使用pcap来交换数据包,请使用虚拟链接。