mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-13 20:28:32 +10:00
118 lines
2.4 KiB
Go
118 lines
2.4 KiB
Go
//go:build with_gvisor && windows
|
|
|
|
package tailscale
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
singTun "github.com/sagernet/sing-tun"
|
|
"github.com/sagernet/sing/common/logger"
|
|
wgTun "github.com/sagernet/wireguard-go/tun"
|
|
)
|
|
|
|
type tunDeviceAdapter struct {
|
|
tun singTun.WinTun
|
|
nativeTun *singTun.NativeTun
|
|
events chan wgTun.Event
|
|
mtu atomic.Int64
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
func newTunDeviceAdapter(tun singTun.Tun, mtu int, _ logger.ContextLogger) (wgTun.Device, error) {
|
|
winTun, ok := tun.(singTun.WinTun)
|
|
if !ok {
|
|
return nil, errors.New("not a windows tun device")
|
|
}
|
|
nativeTun, ok := winTun.(*singTun.NativeTun)
|
|
if !ok {
|
|
return nil, errors.New("unsupported windows tun device")
|
|
}
|
|
if mtu == 0 {
|
|
mtu = 1500
|
|
}
|
|
adapter := &tunDeviceAdapter{
|
|
tun: winTun,
|
|
nativeTun: nativeTun,
|
|
events: make(chan wgTun.Event, 1),
|
|
}
|
|
adapter.mtu.Store(int64(mtu))
|
|
adapter.events <- wgTun.EventUp
|
|
return adapter, nil
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) File() *os.File {
|
|
return nil
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) Read(bufs [][]byte, sizes []int, offset int) (count int, err error) {
|
|
packet, release, err := a.tun.ReadPacket()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer release()
|
|
sizes[0] = copy(bufs[0][offset-singTun.PacketOffset:], packet)
|
|
return 1, nil
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) Write(bufs [][]byte, offset int) (count int, err error) {
|
|
for _, packet := range bufs {
|
|
if singTun.PacketOffset > 0 {
|
|
singTun.PacketFillHeader(packet[offset-singTun.PacketOffset:], singTun.PacketIPVersion(packet[offset:]))
|
|
}
|
|
_, err = a.tun.Write(packet[offset-singTun.PacketOffset:])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) MTU() (int, error) {
|
|
return int(a.mtu.Load()), nil
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) ForceMTU(mtu int) {
|
|
if mtu <= 0 {
|
|
return
|
|
}
|
|
update := int(a.mtu.Load()) != mtu
|
|
a.mtu.Store(int64(mtu))
|
|
if update {
|
|
select {
|
|
case a.events <- wgTun.EventMTUUpdate:
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) LUID() uint64 {
|
|
if a.nativeTun == nil {
|
|
return 0
|
|
}
|
|
return a.nativeTun.LUID()
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) Name() (string, error) {
|
|
return a.tun.Name()
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) Events() <-chan wgTun.Event {
|
|
return a.events
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) Close() error {
|
|
var err error
|
|
a.closeOnce.Do(func() {
|
|
close(a.events)
|
|
err = a.tun.Close()
|
|
})
|
|
return err
|
|
}
|
|
|
|
func (a *tunDeviceAdapter) BatchSize() int {
|
|
return 1
|
|
}
|