Xray-core/proxy/wireguard/tun.go

106 lines
2.0 KiB
Go

package wireguard
import (
"context"
"errors"
"fmt"
"net"
"net/netip"
"runtime"
"strconv"
"strings"
"sync"
"github.com/xtls/xray-core/common/log"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
)
type Tunnel interface {
BuildDevice(ipc string, bind conn.Bind) error
DialContextTCPAddrPort(ctx context.Context, addr netip.AddrPort) (net.Conn, error)
DialUDPAddrPort(laddr, raddr netip.AddrPort) (net.Conn, error)
Close() error
}
type tunnel struct {
tun tun.Device
device *device.Device
rw sync.Mutex
}
func (t *tunnel) BuildDevice(ipc string, bind conn.Bind) (err error) {
t.rw.Lock()
defer t.rw.Unlock()
if t.device != nil {
return errors.New("device is already initialized")
}
logger := &device.Logger{
Verbosef: func(format string, args ...any) {
log.Record(&log.GeneralMessage{
Severity: log.Severity_Debug,
Content: fmt.Sprintf(format, args...),
})
},
Errorf: func(format string, args ...any) {
log.Record(&log.GeneralMessage{
Severity: log.Severity_Error,
Content: fmt.Sprintf(format, args...),
})
},
}
t.device = device.NewDevice(t.tun, bind, logger)
if err = t.device.IpcSet(ipc); err != nil {
return err
}
if err = t.device.Up(); err != nil {
return err
}
return nil
}
func (t *tunnel) Close() (err error) {
t.rw.Lock()
defer t.rw.Unlock()
if t.device == nil {
return nil
}
t.device.Close()
t.device = nil
err = t.tun.Close()
t.tun = nil
return nil
}
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 {
tunIndex = int(index) + 1
}
}
}
tunName = fmt.Sprintf("%s%d", tunName, tunIndex)
return
}