1. wintun
Linux 2.4以后下有一种特殊的虚拟网络设备tun,用户可以直接创建虚拟网卡tun,直接以文件读写方式从设备处读取到网络层数据包(IP数据包),该网卡可以像是真实网卡一样设置IP、配置路由、读写数据,只不过数据的读写由用户编写的程序完成。
Jason A. Donenfeld 基于tun 向Linux社区贡献了WireGuard 用于实现虚拟网络。
为了开发Windows的WireGuard,开发了wintun并且开源,以动态库的方式分发。[3]
2. 下载Wintun
wintun使用C语言开发,以动态库形式分发。
下载后解压文件,目录如下:
bin
- amd64: Windows 64位
- x86: Windows 32位
3. 入门
3.1 创建虚拟网卡
WireGuard
go get -u golang.zx2c4.com/wireguard
wintun.dll
package main
import (
"golang.zx2c4.com/wireguard/tun"
"time"
)
func main() {
ifname := "MyNIC"
dev, err := tun.CreateTUN(ifname, 0)
if err != nil {
panic(err)
}
defer dev.Close()
time.Sleep(time.Second * 30)
}
wintun.dll
直接运行上面程序会出现该错误
2022/03/30 11:56:20 Failed to create private namespace: 拒绝访问。 (Code 0x00000
005)
2022/03/30 11:56:20 Failed to take device installation mutex: 拒绝访问。 (Code 0
x00000005)
2022/03/30 11:56:20 Failed to create private namespace: 拒绝访问。 (Code 0x00000
005)
2022/03/30 11:56:20 Failed to take device installation mutex: 拒绝访问。 (Code 0
x00000005)
panic: Error creating interface: Access is denied.
这是由于创建TUN网卡需要一定的操作系统权限,这里我们使用Windows管理员的方式打开程序,就可以。
GoLand可以这样设置
在使用管理员模式运行后,从网络设备管理器这边
可以看到刚才创建的虚拟网卡。
3.2 设置网卡IP以及路由
设置网卡IP需要使用到Windows API,我这直接复制了取自 wireguard的部分API wireguard-windows/winipcfg
到项目中
LUID
package main
import (
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/tun"
"net/netip"
"simpletun/winipcfg"
)
func main() {
ifname := "MyNIC"
dev, err := tun.CreateTUN(ifname, 0)
if err != nil {
panic(err)
}
defer dev.Close()
// 保存原始设备句柄
nativeTunDevice := dev.(*tun.NativeTun)
// 获取LUID用于配置网络
link := winipcfg.LUID(nativeTunDevice.LUID())
ip, err := netip.ParsePrefix("10.0.0.77/24")
if err != nil {
panic(err)
}
err = link.SetIPAddresses([]netip.Prefix{ip})
if err != nil {
panic(err)
}
// 配置虚拟网段路由
// err = link.SetRoutes([]*winipcfg.RouteData{
// {net.IPNet{IP: ip.Mask(cidrMask), Mask: cidrMask}, m.gateway, 0},
//})
time.Sleep(time.Second * 30)
}
ipconfig
router PRINT -v
ping
3.3 数据读写
readwrite
package main
import (
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/tun"
"log"
"net/netip"
"simpletun/winipcfg"
)
func main() {
ifname := "MyNIC"
dev, err := tun.CreateTUN(ifname, 0)
if err != nil {
panic(err)
}
defer dev.Close()
// 保存原始设备句柄
nativeTunDevice := dev.(*tun.NativeTun)
// 获取LUID用于配置网络
link := winipcfg.LUID(nativeTunDevice.LUID())
ip, err := netip.ParsePrefix("10.0.0.77/24")
if err != nil {
panic(err)
}
err = link.SetIPAddresses([]netip.Prefix{ip})
if err != nil {
panic(err)
}
n := 2048
buf := make([]byte, n)
// 读取ICMP
for {
n = 2048
n, err = dev.Read(buf, 0)
if err != nil {
panic(err)
}
const ProtocolICMP = 1
header, err := ipv4.ParseHeader(buf[:n])
if err != nil {
continue
}
if header.Protocol == ProtocolICMP {
log.Println("Src:", header.Src, " dst:", header.Dst)
msg, _ := icmp.ParseMessage(ProtocolICMP, buf[header.Len:])
log.Println(">> ICMP:", msg.Type)
break;
}
}
}
ping10.0.0.0
4. 常见问题
Win7 32位无法运行
Win7 32运行程序 提示参数错误 Error loading wintun.dll: Unable to load library: the parameter is incorrect.
该问是由于Win7缺少 KB2533623 补丁。
下载安装该补丁后需要重启就可以解决
目前该下载链接已经失效,此处附带备份的连接地址 https://download.csdn.net/download/q1009020096/87374944
Unable to load library
wintun.dll
拒绝访问
在启动运行程序后提示 Failed to create private namespace: 拒绝访问。
该问提示是由于权限不足引起,需要以管理员模式运行程序。
参考文献
[1]. kernel . tuntap . https://www.kernel.org/doc/html/latest/networking/tuntap.html
[2]. wikipedia . WireGuard . https://en.wikipedia.org/wiki/WireGuard
[3]. wintun . https://www.wintun.net/
[4]. github . tun2socks issue . tun2socks程序在WIN7x32系统下无法运行 . https://github.com/xjasonlyu/tun2socks/issues/37
[5]. linux虚拟网络接口 —— tun/tap . sven . 2015.8 . https://lishiwen4.github.io/network/virtual-network-interface-tun-and-tap