add support for linux and udp

This commit is contained in:
kony
2025-04-01 13:45:40 +08:00
parent ab67769c18
commit 32135e6423
13 changed files with 317 additions and 132 deletions

17
netstack/device.go Normal file
View File

@@ -0,0 +1,17 @@
package netstack
import (
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
// Device is the interface that implemented by network layer devices (e.g. tun),
// and easy to use as stack.LinkEndpoint.
type Device interface {
stack.LinkEndpoint
// Name returns the current name of the device.
Name() string
// Type returns the driver type of the device.
Type() string
}

View File

@@ -1,5 +1,5 @@
// Package iobased provides the implementation of io.ReadWriter
// based data-link layer endpoints.
//go:build windows
package netstack
import (

View File

@@ -1,5 +1,3 @@
//go:build windows
package netstack
import (

View File

@@ -1,5 +1,3 @@
//go:build windows
package netstack
import (

80
netstack/setup.go Normal file
View File

@@ -0,0 +1,80 @@
package netstack
import (
"fmt"
"github.com/quic-go/quic-go"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
)
func setNetStack(s *stack.Stack, nicID tcpip.NICID) error {
s.SetRouteTable([]tcpip.Route{
{
Destination: header.IPv4EmptySubnet,
NIC: nicID,
},
})
if err := netstack_stack.SetPromiscuousMode(nicID, true); err != nil {
return fmt.Errorf("promisc: %s", err)
}
if err := netstack_stack.SetSpoofing(nicID, true); err != nil {
return fmt.Errorf("spoofing: %s", err)
}
return nil
}
var (
init_stack_suss = false
netstack_stack *stack.Stack
)
func Start() error {
if init_stack_suss {
return nil
}
netstack_stack = stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
})
wintunEP, err := Open(GetName(), 1490) //因为要加自定义头防止超出1500
if err != nil {
return fmt.Errorf("请管理员权限运行")
}
SetTunIP(&wintunEP, GetRemoteIP(), 32)
// 将TUN设备注册到协议栈中使用NIC ID 1
nicID := tcpip.NICID(1)
if err := netstack_stack.CreateNIC(nicID, wintunEP); err != nil {
return fmt.Errorf("设备注册: %v", err)
}
setNetStack(netstack_stack, nicID)
init_stack_suss = true
return nil
}
func SetForWarder(stun_quic_conn quic.Connection) {
netstack_stack.SetTransportProtocolHandler(tcp.ProtocolNumber, NewTcpForwarder(netstack_stack, stun_quic_conn).HandlePacket)
netstack_stack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUdpForwarder(netstack_stack, stun_quic_conn).HandlePacket)
}
func GetRemoteIP() string {
return "192.17.19.1"
}
func GetName() string {
return "GoodLink"
}

View File

@@ -3,24 +3,100 @@
package netstack
import (
"github.com/quic-go/quic-go"
"fmt"
"log"
"net"
"os/exec"
"unsafe"
"golang.org/x/sys/unix"
)
// setupNetstack 初始化并配置网络栈
// 该函数负责创建协议栈、设置网络接口、配置IP地址和路由表
// 返回:
// - *stack.Stack: 配置好的网络栈实例
// - error: 初始化过程中的错误信息
func Start() error {
func setUnixIP(name string, ip net.IP, mask net.IPMask) error {
log.Printf("setUnixIP: %s %s %s", name, ip, mask)
// 新增接口存在性检查
if err := checkInterfaceExists(name); err != nil {
return err
}
// 修改标志位设置流程(先关闭再开启)
ifreq, _ := unix.NewIfreq(name)
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(unix.AF_INET), unix.SIOCGIFFLAGS, uintptr(unsafe.Pointer(ifreq)))
if errno != 0 {
return fmt.Errorf("SIOCGIFFLAGS(pre-check) failed: %s", unix.ErrnoName(errno))
}
originalFlags := ifreq.Uint16()
// 临时关闭接口(关键步骤)
ifreq.SetUint16(originalFlags &^ unix.IFF_UP)
_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(unix.AF_INET), unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(ifreq)))
if errno != 0 {
return fmt.Errorf("SIOCSIFFLAGS(down) failed: %s", unix.ErrnoName(errno))
}
// 设置IP地址结构体修复掩码处理
addr, _ := unix.NewIfreq(name)
addr.SetInet4Addr(ip.To4())
_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(unix.AF_INET), unix.SIOCSIFADDR, uintptr(unsafe.Pointer(addr)))
if errno != 0 {
return fmt.Errorf("SIOCSIFADDR failed: %s", unix.ErrnoName(errno)) // 显示具体错误名称
}
// 设置子网掩码(修复变量名错误)
maskAddr, _ := unix.NewIfreq(name)
maskAddr.SetInet4Addr(net.IP(mask).To4()) // 显式转换掩码类型
_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(unix.AF_INET), unix.SIOCSIFNETMASK, uintptr(unsafe.Pointer(maskAddr)))
if errno != 0 {
return fmt.Errorf("SIOCSIFNETMASK failed: %s", unix.ErrnoName(errno))
}
// 修改接口激活逻辑(关键修复)
ifreq, _ = unix.NewIfreq(name)
ifreq.SetUint16((originalFlags | unix.IFF_UP) &^ unix.IFF_NOARP) // 保留原始标志位并添加UP标志
_, _, errno = unix.Syscall(unix.SYS_IOCTL, uintptr(unix.AF_INET), unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(ifreq)))
if errno != 0 {
return fmt.Errorf("SIOCSIFFLAGS failed: %s", unix.ErrnoName(errno))
}
log.Printf("Configuration applied successfully")
return nil
}
func SetForWarder(stun_quic_conn quic.Connection) {
// 新增辅助函数
func checkInterfaceExists(name string) error {
ifreq, _ := unix.NewIfreq(name)
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(unix.AF_INET), unix.SIOCGIFFLAGS, uintptr(unsafe.Pointer(ifreq)))
if errno != 0 {
return fmt.Errorf("interface %s not exists: %s", name, unix.ErrnoName(errno))
}
return nil
}
func GetRemoteIP() string {
return "Linux暂不支持Local端"
}
// 修改调用端错误处理
func SetTunIP(wintunEP *Device, ip string, mask int) error {
// ip addr add 192.17.0.1/32 dev GoodLink
// ip link set GoodLink up
// ip route add 192.17.19.1 dev GoodLink
func Stop() {
// 设置网卡eth0的IP地址为192.168.1.10/24
cmd := exec.Command("ip", "addr", "add", "192.17.0.1/32", "dev", GetName())
if err := cmd.Run(); err != nil {
return err
}
cmd = exec.Command("ip", "link", "set", GetName(), "up")
if err := cmd.Run(); err != nil {
return err
}
cmd = exec.Command("ip", "route", "add", GetRemoteIP(), "dev", GetName())
if err := cmd.Run(); err != nil {
return err
}
/*if err := setUnixIP(GetName(), net.ParseIP(ip), net.CIDRMask(mask, 32)); err != nil {
return fmt.Errorf("setUnixIP failed: %w", err)
}*/
return nil
}

View File

@@ -11,17 +11,9 @@ import (
"net/http"
"net/netip"
"time"
"github.com/quic-go/quic-go"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
)
func SetWinTunIP(wintunEP *Device, ip string, mask int) error {
func SetTunIP(wintunEP *Device, ip string, mask int) error {
var ipf netip.Prefix
var err error
@@ -51,30 +43,6 @@ func SetWinTunIP(wintunEP *Device, ip string, mask int) error {
return nil
}
func setNetStack(s *stack.Stack, nicID tcpip.NICID) error {
s.SetRouteTable([]tcpip.Route{
{
Destination: header.IPv4EmptySubnet,
NIC: nicID,
},
})
if err := netstack_stack.SetPromiscuousMode(nicID, true); err != nil {
return fmt.Errorf("promisc: %s", err)
}
if err := netstack_stack.SetSpoofing(nicID, true); err != nil {
return fmt.Errorf("spoofing: %s", err)
}
return nil
}
var (
init_stack_suss = false
netstack_stack *stack.Stack
)
func InitWintunDll() error {
if gogo.Utils().FileExist("wintun.dll") {
return nil
@@ -105,48 +73,3 @@ func InitWintunDll() error {
return nil
}
const (
tunIP = "192.17.19.1"
)
func Start() error {
InitWintunDll()
if init_stack_suss {
return nil
}
netstack_stack = stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
})
wintunEP, err := Open("GoodLink", 1490) //因为要加自定义头防止超出1500
if err != nil {
return fmt.Errorf("请管理员权限运行")
}
SetWinTunIP(&wintunEP, tunIP, 32)
// 将TUN设备注册到协议栈中使用NIC ID 1
nicID := tcpip.NICID(1)
if err := netstack_stack.CreateNIC(nicID, wintunEP); err != nil {
return fmt.Errorf("设备注册: %v", err)
}
setNetStack(netstack_stack, nicID)
init_stack_suss = true
return nil
}
func SetForWarder(stun_quic_conn quic.Connection) {
netstack_stack.SetTransportProtocolHandler(tcp.ProtocolNumber, NewTcpForwarder(netstack_stack, stun_quic_conn).HandlePacket)
netstack_stack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUdpForwarder(netstack_stack, stun_quic_conn).HandlePacket)
}
func GetRemoteIP() string {
return tunIP
}

View File

@@ -1,5 +1,3 @@
//go:build windows
package netstack
import (

View File

@@ -1,5 +1,3 @@
//go:build windows
package netstack
import (

105
netstack/tun_linux.go Normal file
View File

@@ -0,0 +1,105 @@
//go:build linux
package netstack
import (
"fmt"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/rawfile"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
type TUN struct {
stack.LinkEndpoint
fd int
mtu uint32
name string
}
func Open(name string, mtu uint32) (Device, error) {
t := &TUN{name: name, mtu: mtu}
if len(t.name) >= unix.IFNAMSIZ {
return nil, fmt.Errorf("interface name too long: %s", t.name)
}
fd, err := tun.Open(t.name)
if err != nil {
return nil, fmt.Errorf("create tun: %w", err)
}
t.fd = fd
if t.mtu > 0 {
if err := setMTU(t.name, t.mtu); err != nil {
return nil, fmt.Errorf("set mtu: %w", err)
}
}
_mtu, err := rawfile.GetMTU(t.name)
if err != nil {
return nil, fmt.Errorf("get mtu: %w", err)
}
t.mtu = _mtu
ep, err := fdbased.New(&fdbased.Options{
FDs: []int{fd},
MTU: t.mtu,
// TUN only, ignore ethernet header.
EthernetHeader: false,
// SYS_READV support only for TUN fd.
PacketDispatchMode: fdbased.Readv,
// TAP/TUN fd's are not sockets and using the WritePackets calls results
// in errors as it always defaults to using SendMMsg which is not supported
// for tap/tun device fds.
//
// This CL changes WritePackets to gracefully degrade to using writev instead
// of sendmmsg if the underlying fd is not a socket.
//
// Fixed: https://github.com/google/gvisor/commit/f33d034fecd7723a1e560ccc62aeeba328454fd0
MaxSyscallHeaderBytes: 0x00,
})
if err != nil {
return nil, fmt.Errorf("create endpoint: %w", err)
}
t.LinkEndpoint = ep
return t, nil
}
func (t *TUN) Name() string {
return t.name
}
func (t *TUN) Close() {
defer t.LinkEndpoint.Close()
_ = unix.Close(t.fd)
}
func (t *TUN) Type() string {
return "tun" // 返回固定的设备类型标识符
}
func setMTU(name string, n uint32) error {
// open datagram socket
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return err
}
defer unix.Close(fd)
ifr, err := unix.NewIfreq(name)
if err != nil {
return err
}
ifr.SetUint32(n)
return unix.IoctlIfreq(fd, unix.SIOCSIFMTU, ifr)
}

View File

@@ -10,21 +10,8 @@ import (
"sync"
"golang.zx2c4.com/wireguard/tun"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
// Device is the interface that implemented by network layer devices (e.g. tun),
// and easy to use as stack.LinkEndpoint.
type Device interface {
stack.LinkEndpoint
// Name returns the current name of the device.
Name() string
// Type returns the driver type of the device.
Type() string
}
// 常量定义
const (
offset = 0 // 数据包偏移量用于处理TUN_PI头0表示不使用TUN_PI
@@ -59,6 +46,8 @@ type TUN struct {
// - Device: 实现了Device接口的TUN设备
// - error: 创建过程中的错误信息
func Open(name string, mtu uint32) (_ Device, err error) {
InitWintunDll()
// 使用defer和recover处理可能的panic确保错误被正确捕获和包装
defer func() {
if r := recover(); r != nil {