2022-11-22 03:05:54 +02:00
package conf
import (
2024-06-29 21:32:57 +03:00
"context"
2022-11-22 03:05:54 +02:00
"encoding/base64"
"encoding/hex"
2024-10-15 06:30:29 +03:00
"fmt"
2023-11-12 22:52:09 +02:00
"strings"
2022-11-22 03:05:54 +02:00
2024-06-29 21:32:57 +03:00
"github.com/xtls/xray-core/common/errors"
2022-11-22 03:05:54 +02:00
"github.com/xtls/xray-core/proxy/wireguard"
2023-08-10 07:43:34 +03:00
"google.golang.org/protobuf/proto"
2022-11-22 03:05:54 +02:00
)
type WireGuardPeerConfig struct {
PublicKey string ` json:"publicKey" `
PreSharedKey string ` json:"preSharedKey" `
Endpoint string ` json:"endpoint" `
2023-11-18 05:27:17 +02:00
KeepAlive uint32 ` json:"keepAlive" `
2022-11-22 03:05:54 +02:00
AllowedIPs [ ] string ` json:"allowedIPs,omitempty" `
}
func ( c * WireGuardPeerConfig ) Build ( ) ( proto . Message , error ) {
var err error
config := new ( wireguard . PeerConfig )
2023-11-18 05:27:17 +02:00
if c . PublicKey != "" {
2024-06-02 02:34:31 +03:00
config . PublicKey , err = ParseWireGuardKey ( c . PublicKey )
2023-11-18 05:27:17 +02:00
if err != nil {
return nil , err
}
2022-11-22 03:05:54 +02:00
}
if c . PreSharedKey != "" {
2024-06-02 02:34:31 +03:00
config . PreSharedKey , err = ParseWireGuardKey ( c . PreSharedKey )
2022-11-22 03:05:54 +02:00
if err != nil {
return nil , err
}
}
config . Endpoint = c . Endpoint
// default 0
2023-11-18 05:27:17 +02:00
config . KeepAlive = c . KeepAlive
2022-11-22 03:05:54 +02:00
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 {
2023-11-18 05:27:17 +02:00
IsClient bool ` json:"" `
2024-10-15 06:30:29 +03:00
KernelTun * bool ` json:"kernelTun" `
2023-11-18 05:27:17 +02:00
KernelMode * bool ` json:"kernelMode" `
2023-11-12 22:52:09 +02:00
SecretKey string ` json:"secretKey" `
Address [ ] string ` json:"address" `
Peers [ ] * WireGuardPeerConfig ` json:"peers" `
2023-11-18 05:27:17 +02:00
MTU int32 ` json:"mtu" `
NumWorkers int32 ` json:"workers" `
2023-11-12 22:52:09 +02:00
Reserved [ ] byte ` json:"reserved" `
DomainStrategy string ` json:"domainStrategy" `
2022-11-22 03:05:54 +02:00
}
func ( c * WireGuardConfig ) Build ( ) ( proto . Message , error ) {
config := new ( wireguard . DeviceConfig )
var err error
2024-06-02 02:34:31 +03:00
config . SecretKey , err = ParseWireGuardKey ( c . SecretKey )
2022-11-22 03:05:54 +02:00
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 {
2023-11-18 05:27:17 +02:00
config . Mtu = c . MTU
2022-11-22 03:05:54 +02:00
}
2023-11-18 05:27:17 +02:00
// these a fallback code exists in wireguard-go code,
2022-11-22 03:05:54 +02:00
// we don't need to process fallback manually
2023-11-18 05:27:17 +02:00
config . NumWorkers = c . NumWorkers
2022-11-22 03:05:54 +02:00
2023-03-02 18:55:42 +02:00
if len ( c . Reserved ) != 0 && len ( c . Reserved ) != 3 {
2024-06-29 21:32:57 +03:00
return nil , errors . New ( ` "reserved" should be empty or 3 bytes ` )
2023-03-02 18:55:42 +02:00
}
config . Reserved = c . Reserved
2023-11-12 22:52:09 +02:00
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 :
2024-06-29 21:32:57 +03:00
return nil , errors . New ( "unsupported domain strategy: " , c . DomainStrategy )
2023-11-12 22:52:09 +02:00
}
2023-11-18 05:27:17 +02:00
config . IsClient = c . IsClient
2024-10-15 06:30:29 +03:00
kernelTunSupported , err := wireguard . KernelTunSupported ( )
if err != nil {
errors . LogWarning ( context . Background ( ) , fmt . Sprintf ( "Failed to check kernel TUN support: %v. This may indicate that your OS doesn't support kernel TUN or you lack the necessary permissions. Please ensure you have the required privileges." , err ) )
config . KernelMode = false
return config , nil
}
if c . KernelMode == nil {
c . KernelMode = c . KernelTun
}
2023-11-18 05:27:17 +02:00
if c . KernelMode != nil {
config . KernelMode = * c . KernelMode
2024-10-15 06:30:29 +03:00
if config . KernelMode && ! kernelTunSupported {
errors . LogWarning ( context . Background ( ) , "kernel TUN is not supported on your OS or permission is insufficient" )
2023-11-18 05:27:17 +02:00
}
} else {
2024-10-15 06:30:29 +03:00
config . KernelMode = kernelTunSupported
2023-11-18 05:27:17 +02:00
if config . KernelMode {
2024-10-15 06:30:29 +03:00
errors . LogDebug ( context . Background ( ) , "kernel TUN is enabled as it's supported and permission is sufficient" )
2023-11-18 05:27:17 +02:00
}
}
2022-11-22 03:05:54 +02:00
return config , nil
}
2024-06-02 02:34:31 +03:00
func ParseWireGuardKey ( str string ) ( string , error ) {
2023-11-18 05:27:17 +02:00
var err error
if len ( str ) % 2 == 0 {
_ , err = hex . DecodeString ( str )
if err == nil {
return str , nil
2022-11-22 03:05:54 +02:00
}
2023-11-18 05:27:17 +02:00
}
var dat [ ] byte
str = strings . TrimSuffix ( str , "=" )
if strings . ContainsRune ( str , '+' ) || strings . ContainsRune ( str , '/' ) {
dat , err = base64 . RawStdEncoding . DecodeString ( str )
2022-11-22 03:05:54 +02:00
} else {
2023-11-18 05:27:17 +02:00
dat , err = base64 . RawURLEncoding . DecodeString ( str )
2022-11-22 03:05:54 +02:00
}
2023-11-18 05:27:17 +02:00
if err == nil {
return hex . EncodeToString ( dat ) , nil
}
2024-06-29 21:32:57 +03:00
return "" , errors . New ( "failed to deserialize key" ) . Base ( err )
2022-11-22 03:05:54 +02:00
}