如何在TUN/TAP接口上读取TCP数据包



我正在研究一个简单的项目,该项目会在TUN接口上倾听并修改数据包,然后将它们重新放置为真实的接口。

我尝试过songgao/waterpkg/tuntap,甚至根据一些C代码编写我自己的编写,但是无论我尝试过什么,我都无法接收TCP数据包(ICMP/UDP工作正常(。

我觉得我错过了一些非常明显的东西,但我无法弄清楚这是我的一生...

代码:

package main
import (
    "log"
    "os"
    "os/exec"
    "golang.org/x/net/ipv4"
    "github.com/songgao/water"
)
const (
    // I use TUN interface, so only plain IP packet, no ethernet header + mtu is set to 1300
    BUFFERSIZE = 1600
    MTU        = "1300"
)
func main() {
    iface, err := water.New(water.Config{})
    fatalIf(err)
    log.Printf("tun interface: %s", iface.Name())
    runBin("/bin/ip", "link", "set", "dev", iface.Name(), "mtu", MTU)
    runBin("/bin/ip", "addr", "add", "10.2.0.10/24", "dev", iface.Name())
    runBin("/bin/ip", "link", "set", "dev", iface.Name(), "up")
    buf := make([]byte, BUFFERSIZE)
    for {
        n, err := iface.Read(buf)
        if err != nil {
            log.Fatal(err)
        }
        header, _ := ipv4.ParseHeader(buf[:n])
        log.Printf("isTCP: %v, header: %s", header.Protocol == 6, header)
    }
}
func fatalIf(err error) {
    if err != nil {
        log.Fatal(err)
    }
}
func runBin(bin string, args ...string) {
    cmd := exec.Command(bin, args...)
    cmd.Stderr = os.Stderr
    cmd.Stdout = os.Stdout
    cmd.Stdin = os.Stdin
    fatalIf(cmd.Run())
}

您的代码对我有用。如果运行它,那么在启动一些与TCP相关的活动后,我可以看到TCP数据包。在这种情况下,我使用了" SSH 10.2.0.11"。这是我得到的:

2020/03/07 15:52:23 isTCP: false, header: ver=6 hdrlen=0 tos=0x0 totallen=0 id=0x8 flags=0x1 fragoff=0x1aff ttl=254 proto=128 cksum=0x0 src=0.0.0.0 dst=126.87.58.227
2020/03/07 15:52:27 isTCP: false, header: ver=6 hdrlen=0 tos=0x0 totallen=0 id=0x8 flags=0x1 fragoff=0x1aff ttl=254 proto=128 cksum=0x0 src=0.0.0.0 dst=126.87.58.227
2020/03/07 15:52:34 isTCP: false, header: ver=6 hdrlen=0 tos=0x0 totallen=0 id=0x8 flags=0x1 fragoff=0x1aff ttl=254 proto=128 cksum=0x0 src=0.0.0.0 dst=126.87.58.227
2020/03/07 15:52:36 isTCP: true, header: ver=4 hdrlen=20 tos=0x0 totallen=60 id=0x9cec flags=0x2 fragoff=0x0 ttl=64 proto=6 cksum=0x89b7 src=10.2.0.10 dst=10.2.0.11
2020/03/07 15:52:37 isTCP: true, header: ver=4 hdrlen=20 tos=0x0 totallen=60 id=0x9ced flags=0x2 fragoff=0x0 ttl=64 proto=6 cksum=0x89b6 src=10.2.0.10 dst=10.2.0.11
2020/03/07 15:52:39 isTCP: true, header: ver=4 hdrlen=20 tos=0x0 totallen=60 id=0x9cee flags=0x2 fragoff=0x0 ttl=64 proto=6 cksum=0x89b5 src=10.2.0.10 dst=10.2.0.11
2020/03/07 15:52:43 isTCP: true, header: ver=4 hdrlen=20 tos=0x0 totallen=60 id=0x9cef flags=0x2 fragoff=0x0 ttl=64 proto=6 cksum=0x89b4 src=10.2.0.10 dst=10.2.0.11

您可以看到,TCP客户端处于10.2.0.10,正在尝试建立(TCP-SYN(与10.2.0.11。

我也有同样的问题。发送到同一网络上的不同IP结束。发送到绑定到隧道的地址(ip addr add ...(没有。我猜想内核TCP堆栈优先考虑绑定地址?

在路由表中添加路由,而不是将地址绑定到接口,而是为我解决:

ip link set dev tun0 up
ip route add 10.2.0.10/32 dev tun0

注意:必须在应用路线之前链接。

点对点配置而不是路由也将有能力:

ip link set dev tun0 up
ip addr add 10.2.0.0 peer 10.2.0.10 dev tun0

您将将数据包发送到同行地址。

最新更新