代码之家  ›  专栏  ›  技术社区  ›  OneOfOne

如何在tun/tap接口上读取TCP数据包?

  •  3
  • OneOfOne  · 技术社区  · 7 年前

    我正在做一个简单的项目,它监听tun接口并修改数据包,然后将它们重新发送到真正的接口。

    我试过了 songgao/water ,则, pkg/tuntap 甚至基于一些浮动的C代码编写我自己的代码,但无论我尝试了什么,我都无法接收TCP数据包(ICMP/UDP工作正常)。

    我觉得我错过了一些非常明显的东西,但我一辈子都想不出来。。。

    这个 code :

    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())
    }
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   kmeaw    5 年前

    你的代码对我有用。 如果我运行它,那么我可以在启动一些与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
    

    如您所见,10.2.0.10的TCP客户端正在尝试建立(TCP-SYN)到10.2.0.11的连接。

        2
  •  0
  •   Jason Stewart    3 年前

    我也有同样的问题。在同一个网络上发送到不同的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
    

    您将向对等地址发送数据包。

    推荐文章