sing-tun/tun.go
2022-08-15 09:46:58 +08:00

100 lines
2.3 KiB
Go

package tun
import (
"io"
"net"
"net/netip"
"runtime"
"sort"
"strconv"
"strings"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/ranges"
)
type Handler interface {
N.TCPConnectionHandler
N.UDPConnectionHandler
E.Handler
}
type Tun interface {
io.ReadWriter
Close() error
}
type WinTun interface {
Tun
ReadPacket() ([]byte, func(), error)
}
type Options struct {
Name string
Inet4Address netip.Prefix
Inet6Address netip.Prefix
MTU uint32
AutoRoute bool
IncludeUID []ranges.Range[uint32]
IncludeAndroidUser []int
ExcludeUID []ranges.Range[uint32]
}
func (o Options) ExcludedRanges() (uidRanges []ranges.Range[uint32]) {
var includeAndroidUser []int
if runtime.GOOS == "android" {
includeAndroidUser = o.IncludeAndroidUser
}
return buildExcludedRanges(o.IncludeUID, o.ExcludeUID, includeAndroidUser)
}
const (
androidUserRange = 100000
userEnd uint32 = 0xFFFFFFFF - 1
)
func buildExcludedRanges(includeRanges []ranges.Range[uint32], excludeRanges []ranges.Range[uint32], includeAndroidUser []int) (uidRanges []ranges.Range[uint32]) {
if len(includeRanges) > 0 {
uidRanges = includeRanges
}
if len(includeAndroidUser) > 0 {
includeAndroidUser = common.Uniq(includeAndroidUser)
sort.Ints(includeAndroidUser)
for _, androidUser := range includeAndroidUser {
uidRanges = append(uidRanges, ranges.New[uint32](uint32(androidUser)*androidUserRange, uint32(androidUser+1)*androidUserRange-1))
}
}
if len(uidRanges) > 0 {
uidRanges = ranges.Exclude(uidRanges, excludeRanges)
uidRanges = ranges.Revert(0, userEnd, uidRanges)
} else {
uidRanges = excludeRanges
}
return ranges.Merge(uidRanges)
}
func DefaultInterfaceName() (tunName string) {
if runtime.GOOS == "darwin" {
tunName = "utun"
} 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 {
tunIndex = int(index) + 1
}
}
}
tunName = F.ToString(tunName, tunIndex)
return
}