如何读取 tun/tap 接口上的 TCP 数据包?
How to read TCP packets on a tun/tap interface?
我正在做一个简单的项目,它监听 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())
}
你的代码对我有用。
如果我 运行 它,那么在我启动一些与 TCP 相关的 activity 之后我可以看到 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 的连接。
我遇到了同样的问题。发送到同一网络上的不同 IP 使其通过。发送到绑定到隧道的地址 (ip addr add ...
) 没有。我猜内核 TCP 堆栈优先于绑定地址?
添加路由到路由 table,而不是绑定地址到接口,为我解决了:
ip link set dev tun0 up
ip route add 10.2.0.10/32 dev tun0
注意:link 必须先启动才能应用路由。
point-to-point 配置而不是路由也可以解决问题:
ip link set dev tun0 up
ip addr add 10.2.0.0 peer 10.2.0.10 dev tun0
您将向对等地址发送数据包。
我正在做一个简单的项目,它监听 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())
}
你的代码对我有用。 如果我 运行 它,那么在我启动一些与 TCP 相关的 activity 之后我可以看到 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 的连接。
我遇到了同样的问题。发送到同一网络上的不同 IP 使其通过。发送到绑定到隧道的地址 (ip addr add ...
) 没有。我猜内核 TCP 堆栈优先于绑定地址?
添加路由到路由 table,而不是绑定地址到接口,为我解决了:
ip link set dev tun0 up
ip route add 10.2.0.10/32 dev tun0
注意:link 必须先启动才能应用路由。
point-to-point 配置而不是路由也可以解决问题:
ip link set dev tun0 up
ip addr add 10.2.0.0 peer 10.2.0.10 dev tun0
您将向对等地址发送数据包。