github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/infra/conf/wireguard.go (about)

     1  package conf
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/hex"
     6  	"strings"
     7  
     8  	"github.com/xmplusdev/xmcore/proxy/wireguard"
     9  	"google.golang.org/protobuf/proto"
    10  )
    11  
    12  type WireGuardPeerConfig struct {
    13  	PublicKey    string   `json:"publicKey"`
    14  	PreSharedKey string   `json:"preSharedKey"`
    15  	Endpoint     string   `json:"endpoint"`
    16  	KeepAlive    uint32   `json:"keepAlive"`
    17  	AllowedIPs   []string `json:"allowedIPs,omitempty"`
    18  }
    19  
    20  func (c *WireGuardPeerConfig) Build() (proto.Message, error) {
    21  	var err error
    22  	config := new(wireguard.PeerConfig)
    23  
    24  	if c.PublicKey != "" {
    25  		config.PublicKey, err = parseWireGuardKey(c.PublicKey)
    26  		if err != nil {
    27  			return nil, err
    28  		}
    29  	}
    30  
    31  	if c.PreSharedKey != "" {
    32  		config.PreSharedKey, err = parseWireGuardKey(c.PreSharedKey)
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  	}
    37  
    38  	config.Endpoint = c.Endpoint
    39  	// default 0
    40  	config.KeepAlive = c.KeepAlive
    41  	if c.AllowedIPs == nil {
    42  		config.AllowedIps = []string{"0.0.0.0/0", "::0/0"}
    43  	} else {
    44  		config.AllowedIps = c.AllowedIPs
    45  	}
    46  
    47  	return config, nil
    48  }
    49  
    50  type WireGuardConfig struct {
    51  	IsClient bool `json:""`
    52  
    53  	KernelMode     *bool                  `json:"kernelMode"`
    54  	SecretKey      string                 `json:"secretKey"`
    55  	Address        []string               `json:"address"`
    56  	Peers          []*WireGuardPeerConfig `json:"peers"`
    57  	MTU            int32                  `json:"mtu"`
    58  	NumWorkers     int32                  `json:"workers"`
    59  	Reserved       []byte                 `json:"reserved"`
    60  	DomainStrategy string                 `json:"domainStrategy"`
    61  }
    62  
    63  func (c *WireGuardConfig) Build() (proto.Message, error) {
    64  	config := new(wireguard.DeviceConfig)
    65  
    66  	var err error
    67  	config.SecretKey, err = parseWireGuardKey(c.SecretKey)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	if c.Address == nil {
    73  		// bogon ips
    74  		config.Endpoint = []string{"10.0.0.1", "fd59:7153:2388:b5fd:0000:0000:0000:0001"}
    75  	} else {
    76  		config.Endpoint = c.Address
    77  	}
    78  
    79  	if c.Peers != nil {
    80  		config.Peers = make([]*wireguard.PeerConfig, len(c.Peers))
    81  		for i, p := range c.Peers {
    82  			msg, err := p.Build()
    83  			if err != nil {
    84  				return nil, err
    85  			}
    86  			config.Peers[i] = msg.(*wireguard.PeerConfig)
    87  		}
    88  	}
    89  
    90  	if c.MTU == 0 {
    91  		config.Mtu = 1420
    92  	} else {
    93  		config.Mtu = c.MTU
    94  	}
    95  	// these a fallback code exists in wireguard-go code,
    96  	// we don't need to process fallback manually
    97  	config.NumWorkers = c.NumWorkers
    98  
    99  	if len(c.Reserved) != 0 && len(c.Reserved) != 3 {
   100  		return nil, newError(`"reserved" should be empty or 3 bytes`)
   101  	}
   102  	config.Reserved = c.Reserved
   103  
   104  	switch strings.ToLower(c.DomainStrategy) {
   105  	case "forceip", "":
   106  		config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP
   107  	case "forceipv4":
   108  		config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP4
   109  	case "forceipv6":
   110  		config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP6
   111  	case "forceipv4v6":
   112  		config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP46
   113  	case "forceipv6v4":
   114  		config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP64
   115  	default:
   116  		return nil, newError("unsupported domain strategy: ", c.DomainStrategy)
   117  	}
   118  
   119  	config.IsClient = c.IsClient
   120  	if c.KernelMode != nil {
   121  		config.KernelMode = *c.KernelMode
   122  		if config.KernelMode && !wireguard.KernelTunSupported() {
   123  			newError("kernel mode is not supported on your OS or permission is insufficient").AtWarning().WriteToLog()
   124  		}
   125  	} else {
   126  		config.KernelMode = wireguard.KernelTunSupported()
   127  		if config.KernelMode {
   128  			newError("kernel mode is enabled as it's supported and permission is sufficient").AtDebug().WriteToLog()
   129  		}
   130  	}
   131  
   132  	return config, nil
   133  }
   134  
   135  func parseWireGuardKey(str string) (string, error) {
   136  	var err error
   137  
   138  	if len(str)%2 == 0 {
   139  		_, err = hex.DecodeString(str)
   140  		if err == nil {
   141  			return str, nil
   142  		}
   143  	}
   144  
   145  	var dat []byte
   146  	str = strings.TrimSuffix(str, "=")
   147  	if strings.ContainsRune(str, '+') || strings.ContainsRune(str, '/') {
   148  		dat, err = base64.RawStdEncoding.DecodeString(str)
   149  	} else {
   150  		dat, err = base64.RawURLEncoding.DecodeString(str)
   151  	}
   152  	if err == nil {
   153  		return hex.EncodeToString(dat), nil
   154  	}
   155  
   156  	return "", newError("failed to deserialize key").Base(err)
   157  }