mirror of https://github.com/XTLS/Xray-core
160 lines
4.0 KiB
Go
160 lines
4.0 KiB
Go
package conf
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"strings"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
"github.com/xtls/xray-core/proxy/wireguard"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
type WireGuardPeerConfig struct {
|
|
PublicKey string `json:"publicKey"`
|
|
PreSharedKey string `json:"preSharedKey"`
|
|
Endpoint string `json:"endpoint"`
|
|
KeepAlive uint32 `json:"keepAlive"`
|
|
AllowedIPs []string `json:"allowedIPs,omitempty"`
|
|
}
|
|
|
|
func (c *WireGuardPeerConfig) Build() (proto.Message, error) {
|
|
var err error
|
|
config := new(wireguard.PeerConfig)
|
|
|
|
if c.PublicKey != "" {
|
|
config.PublicKey, err = ParseWireGuardKey(c.PublicKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if c.PreSharedKey != "" {
|
|
config.PreSharedKey, err = ParseWireGuardKey(c.PreSharedKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
config.Endpoint = c.Endpoint
|
|
// default 0
|
|
config.KeepAlive = c.KeepAlive
|
|
if c.AllowedIPs == nil {
|
|
config.AllowedIps = []string{"0.0.0.0/0", "::0/0"}
|
|
} else {
|
|
config.AllowedIps = c.AllowedIPs
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
type WireGuardConfig struct {
|
|
IsClient bool `json:""`
|
|
|
|
KernelMode *bool `json:"kernelMode"`
|
|
SecretKey string `json:"secretKey"`
|
|
Address []string `json:"address"`
|
|
Peers []*WireGuardPeerConfig `json:"peers"`
|
|
MTU int32 `json:"mtu"`
|
|
NumWorkers int32 `json:"workers"`
|
|
Reserved []byte `json:"reserved"`
|
|
DomainStrategy string `json:"domainStrategy"`
|
|
}
|
|
|
|
func (c *WireGuardConfig) Build() (proto.Message, error) {
|
|
config := new(wireguard.DeviceConfig)
|
|
|
|
var err error
|
|
config.SecretKey, err = ParseWireGuardKey(c.SecretKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if c.Address == nil {
|
|
// bogon ips
|
|
config.Endpoint = []string{"10.0.0.1", "fd59:7153:2388:b5fd:0000:0000:0000:0001"}
|
|
} else {
|
|
config.Endpoint = c.Address
|
|
}
|
|
|
|
if c.Peers != nil {
|
|
config.Peers = make([]*wireguard.PeerConfig, len(c.Peers))
|
|
for i, p := range c.Peers {
|
|
msg, err := p.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Peers[i] = msg.(*wireguard.PeerConfig)
|
|
}
|
|
}
|
|
|
|
if c.MTU == 0 {
|
|
config.Mtu = 1420
|
|
} else {
|
|
config.Mtu = c.MTU
|
|
}
|
|
// these a fallback code exists in wireguard-go code,
|
|
// we don't need to process fallback manually
|
|
config.NumWorkers = c.NumWorkers
|
|
|
|
if len(c.Reserved) != 0 && len(c.Reserved) != 3 {
|
|
return nil, errors.New(`"reserved" should be empty or 3 bytes`)
|
|
}
|
|
config.Reserved = c.Reserved
|
|
|
|
switch strings.ToLower(c.DomainStrategy) {
|
|
case "forceip", "":
|
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP
|
|
case "forceipv4":
|
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP4
|
|
case "forceipv6":
|
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP6
|
|
case "forceipv4v6":
|
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP46
|
|
case "forceipv6v4":
|
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP64
|
|
default:
|
|
return nil, errors.New("unsupported domain strategy: ", c.DomainStrategy)
|
|
}
|
|
|
|
config.IsClient = c.IsClient
|
|
if c.KernelMode != nil {
|
|
config.KernelMode = *c.KernelMode
|
|
if config.KernelMode && !wireguard.KernelTunSupported() {
|
|
errors.LogWarning(context.Background(), "kernel mode is not supported on your OS or permission is insufficient")
|
|
}
|
|
} else {
|
|
config.KernelMode = wireguard.KernelTunSupported()
|
|
if config.KernelMode {
|
|
errors.LogDebug(context.Background(), "kernel mode is enabled as it's supported and permission is sufficient")
|
|
}
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
func ParseWireGuardKey(str string) (string, error) {
|
|
var err error
|
|
|
|
if len(str)%2 == 0 {
|
|
_, err = hex.DecodeString(str)
|
|
if err == nil {
|
|
return str, nil
|
|
}
|
|
}
|
|
|
|
var dat []byte
|
|
str = strings.TrimSuffix(str, "=")
|
|
if strings.ContainsRune(str, '+') || strings.ContainsRune(str, '/') {
|
|
dat, err = base64.RawStdEncoding.DecodeString(str)
|
|
} else {
|
|
dat, err = base64.RawURLEncoding.DecodeString(str)
|
|
}
|
|
if err == nil {
|
|
return hex.EncodeToString(dat), nil
|
|
}
|
|
|
|
return "", errors.New("failed to deserialize key").Base(err)
|
|
}
|