Files
Xray-core/infra/conf/tun.go
T
patternihaandClaude Opus 5.5 63de6135cb TUN inbound: Rename strictRoute to autoSystemWFP
It only turns on the Windows Filtering Platform filters, along with Xray
resolving its own lookups while they restrict DNS, so it is named after
what it sets up in the system, like autoSystemRoutingTable and
autoSystemDNS. The config field becomes auto_system_wfp, with the same
number; strictRoute was never released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:22:22 +03:30

115 lines
2.7 KiB
Go

package conf
import (
"crypto/rand"
"fmt"
"math/big"
"net"
"strconv"
"github.com/xtls/xray-core/proxy/tun"
"google.golang.org/protobuf/proto"
)
type TunConfig struct {
Name string `json:"name"`
Desc string `json:"desc"`
MTU uint32 `json:"mtu"`
Gateway []string `json:"gateway"`
DNS []string `json:"dns"`
UserLevel uint32 `json:"userLevel"`
AutoSystemRoutingTable []string `json:"autoSystemRoutingTable"`
AutoOutboundsInterface *string `json:"autoOutboundsInterface"`
AutoSystemDNS bool `json:"autoSystemDNS"`
AutoSystemWFP bool `json:"autoSystemWFP"`
}
func (v *TunConfig) Build() (proto.Message, error) {
config := &tun.Config{
Name: v.Name,
Desc: v.Desc,
MTU: v.MTU,
Gateway: v.Gateway,
DNS: v.DNS,
UserLevel: v.UserLevel,
AutoSystemRoutingTable: v.AutoSystemRoutingTable,
AutoSystemDns: v.AutoSystemDNS,
AutoSystemWfp: v.AutoSystemWFP,
}
if v.AutoOutboundsInterface != nil {
config.AutoOutboundsInterface = *v.AutoOutboundsInterface
}
if len(v.AutoSystemRoutingTable) > 0 && v.AutoOutboundsInterface == nil {
config.AutoOutboundsInterface = "auto"
}
if config.Name == "" {
name, err := GetAvailableTunName()
if err != nil {
return nil, err
}
config.Name = name
}
if config.Desc == "" {
config.Desc = "Wintun"
}
if config.MTU == 0 {
config.MTU = 1500
}
return config, nil
}
const (
tunNamePrefix = "utun"
minTunIndex = 10
maxTunIndex = 1024
)
func GetAvailableTunName() (string, error) {
interfaces, err := net.Interfaces()
if err != nil {
return "", fmt.Errorf("fail to get system interface information: %w", err)
}
usedNames := make(map[string]struct{}, len(interfaces))
for _, iface := range interfaces {
usedNames[iface.Name] = struct{}{}
}
startIndex, err := randomInt(minTunIndex, maxTunIndex)
if err != nil {
return "", fmt.Errorf("fail to generate valid tun name: %w", err)
}
rangeSize := maxTunIndex - minTunIndex + 1
for offset := 0; offset < rangeSize; offset++ {
index := minTunIndex + (startIndex-minTunIndex+offset)%rangeSize
name := tunNamePrefix + strconv.Itoa(index)
if _, exists := usedNames[name]; !exists {
return name, nil
}
}
return "", fmt.Errorf(
"no available TUN interface name in range %s%d-%s%d",
tunNamePrefix,
minTunIndex,
tunNamePrefix,
maxTunIndex,
)
}
func randomInt(min, max int) (int, error) {
value, err := rand.Int(
rand.Reader,
big.NewInt(int64(max-min+1)),
)
if err != nil {
return 0, err
}
return min + int(value.Int64()), nil
}