Files
Xray-core/infra/conf/tun.go
T
patternihaandClaude Opus 5.5 4ec4fb8aab TUN inbound: Rename to autoSystemWfpBlockLeak and autoSystemDnsToGateway
autoSystemWFP becomes autoSystemWfpBlockLeak, saying that the WFP filters
block leaks, and autoSystemDNS becomes autoSystemDnsToGateway, saying
where it points the system DNS, so that pointing the system DNS at the
gateway on Windows later would fit the same name. Their config fields
keep their numbers; neither was released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:31:00 +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"`
AutoSystemDnsToGateway bool `json:"autoSystemDnsToGateway"`
AutoSystemWfpBlockLeak bool `json:"autoSystemWfpBlockLeak"`
}
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,
AutoSystemDnsToGateway: v.AutoSystemDnsToGateway,
AutoSystemWfpBlockLeak: v.AutoSystemWfpBlockLeak,
}
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
}