Build and Release for Windows 7 / check-assets (push) Successful in 11s
Build and Release / check-assets (push) Successful in 16s
Scheduled assets update / geodat (push) Successful in 21s
Tests and Checkings / check-assets (push) Successful in 11s
Scheduled assets update / wintun (push) Successful in 17s
Tests and Checkings / check-proto (push) Successful in 13s
Build and Release for Windows 7 / check-assets (release) Successful in 10s
Build and Release / check-assets (release) Successful in 15s
Tests and Checkings / check-format (push) Successful in 1m14s
Build and Release / build (amd64, linux, ) (push) Successful in 1m14s
Build and Release for Windows 7 / build (win7-64, amd64, windows) (push) Successful in 2m0s
Build and Release / build (arm64, linux) (push) Successful in 1m31s
Build and Release for Windows 7 / build (win7-64, amd64, windows) (release) Successful in 2m5s
Build and Release / build (amd64, linux, ) (release) Successful in 1m15s
Build and Release / build (arm64, linux) (release) Successful in 1m38s
Build and Push Docker Image / build-and-push (release) Successful in 7m25s
Adopt fix from https://github.com/XTLS/Xray-core/commit/c7e569b0377724600af1ea2a05eb8f4c7c3e0609 for Amnezia protocol, now user's DNS is work properly
217 lines
5.2 KiB
Go
217 lines
5.2 KiB
Go
package conf
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
"github.com/xtls/xray-core/common/protocol"
|
|
"github.com/xtls/xray-core/common/serial"
|
|
"github.com/xtls/xray-core/common/task"
|
|
"github.com/xtls/xray-core/proxy/amnezia"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
type AmneziaPeerConfig struct {
|
|
PublicKey string `json:"publicKey"`
|
|
PreSharedKey string `json:"preSharedKey"`
|
|
Endpoint string `json:"endpoint"`
|
|
KeepAlive uint32 `json:"keepAlive"`
|
|
AllowedIPs []string `json:"allowedIPs,omitempty"`
|
|
|
|
Level uint32 `json:"level"`
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
func (c *AmneziaPeerConfig) Build() (*amnezia.PeerConfig, error) {
|
|
var err error
|
|
config := new(amnezia.PeerConfig)
|
|
|
|
if c.PublicKey != "" {
|
|
config.PublicKey, err = ParseAmneziaKey(c.PublicKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if c.PreSharedKey != "" {
|
|
config.PreSharedKey, err = ParseAmneziaKey(c.PreSharedKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
config.Endpoint = c.Endpoint
|
|
if c.KeepAlive != 0 {
|
|
config.KeepAlive = strconv.FormatUint(uint64(c.KeepAlive), 10)
|
|
}
|
|
if c.AllowedIPs == nil {
|
|
config.AllowedIps = []string{"0.0.0.0/0", "::0/0"}
|
|
} else {
|
|
config.AllowedIps = c.AllowedIPs
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
type AmneziaConfig struct {
|
|
IsClient bool `json:""`
|
|
|
|
NoKernelTun bool `json:"noKernelTun"`
|
|
SecretKey string `json:"secretKey"`
|
|
Address []string `json:"address"`
|
|
Peers []*AmneziaPeerConfig `json:"peers"`
|
|
MTU int32 `json:"mtu"`
|
|
Reserved []byte `json:"reserved"`
|
|
DomainStrategy string `json:"domainStrategy"`
|
|
DNS []string `json:"remoteDNS"`
|
|
// Amnezia stuff (version 2.0)
|
|
JunkCount int32 `json:"jc"`
|
|
JunkMin int32 `json:"jmin"`
|
|
JunkMax int32 `json:"jmax"`
|
|
|
|
InitPadding int32 `json:"s1"`
|
|
ResponsePadding int32 `json:"s2"`
|
|
CookiePadding int32 `json:"s3"`
|
|
TransportPadding int32 `json:"s4"`
|
|
|
|
InitHeader string `json:"h1"`
|
|
ResponseHeader string `json:"h2"`
|
|
CookieHeader string `json:"h3"`
|
|
TransportHeader string `json:"h4"`
|
|
|
|
Signature1 string `json:"i1"`
|
|
Signature2 string `json:"i2"`
|
|
Signature3 string `json:"i3"`
|
|
Signature4 string `json:"i4"`
|
|
Signature5 string `json:"i5"`
|
|
}
|
|
|
|
func (c *AmneziaConfig) Build() (proto.Message, error) {
|
|
config := new(amnezia.DeviceConfig)
|
|
|
|
var err error
|
|
config.SecretKey, err = ParseAmneziaKey(c.SecretKey)
|
|
if err != nil {
|
|
return nil, errors.New("invalid Amnezia secret key: %w", 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.IsClient {
|
|
config.Peers = make([]*amnezia.PeerConfig, len(c.Peers))
|
|
for i, p := range c.Peers {
|
|
msg, err := p.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Peers[i] = msg
|
|
}
|
|
} else {
|
|
config.Users = make([]*protocol.User, len(c.Peers))
|
|
processUser := func(idx int) error {
|
|
p := c.Peers[idx]
|
|
m, err := p.Build()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
config.Users[idx] = &protocol.User{
|
|
Email: p.Email,
|
|
Level: p.Level,
|
|
Account: serial.ToTypedMessage(m),
|
|
}
|
|
return nil
|
|
}
|
|
if err := task.ParallelForN(len(c.Peers), processUser); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if c.MTU == 0 {
|
|
config.Mtu = 1420
|
|
} else {
|
|
config.Mtu = c.MTU
|
|
}
|
|
|
|
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 = amnezia.DeviceConfig_FORCE_IP
|
|
case "forceipv4":
|
|
config.DomainStrategy = amnezia.DeviceConfig_FORCE_IP4
|
|
case "forceipv6":
|
|
config.DomainStrategy = amnezia.DeviceConfig_FORCE_IP6
|
|
case "forceipv4v6":
|
|
config.DomainStrategy = amnezia.DeviceConfig_FORCE_IP46
|
|
case "forceipv6v4":
|
|
config.DomainStrategy = amnezia.DeviceConfig_FORCE_IP64
|
|
default:
|
|
return nil, errors.New("unsupported domain strategy: ", c.DomainStrategy)
|
|
}
|
|
|
|
config.IsClient = c.IsClient
|
|
config.NoKernelTun = c.NoKernelTun
|
|
config.DNS = c.DNS
|
|
|
|
config.Jc = c.JunkCount
|
|
config.JMin = c.JunkMin
|
|
config.JMax = c.JunkMax
|
|
|
|
config.S1 = c.InitPadding
|
|
config.S2 = c.ResponsePadding
|
|
config.S3 = c.CookiePadding
|
|
config.S4 = c.TransportPadding
|
|
|
|
config.H1 = c.InitHeader
|
|
config.H2 = c.ResponseHeader
|
|
config.H3 = c.CookieHeader
|
|
config.H4 = c.TransportHeader
|
|
|
|
config.I1 = c.Signature1
|
|
config.I2 = c.Signature2
|
|
config.I3 = c.Signature3
|
|
config.I4 = c.Signature4
|
|
config.I5 = c.Signature5
|
|
|
|
return config, nil
|
|
}
|
|
|
|
func ParseAmneziaKey(str string) (string, error) {
|
|
var err error
|
|
|
|
if str == "" {
|
|
return "", errors.New("key must not be empty")
|
|
}
|
|
|
|
if len(str) == 64 {
|
|
_, 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)
|
|
}
|