mirror of
https://github.com/SagerNet/sing-tun.git
synced 2025-03-31 10:27:39 +03:00
168 lines
4 KiB
Go
168 lines
4 KiB
Go
package tun
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"net/netip"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/sagernet/sing/common/control"
|
|
F "github.com/sagernet/sing/common/format"
|
|
"github.com/sagernet/sing/common/logger"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
N "github.com/sagernet/sing/common/network"
|
|
"github.com/sagernet/sing/common/ranges"
|
|
)
|
|
|
|
type Handler interface {
|
|
PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error
|
|
N.TCPConnectionHandlerEx
|
|
N.UDPConnectionHandlerEx
|
|
}
|
|
|
|
type Tun interface {
|
|
io.ReadWriter
|
|
N.VectorisedWriter
|
|
Name() (string, error)
|
|
Start() error
|
|
Close() error
|
|
UpdateRouteOptions(tunOptions Options) error
|
|
}
|
|
|
|
type WinTun interface {
|
|
Tun
|
|
ReadPacket() ([]byte, func(), error)
|
|
}
|
|
|
|
type LinuxTUN interface {
|
|
Tun
|
|
N.FrontHeadroom
|
|
BatchSize() int
|
|
BatchRead(buffers [][]byte, offset int, readN []int) (n int, err error)
|
|
BatchWrite(buffers [][]byte, offset int) (n int, err error)
|
|
TXChecksumOffload() bool
|
|
}
|
|
|
|
const (
|
|
DefaultIPRoute2TableIndex = 2022
|
|
DefaultIPRoute2RuleIndex = 9000
|
|
)
|
|
|
|
type Options struct {
|
|
Name string
|
|
Inet4Address []netip.Prefix
|
|
Inet6Address []netip.Prefix
|
|
MTU uint32
|
|
GSO bool
|
|
AutoRoute bool
|
|
InterfaceScope bool
|
|
Inet4Gateway netip.Addr
|
|
Inet6Gateway netip.Addr
|
|
DNSServers []netip.Addr
|
|
IPRoute2TableIndex int
|
|
IPRoute2RuleIndex int
|
|
AutoRedirectMarkMode bool
|
|
AutoRedirectInputMark uint32
|
|
AutoRedirectOutputMark uint32
|
|
StrictRoute bool
|
|
Inet4RouteAddress []netip.Prefix
|
|
Inet6RouteAddress []netip.Prefix
|
|
Inet4RouteExcludeAddress []netip.Prefix
|
|
Inet6RouteExcludeAddress []netip.Prefix
|
|
IncludeInterface []string
|
|
ExcludeInterface []string
|
|
IncludeUID []ranges.Range[uint32]
|
|
ExcludeUID []ranges.Range[uint32]
|
|
IncludeAndroidUser []int
|
|
IncludePackage []string
|
|
ExcludePackage []string
|
|
InterfaceFinder control.InterfaceFinder
|
|
InterfaceMonitor DefaultInterfaceMonitor
|
|
FileDescriptor int
|
|
Logger logger.Logger
|
|
|
|
// No work for TCP, do not use.
|
|
_TXChecksumOffload bool
|
|
|
|
// For library usages.
|
|
EXP_DisableDNSHijack bool
|
|
}
|
|
|
|
func (o *Options) Inet4GatewayAddr() netip.Addr {
|
|
if o.Inet4Gateway.IsValid() {
|
|
return o.Inet4Gateway
|
|
}
|
|
if len(o.Inet4Address) > 0 {
|
|
switch runtime.GOOS {
|
|
case "android":
|
|
case "linux":
|
|
if HasNextAddress(o.Inet4Address[0], 1) {
|
|
return o.Inet4Address[0].Addr().Next()
|
|
}
|
|
case "darwin":
|
|
return o.Inet4Address[0].Addr()
|
|
default:
|
|
if !o.InterfaceScope {
|
|
if HasNextAddress(o.Inet4Address[0], 1) {
|
|
return o.Inet4Address[0].Addr().Next()
|
|
} else {
|
|
return o.Inet4Address[0].Addr()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return netip.IPv4Unspecified()
|
|
}
|
|
|
|
func (o *Options) Inet6GatewayAddr() netip.Addr {
|
|
if o.Inet6Gateway.IsValid() {
|
|
return o.Inet6Gateway
|
|
}
|
|
if len(o.Inet6Address) > 0 {
|
|
switch runtime.GOOS {
|
|
case "android":
|
|
case "linux":
|
|
if HasNextAddress(o.Inet6Address[0], 1) {
|
|
return o.Inet6Address[0].Addr().Next()
|
|
}
|
|
case "darwin":
|
|
return o.Inet6Address[0].Addr()
|
|
default:
|
|
if !o.InterfaceScope {
|
|
if HasNextAddress(o.Inet6Address[0], 1) {
|
|
return o.Inet6Address[0].Addr().Next()
|
|
} else {
|
|
return o.Inet6Address[0].Addr()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return netip.IPv6Unspecified()
|
|
}
|
|
|
|
func CalculateInterfaceName(name string) (tunName string) {
|
|
if runtime.GOOS == "darwin" {
|
|
tunName = "utun"
|
|
} else if name != "" {
|
|
tunName = name
|
|
} else {
|
|
tunName = "tun"
|
|
}
|
|
interfaces, err := net.Interfaces()
|
|
if err != nil {
|
|
return
|
|
}
|
|
var tunIndex int
|
|
for _, netInterface := range interfaces {
|
|
if strings.HasPrefix(netInterface.Name, tunName) {
|
|
index, parseErr := strconv.ParseInt(netInterface.Name[len(tunName):], 10, 16)
|
|
if parseErr == nil && int(index) >= tunIndex {
|
|
tunIndex = int(index) + 1
|
|
}
|
|
}
|
|
}
|
|
tunName = F.ToString(tunName, tunIndex)
|
|
return
|
|
}
|