feat: 实现部分 windows tun 接口

This commit is contained in:
lynx
2023-08-11 17:51:43 +08:00
parent aa446960cf
commit f1765b4a59
9 changed files with 227 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
package device
import (
"NetHive/pkgs/win"
"net/netip"
"github.com/pkg/errors"
"golang.zx2c4.com/wintun"
)
const (
WintunTunnelType = "NetHive"
)
type tun struct {
adapter *wintun.Adapter
session *wintun.Session
name string
mtu int
}
func (t *tun) Read(bytes []byte) (int, error) {
//TODO implement me
panic("implement me")
}
func (t *tun) Write(bytes []byte) (int, error) {
//TODO implement me
panic("implement me")
}
func (t *tun) Close() error {
return t.adapter.Close()
}
func (t *tun) MTU() (int, error) {
return t.mtu, nil
}
func (t *tun) Name() (string, error) {
return t.name, nil
}
func (t *tun) AddAddress(addr netip.Prefix) error {
luid := t.adapter.LUID()
itf := win.NetItf(luid)
return errors.Wrap(itf.AddIPAddress(addr), "Error AddAddress:")
}
func (t *tun) FlushAddress() error {
//TODO implement me
panic("implement me")
}
func (t *tun) Up() error {
//TODO implement me
panic("implement me")
}
func (t *tun) Down() error {
//TODO implement me
panic("implement me")
}
func (t *tun) State() bool {
//TODO implement me
panic("implement me")
}
func CreateTUN(name string, mtu int) (Device, error) {
adapter, err := wintun.CreateAdapter(name, WintunTunnelType, nil)
if err != nil {
return nil, errors.Wrapf(err, "error creating interface: ")
}
session, err := adapter.StartSession(0x800000)
if err != nil {
adapter.Close()
return nil, errors.Wrapf(err, "error start session: ")
}
if mtu <= 0 {
mtu = 1420
}
t := &tun{
adapter: adapter,
session: &session,
name: name,
mtu: mtu,
}
return t, nil
}

1
go.mod
View File

@@ -120,6 +120,7 @@ require (
golang.org/x/sync v0.3.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/tools v0.11.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
google.golang.org/protobuf v1.30.0 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
)

2
go.sum
View File

@@ -563,6 +563,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=

26
pkgs/win/interface.go Normal file
View File

@@ -0,0 +1,26 @@
package win
import (
"net/netip"
)
// NetItf represents the network interface UUID of windows.
type NetItf uint64
func (i NetItf) AddIPAddress(address netip.Prefix) error {
row := &MibUnicastIPAddressRow{}
row.Init()
if err := row.Address.SetAddrPort(netip.AddrPortFrom(address.Addr(), 0)); err != nil {
return err
}
row.InterfaceLUID = uint64(i)
row.ValidLifetime = 0xffffffff
row.PreferredLifetime = 0xffffffff
row.OnLinkPrefixLength = uint8(address.Bits())
row.DadState = NldsPreferred
return nil
}
func (i *NetItf) FlushAddress() {
}

18
pkgs/win/iphlpapi.go Normal file
View File

@@ -0,0 +1,18 @@
package win
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var (
modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
procInitializeUnicastIpAddressEntry = modiphlpapi.NewProc("InitializeUnicastIpAddressEntry")
)
func initializeUnicastIPAddressEntry(row *MibUnicastIPAddressRow) {
syscall.SyscallN(procInitializeUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0)
}

22
pkgs/win/netioapi.go Normal file
View File

@@ -0,0 +1,22 @@
package win
// MibUnicastIPAddressRow structure stores information about a unicast IP address.
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row
type MibUnicastIPAddressRow struct {
Address SockAddrInet
InterfaceLUID uint64
InterfaceIndex uint32
PrefixOrigin uint32
SuffixOrigin uint32
ValidLifetime uint32
PreferredLifetime uint32
OnLinkPrefixLength uint8
SkipAsSource bool
DadState NLDadState
ScopeID uint32
CreationTimeStamp int64
}
func (m *MibUnicastIPAddressRow) Init() {
initializeUnicastIPAddressEntry(m)
}

11
pkgs/win/nldef.go Normal file
View File

@@ -0,0 +1,11 @@
package win
type NLDadState uint32
const (
NldsInvalid NLDadState = iota
NldsTentative
NldsDuplicate
NldsDeprecated
NldsPreferred
)

43
pkgs/win/sockaddr.go Normal file
View File

@@ -0,0 +1,43 @@
package win
import (
"net/netip"
"strconv"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type SockAddrInet struct {
Family uint16
data [26]byte
}
func (s *SockAddrInet) SetAddrPort(ap netip.AddrPort) error {
if ap.Addr().Is4() {
addr4 := (*syscall.RawSockaddrInet4)(unsafe.Pointer(s))
addr4.Family = syscall.AF_INET
addr4.Addr = ap.Addr().As4()
addr4.Port = be2se(ap.Port())
for i := 0; i < 8; i++ {
addr4.Zero[i] = 0
}
return nil
} else if ap.Addr().Is6() {
addr6 := (*windows.RawSockaddrInet6)(unsafe.Pointer(s))
addr6.Family = syscall.AF_INET6
addr6.Addr = ap.Addr().As16()
addr6.Port = be2se(ap.Port())
addr6.Flowinfo = 0
scopeId := uint32(0)
if z := ap.Addr().Zone(); z != "" {
if s, err := strconv.ParseUint(z, 10, 32); err == nil {
scopeId = uint32(s)
}
}
addr6.Scope_id = scopeId
return nil
}
return windows.ERROR_INVALID_PARAMETER
}

9
pkgs/win/util.go Normal file
View File

@@ -0,0 +1,9 @@
package win
func be2se(i uint16) uint16 {
return (i>>8)&0xFF | (i&0xFF)<<8
}
func se2be(i uint16) uint16 {
return (i>>8)&0xFF | (i&0xFF)<<8
}