Compare commits

..

23 Commits

Author SHA1 Message Date
RPRX
0203190a98 v1.1.5 2020-12-25 15:25:10 +00:00
RPRX
a78db47571 Adjust OCSP Stapling 2020-12-25 15:10:12 +00:00
RPRX
ffd8fd1d8a Adjust JSON & TOML & YAML 2020-12-25 18:53:17 +08:00
eMeab
3d7e86efba Add OCSP Stapling for TLS & XTLS (#92) 2020-12-25 08:01:20 +00:00
Arthur Morgan
6f25191822 Changes from v2ray-core (#93) 2020-12-24 19:45:35 +00:00
Monsoon
85619b5a29 Add YAML Support (#86) 2020-12-24 19:30:26 +00:00
秋のかえで
f073456ac0 Add TOML Support (#98) 2020-12-24 19:11:32 +00:00
RPRX
09f9d03fb6 Add Homebrew 2020-12-24 12:43:19 +00:00
RPRX
8f8f7dd66f Refactor: Shadowsocks & Trojan UDP FullCone NAT
https://t.me/projectXray/95704
2020-12-23 13:06:21 +00:00
RPRX
4140ed7ab0 v1.1.4 2020-12-18 13:12:41 +00:00
RPRX
f390047b37 Disable VMess drain when not pure connection 2020-12-18 12:45:47 +00:00
RPRX
ff9bb2d8df Optimize cipherSuites setting loader 2020-12-17 09:25:30 +00:00
RPRX
38faac5ffc Adjust config loader of TLS & XTLS 2020-12-16 15:59:04 +00:00
eMeab
88dfed931b Add cipherSuites setting for TLS & XTLS (#78) 2020-12-16 12:53:55 +00:00
Jim Han
19ce0e99a5 Config loader returns error instead of directly panic (#80) 2020-12-16 12:35:27 +00:00
Jim Han
fe445f8e1a Fix: HTTP dialer uses ctx instead of context.Background() (#79) 2020-12-16 11:52:45 +00:00
RPRX
6a5618bc54 Outbound Splice supports Inbound XTLS 2020-12-16 10:35:28 +00:00
RPRX
ed0e9b12dc Adjust ProtoBuf of TLS & XTLS 2020-12-16 08:50:18 +00:00
eMeab
dab978749c Add minVersion setting for TLS & XTLS (#77) 2020-12-16 05:20:24 +00:00
RPRX
45f44c401a Refactor: Optimize Memory Usage At Startup
https://github.com/XTLS/Xray-core/issues/68#issuecomment-745231528
2020-12-15 20:27:18 +08:00
RPRX
2e942e0303 Fix Trojan XTLS 2020-12-14 17:05:15 +08:00
RPRX
decb012f9d Add Qv2ray and Kitsunebi 2020-12-13 06:21:50 +00:00
RPRX
574446f942 Add Hello World and ShadowSocksR Plus+ 2020-12-13 05:55:38 +00:00
54 changed files with 1244 additions and 372 deletions

View File

@@ -20,6 +20,9 @@
- Magisk - Magisk
- [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk) - [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk)
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk) - [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
- Homebrew
- [Repository 0](https://github.com/N4FA/homebrew-xray)
- [Repository 1](https://github.com/xiruizhao/homebrew-xray)
## Usage ## Usage
@@ -29,10 +32,14 @@
- OpenWrt - OpenWrt
- [PassWall](https://github.com/xiaorouji/openwrt-passwall) - [PassWall](https://github.com/xiaorouji/openwrt-passwall)
- [Hello World](https://github.com/jerrykuku/luci-app-vssr)
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
- Windows - Windows
- [v2rayN](https://github.com/2dust/v2rayN) - [v2rayN](https://github.com/2dust/v2rayN)
- [Qv2ray](https://github.com/Qv2ray/Qv2ray)
- Android - Android
- [v2rayNG](https://github.com/2dust/v2rayNG) - [v2rayNG](https://github.com/2dust/v2rayNG)
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)
- iOS / Mac - iOS / Mac
- [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118) - [Shadowrocket](https://apps.apple.com/app/shadowrocket/id932747118)

View File

@@ -2,6 +2,7 @@ package buf
import ( import (
"io" "io"
"net"
"github.com/xtls/xray-core/common/bytespool" "github.com/xtls/xray-core/common/bytespool"
) )
@@ -20,6 +21,7 @@ type Buffer struct {
v []byte v []byte
start int32 start int32
end int32 end int32
UDP *net.UDPAddr
} }
// New creates a Buffer with 0 length and 2K capacity. // New creates a Buffer with 0 length and 2K capacity.

View File

@@ -36,19 +36,23 @@ func (m *AccessMessage) String() string {
builder.WriteString(string(m.Status)) builder.WriteString(string(m.Status))
builder.WriteByte(' ') builder.WriteByte(' ')
builder.WriteString(serial.ToString(m.To)) builder.WriteString(serial.ToString(m.To))
builder.WriteByte(' ')
if len(m.Detour) > 0 { if len(m.Detour) > 0 {
builder.WriteByte('[') builder.WriteString(" [")
builder.WriteString(m.Detour) builder.WriteString(m.Detour)
builder.WriteString("] ") builder.WriteByte(']')
}
if reason := serial.ToString(m.Reason); len(reason) > 0 {
builder.WriteString(" ")
builder.WriteString(reason)
} }
builder.WriteString(serial.ToString(m.Reason))
if len(m.Email) > 0 { if len(m.Email) > 0 {
builder.WriteString(" email: ") builder.WriteString(" email: ")
builder.WriteString(m.Email) builder.WriteString(m.Email)
builder.WriteByte(' ')
} }
return builder.String() return builder.String()
} }

View File

@@ -1,4 +1,4 @@
package jsonem package ocsp
import "github.com/xtls/xray-core/common/errors" import "github.com/xtls/xray-core/common/errors"

136
common/ocsp/ocsp.go Normal file
View File

@@ -0,0 +1,136 @@
package ocsp
import (
"bytes"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"net/http"
"os"
"golang.org/x/crypto/ocsp"
"github.com/xtls/xray-core/common/platform/filesystem"
)
func GetOCSPForFile(path string) ([]byte, error) {
return filesystem.ReadFile(path)
}
func CheckOCSPFileIsNotExist(path string) bool {
_, err := os.Stat(path)
if err != nil {
return os.IsNotExist(err)
}
return false
}
func GetOCSPStapling(cert [][]byte, path string) ([]byte, error) {
ocspData, err := GetOCSPForFile(path)
if err != nil {
ocspData, err = GetOCSPForCert(cert)
if !CheckOCSPFileIsNotExist(path) {
err = os.Remove(path)
if err != nil {
return nil, err
}
}
newFile, err := os.Create(path)
if err != nil {
return nil, err
}
newFile.Write(ocspData)
defer newFile.Close()
}
return ocspData, nil
}
func GetOCSPForCert(cert [][]byte) ([]byte, error) {
bundle := new(bytes.Buffer)
for _, derBytes := range cert {
err := pem.Encode(bundle, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
if err != nil {
return nil, err
}
}
pemBundle := bundle.Bytes()
certificates, err := parsePEMBundle(pemBundle)
if err != nil {
return nil, err
}
issuedCert := certificates[0]
if len(issuedCert.OCSPServer) == 0 {
return nil, newError("no OCSP server specified in cert")
}
if len(certificates) == 1 {
if len(issuedCert.IssuingCertificateURL) == 0 {
return nil, newError("no issuing certificate URL")
}
resp, errC := http.Get(issuedCert.IssuingCertificateURL[0])
if errC != nil {
return nil, newError("no issuing certificate URL")
}
defer resp.Body.Close()
issuerBytes, errC := ioutil.ReadAll(resp.Body)
if errC != nil {
return nil, newError(errC)
}
issuerCert, errC := x509.ParseCertificate(issuerBytes)
if errC != nil {
return nil, newError(errC)
}
certificates = append(certificates, issuerCert)
}
issuerCert := certificates[1]
ocspReq, err := ocsp.CreateRequest(issuedCert, issuerCert, nil)
if err != nil {
return nil, err
}
reader := bytes.NewReader(ocspReq)
req, err := http.Post(issuedCert.OCSPServer[0], "application/ocsp-request", reader)
if err != nil {
return nil, newError(err)
}
defer req.Body.Close()
ocspResBytes, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, newError(err)
}
return ocspResBytes, nil
}
// parsePEMBundle parses a certificate bundle from top to bottom and returns
// a slice of x509 certificates. This function will error if no certificates are found.
func parsePEMBundle(bundle []byte) ([]*x509.Certificate, error) {
var certificates []*x509.Certificate
var certDERBlock *pem.Block
for {
certDERBlock, bundle = pem.Decode(bundle)
if certDERBlock == nil {
break
}
if certDERBlock.Type == "CERTIFICATE" {
cert, err := x509.ParseCertificate(certDERBlock.Bytes)
if err != nil {
return nil, err
}
certificates = append(certificates, cert)
}
}
if len(certificates) == 0 {
return nil, newError("no certificates were found while parsing the bundle")
}
return certificates, nil
}

View File

@@ -18,7 +18,7 @@ import (
) )
var ( var (
version = "1.1.3" version = "1.1.5"
build = "Custom" build = "Custom"
codename = "Xray, Penetrates Everything." codename = "Xray, Penetrates Everything."
intro = "A unified platform for anti-censorship." intro = "A unified platform for anti-censorship."

13
go.mod
View File

@@ -3,7 +3,8 @@ module github.com/xtls/xray-core
go 1.15 go 1.15
require ( require (
github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165 // indirect github.com/BurntSushi/toml v0.3.1
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/golang/mock v1.4.4 github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/google/go-cmp v0.5.4 github.com/google/go-cmp v0.5.4
@@ -11,15 +12,15 @@ require (
github.com/lucas-clemente/quic-go v0.19.3 github.com/lucas-clemente/quic-go v0.19.3
github.com/miekg/dns v1.1.35 github.com/miekg/dns v1.1.35
github.com/pires/go-proxyproto v0.3.3 github.com/pires/go-proxyproto v0.3.3
github.com/seiflotfy/cuckoofilter v0.0.0-20201009151232-afb285a456ab github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5 go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 golang.org/x/net v0.0.0-20201224014010-6772e930b67b
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20201211002650-1f0c578a6b29 golang.org/x/sys v0.0.0-20201223074533-0d417f636930
google.golang.org/grpc v1.34.0 google.golang.org/grpc v1.34.0
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.25.0
h12.io/socks v1.0.1 h12.io/socks v1.0.2
) )

26
go.sum
View File

@@ -7,6 +7,7 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -37,6 +38,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -134,8 +137,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/seiflotfy/cuckoofilter v0.0.0-20201009151232-afb285a456ab h1:O43uBnD2Y6fo1oFsXY+Vqp1n3RFfxg1u3XATDGvUXgI= github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c h1:pqy40B3MQWYrza7YZXOXgl0Nf0QGFqrOC0BKae1UNAA=
github.com/seiflotfy/cuckoofilter v0.0.0-20201009151232-afb285a456ab/go.mod h1:ET5mVvNjwaGXRgZxO9UZr7X+8eAf87AfIYNwRSp9s4Y= github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
@@ -184,8 +187,8 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 h1:sYNJzB4J8toYPQTM6pAkcmBRgw9SnQKP9oXCHfgy604= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -206,8 +209,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 h1:lwlPPsmjDKK0J6eG6xDWd5XPehI0R024zxjDnw3esPA= golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -238,8 +241,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201211002650-1f0c578a6b29 h1:hAYi5mzhvBeCfkgaIHGZ8R+Q04WjSW5ZvQO3BZ94dHY= golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo=
golang.org/x/sys v0.0.0-20201211002650-1f0c578a6b29/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -310,11 +313,12 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
h12.io/socks v1.0.1 h1:bXESSI/+hbdrp+22vcc7/JiXjmLH4UWktKdYgGr3ShA= h12.io/socks v1.0.2 h1:cZhhbV8+DE0Y1kotwhr1a3RC3kFO7AtuZ4GLr3qKSc8=
h12.io/socks v1.0.1/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck= h12.io/socks v1.0.2/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -84,7 +84,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
geoipList, err := toCidrList(c.ExpectIPs) geoipList, err := toCidrList(c.ExpectIPs)
if err != nil { if err != nil {
return nil, newError("invalid ip rule: ", c.ExpectIPs).Base(err) return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err)
} }
return &dns.NameServer{ return &dns.NameServer{
@@ -159,15 +159,23 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
var mappings []*dns.Config_HostMapping var mappings []*dns.Config_HostMapping
switch { switch {
case strings.HasPrefix(domain, "domain:"): case strings.HasPrefix(domain, "domain:"):
domainName := domain[7:]
if len(domainName) == 0 {
return nil, newError("empty domain type of rule: ", domain)
}
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Subdomain mapping.Type = dns.DomainMatchingType_Subdomain
mapping.Domain = domain[7:] mapping.Domain = domainName
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "geosite:"): case strings.HasPrefix(domain, "geosite:"):
domains, err := loadGeositeWithAttr("geosite.dat", strings.ToUpper(domain[8:])) listName := domain[8:]
if len(listName) == 0 {
return nil, newError("empty geosite rule: ", domain)
}
domains, err := loadGeositeWithAttr("geosite.dat", listName)
if err != nil { if err != nil {
return nil, newError("invalid geosite settings: ", domain).Base(err) return nil, newError("failed to load geosite: ", listName).Base(err)
} }
for _, d := range domains { for _, d := range domains {
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
@@ -177,21 +185,33 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
} }
case strings.HasPrefix(domain, "regexp:"): case strings.HasPrefix(domain, "regexp:"):
regexpVal := domain[7:]
if len(regexpVal) == 0 {
return nil, newError("empty regexp type of rule: ", domain)
}
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Regex mapping.Type = dns.DomainMatchingType_Regex
mapping.Domain = domain[7:] mapping.Domain = regexpVal
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "keyword:"): case strings.HasPrefix(domain, "keyword:"):
keywordVal := domain[8:]
if len(keywordVal) == 0 {
return nil, newError("empty keyword type of rule: ", domain)
}
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Keyword mapping.Type = dns.DomainMatchingType_Keyword
mapping.Domain = domain[8:] mapping.Domain = keywordVal
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "full:"): case strings.HasPrefix(domain, "full:"):
fullVal := domain[5:]
if len(fullVal) == 0 {
return nil, newError("empty full domain type of rule: ", domain)
}
mapping := getHostMapping(addr) mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Full mapping.Type = dns.DomainMatchingType_Full
mapping.Domain = domain[5:] mapping.Domain = fullVal
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "dotless:"): case strings.HasPrefix(domain, "dotless:"):
@@ -213,10 +233,10 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
return nil, newError("invalid external resource: ", domain) return nil, newError("invalid external resource: ", domain)
} }
filename := kv[0] filename := kv[0]
country := kv[1] list := kv[1]
domains, err := loadGeositeWithAttr(filename, country) domains, err := loadGeositeWithAttr(filename, list)
if err != nil { if err != nil {
return nil, newError("failed to load domains: ", country, " from ", filename).Base(err) return nil, newError("failed to load domain list: ", list, " from ", filename).Base(err)
} }
for _, d := range domains { for _, d := range domains {
mapping := getHostMapping(addr) mapping := getHostMapping(addr)

View File

@@ -2,6 +2,7 @@ package conf
import ( import (
"encoding/json" "encoding/json"
"runtime"
"strconv" "strconv"
"strings" "strings"
@@ -147,46 +148,109 @@ func ParseIP(s string) (*router.CIDR, error) {
} }
} }
func loadGeoIP(country string) ([]*router.CIDR, error) { func loadGeoIP(code string) ([]*router.CIDR, error) {
return loadIP("geoip.dat", country) return loadIP("geoip.dat", code)
} }
func loadIP(filename, country string) ([]*router.CIDR, error) { var (
geoipBytes, err := filesystem.ReadAsset(filename) FileCache = make(map[string][]byte)
IPCache = make(map[string]*router.GeoIP)
SiteCache = make(map[string]*router.GeoSite)
)
func loadFile(file string) ([]byte, error) {
if FileCache[file] == nil {
bs, err := filesystem.ReadAsset(file)
if err != nil { if err != nil {
return nil, newError("failed to open file: ", filename).Base(err) return nil, newError("failed to open file: ", file).Base(err)
} }
var geoipList router.GeoIPList if len(bs) == 0 {
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil { return nil, newError("empty file: ", file)
return nil, err }
// Do not cache file, may save RAM when there
// are many files, but consume CPU each time.
return bs, nil
FileCache[file] = bs
}
return FileCache[file], nil
} }
for _, geoip := range geoipList.Entry { func loadIP(file, code string) ([]*router.CIDR, error) {
if geoip.CountryCode == country { index := file + ":" + code
return geoip.Cidr, nil if IPCache[index] == nil {
} bs, err := loadFile(file)
}
return nil, newError("country not found in ", filename, ": ", country)
}
func loadSite(filename, country string) ([]*router.Domain, error) {
geositeBytes, err := filesystem.ReadAsset(filename)
if err != nil { if err != nil {
return nil, newError("failed to open file: ", filename).Base(err) return nil, newError("failed to load file: ", file).Base(err)
} }
var geositeList router.GeoSiteList bs = find(bs, []byte(code))
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil { if bs == nil {
return nil, err return nil, newError("code not found in ", file, ": ", code)
}
var geoip router.GeoIP
if err := proto.Unmarshal(bs, &geoip); err != nil {
return nil, newError("error unmarshal IP in ", file, ": ", code).Base(err)
}
defer runtime.GC() // or debug.FreeOSMemory()
return geoip.Cidr, nil // do not cache geoip
IPCache[index] = &geoip
}
return IPCache[index].Cidr, nil
} }
for _, site := range geositeList.Entry { func loadSite(file, code string) ([]*router.Domain, error) {
if site.CountryCode == country { index := file + ":" + code
return site.Domain, nil if SiteCache[index] == nil {
bs, err := loadFile(file)
if err != nil {
return nil, newError("failed to load file: ", file).Base(err)
} }
bs = find(bs, []byte(code))
if bs == nil {
return nil, newError("list not found in ", file, ": ", code)
}
var geosite router.GeoSite
if err := proto.Unmarshal(bs, &geosite); err != nil {
return nil, newError("error unmarshal Site in ", file, ": ", code).Base(err)
}
defer runtime.GC() // or debug.FreeOSMemory()
return geosite.Domain, nil // do not cache geosite
SiteCache[index] = &geosite
}
return SiteCache[index].Domain, nil
} }
return nil, newError("list not found in ", filename, ": ", country) func find(data, code []byte) []byte {
codeL := len(code)
if codeL == 0 {
return nil
}
for {
dataL := len(data)
if dataL < 2 {
return nil
}
x, y := proto.DecodeVarint(data[1:])
if x == 0 && y == 0 {
return nil
}
headL, bodyL := 1+y, int(x)
dataL -= headL
if dataL < bodyL {
return nil
}
data = data[headL:]
if int(data[1]) == codeL {
for i := 0; i < codeL && data[2+i] == code[i]; i++ {
if i+1 == codeL {
return data[:bodyL]
}
}
}
if dataL == bodyL {
return nil
}
data = data[bodyL:]
}
} }
type AttributeMatcher interface { type AttributeMatcher interface {

View File

@@ -4,6 +4,10 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"io" "io"
"io/ioutil"
"github.com/BurntSushi/toml"
"github.com/ghodss/yaml"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
@@ -80,3 +84,68 @@ func LoadJSONConfig(reader io.Reader) (*core.Config, error) {
return pbConfig, nil return pbConfig, nil
} }
// DecodeTOMLConfig reads from reader and decode the config into *conf.Config
// using github.com/BurntSushi/toml and map to convert toml to json.
func DecodeTOMLConfig(reader io.Reader) (*conf.Config, error) {
tomlFile, err := ioutil.ReadAll(reader)
if err != nil {
return nil, newError("failed to read config file").Base(err)
}
configMap := make(map[string]interface{})
if _, err := toml.Decode(string(tomlFile), &configMap); err != nil {
return nil, newError("failed to convert toml to map").Base(err)
}
jsonFile, err := json.Marshal(&configMap)
if err != nil {
return nil, newError("failed to convert map to json").Base(err)
}
return DecodeJSONConfig(bytes.NewReader(jsonFile))
}
func LoadTOMLConfig(reader io.Reader) (*core.Config, error) {
tomlConfig, err := DecodeTOMLConfig(reader)
if err != nil {
return nil, err
}
pbConfig, err := tomlConfig.Build()
if err != nil {
return nil, newError("failed to parse toml config").Base(err)
}
return pbConfig, nil
}
// DecodeYAMLConfig reads from reader and decode the config into *conf.Config
// using github.com/ghodss/yaml to convert yaml to json.
func DecodeYAMLConfig(reader io.Reader) (*conf.Config, error) {
yamlFile, err := ioutil.ReadAll(reader)
if err != nil {
return nil, newError("failed to read config file").Base(err)
}
jsonFile, err := yaml.YAMLToJSON(yamlFile)
if err != nil {
return nil, newError("failed to convert yaml to json").Base(err)
}
return DecodeJSONConfig(bytes.NewReader(jsonFile))
}
func LoadYAMLConfig(reader io.Reader) (*core.Config, error) {
yamlConfig, err := DecodeYAMLConfig(reader)
if err != nil {
return nil, err
}
pbConfig, err := yamlConfig.Build()
if err != nil {
return nil, newError("failed to parse yaml config").Base(err)
}
return pbConfig, nil
}

View File

@@ -252,6 +252,7 @@ type TLSCertConfig struct {
KeyFile string `json:"keyFile"` KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"` KeyStr []string `json:"key"`
Usage string `json:"usage"` Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -283,17 +284,22 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
certificate.Usage = tls.Certificate_ENCIPHERMENT certificate.Usage = tls.Certificate_ENCIPHERMENT
} }
certificate.OcspStapling = c.OcspStapling
return certificate, nil return certificate, nil
} }
type TLSConfig struct { type TLSConfig struct {
Insecure bool `json:"allowInsecure"` Insecure bool `json:"allowInsecure"`
InsecureCiphers bool `json:"allowInsecureCiphers"`
Certs []*TLSCertConfig `json:"certificates"` Certs []*TLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"` ServerName string `json:"serverName"`
ALPN *StringList `json:"alpn"` ALPN *StringList `json:"alpn"`
DisableSessionResumption bool `json:"disableSessionResumption"` DisableSessionResumption bool `json:"disableSessionResumption"`
DisableSystemRoot bool `json:"disableSystemRoot"` DisableSystemRoot bool `json:"disableSystemRoot"`
MinVersion string `json:"minVersion"`
MaxVersion string `json:"maxVersion"`
CipherSuites string `json:"cipherSuites"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -309,7 +315,6 @@ func (c *TLSConfig) Build() (proto.Message, error) {
} }
serverName := c.ServerName serverName := c.ServerName
config.AllowInsecure = c.Insecure config.AllowInsecure = c.Insecure
config.AllowInsecureCiphers = c.InsecureCiphers
if len(c.ServerName) > 0 { if len(c.ServerName) > 0 {
config.ServerName = serverName config.ServerName = serverName
} }
@@ -318,6 +323,10 @@ func (c *TLSConfig) Build() (proto.Message, error) {
} }
config.DisableSessionResumption = c.DisableSessionResumption config.DisableSessionResumption = c.DisableSessionResumption
config.DisableSystemRoot = c.DisableSystemRoot config.DisableSystemRoot = c.DisableSystemRoot
config.MinVersion = c.MinVersion
config.MaxVersion = c.MaxVersion
config.CipherSuites = c.CipherSuites
config.PreferServerCipherSuites = c.PreferServerCipherSuites
return config, nil return config, nil
} }
@@ -327,6 +336,7 @@ type XTLSCertConfig struct {
KeyFile string `json:"keyFile"` KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"` KeyStr []string `json:"key"`
Usage string `json:"usage"` Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -358,17 +368,22 @@ func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
certificate.Usage = xtls.Certificate_ENCIPHERMENT certificate.Usage = xtls.Certificate_ENCIPHERMENT
} }
certificate.OcspStapling = c.OcspStapling
return certificate, nil return certificate, nil
} }
type XTLSConfig struct { type XTLSConfig struct {
Insecure bool `json:"allowInsecure"` Insecure bool `json:"allowInsecure"`
InsecureCiphers bool `json:"allowInsecureCiphers"`
Certs []*XTLSCertConfig `json:"certificates"` Certs []*XTLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"` ServerName string `json:"serverName"`
ALPN *StringList `json:"alpn"` ALPN *StringList `json:"alpn"`
DisableSessionResumption bool `json:"disableSessionResumption"` DisableSessionResumption bool `json:"disableSessionResumption"`
DisableSystemRoot bool `json:"disableSystemRoot"` DisableSystemRoot bool `json:"disableSystemRoot"`
MinVersion string `json:"minVersion"`
MaxVersion string `json:"maxVersion"`
CipherSuites string `json:"cipherSuites"`
PreferServerCipherSuites bool `json:"preferServerCipherSuites"`
} }
// Build implements Buildable. // Build implements Buildable.
@@ -384,7 +399,6 @@ func (c *XTLSConfig) Build() (proto.Message, error) {
} }
serverName := c.ServerName serverName := c.ServerName
config.AllowInsecure = c.Insecure config.AllowInsecure = c.Insecure
config.AllowInsecureCiphers = c.InsecureCiphers
if len(c.ServerName) > 0 { if len(c.ServerName) > 0 {
config.ServerName = serverName config.ServerName = serverName
} }
@@ -393,6 +407,10 @@ func (c *XTLSConfig) Build() (proto.Message, error) {
} }
config.DisableSessionResumption = c.DisableSessionResumption config.DisableSessionResumption = c.DisableSessionResumption
config.DisableSystemRoot = c.DisableSystemRoot config.DisableSystemRoot = c.DisableSystemRoot
config.MinVersion = c.MinVersion
config.MaxVersion = c.MaxVersion
config.CipherSuites = c.CipherSuites
config.PreferServerCipherSuites = c.PreferServerCipherSuites
return config, nil return config, nil
} }

View File

@@ -52,6 +52,17 @@ func (c *TrojanClientConfig) Build() (proto.Message, error) {
Password: rec.Password, Password: rec.Password,
Flow: rec.Flow, Flow: rec.Flow,
} }
switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443":
case "xtls-rprx-splice", "xtls-rprx-splice-udp443":
if runtime.GOOS != "linux" && runtime.GOOS != "android" {
return nil, newError(`Trojan servers: "` + account.Flow + `" only support linux in this version`)
}
default:
return nil, newError(`Trojan servers: "flow" doesn't support "` + account.Flow + `" in this version`)
}
trojan := &protocol.ServerEndpoint{ trojan := &protocol.ServerEndpoint{
Address: rec.Address.Build(), Address: rec.Address.Build(),
Port: uint32(rec.Port), Port: uint32(rec.Port),
@@ -107,6 +118,14 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
Flow: rawUser.Flow, Flow: rawUser.Flow,
} }
switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-direct":
case "xtls-rprx-splice":
return nil, newError(`Trojan clients: inbound doesn't support "xtls-rprx-splice" in this version, please use "xtls-rprx-direct" instead`)
default:
return nil, newError(`Trojan clients: "flow" doesn't support "` + account.Flow + `" in this version`)
}
user.Email = rawUser.Email user.Email = rawUser.Email
user.Level = uint32(rawUser.Level) user.Level = uint32(rawUser.Level)
user.Account = serial.ToTypedMessage(account) user.Account = serial.ToTypedMessage(account)
@@ -148,7 +167,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
switch fb.Dest[0] { switch fb.Dest[0] {
case '@', '/': case '@', '/':
fb.Type = "unix" fb.Type = "unix"
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == "linux" { if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, fb.Dest[1:]) copy(fullAddr, fb.Dest[1:])
fb.Dest = string(fullAddr) fb.Dest = string(fullAddr)

View File

@@ -101,7 +101,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
switch fb.Dest[0] { switch fb.Dest[0] {
case '@', '/': case '@', '/':
fb.Type = "unix" fb.Type = "unix"
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == "linux" { if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, fb.Dest[1:]) copy(fullAddr, fb.Dest[1:])
fb.Dest = string(fullAddr) fb.Dest = string(fullAddr)

View File

@@ -57,15 +57,14 @@ import (
_ "github.com/xtls/xray-core/transport/internet/headers/wechat" _ "github.com/xtls/xray-core/transport/internet/headers/wechat"
_ "github.com/xtls/xray-core/transport/internet/headers/wireguard" _ "github.com/xtls/xray-core/transport/internet/headers/wireguard"
// JSON config support. Choose only one from the two below. // JSON & TOML & YAML
// The following line loads JSON from xctl _ "github.com/xtls/xray-core/main/json"
// _ "github.com/xtls/xray-core/main/json" _ "github.com/xtls/xray-core/main/toml"
// The following line loads JSON internally _ "github.com/xtls/xray-core/main/yaml"
_ "github.com/xtls/xray-core/main/jsonem"
// Load config from file or http(s) // Load config from file or http(s)
_ "github.com/xtls/xray-core/main/confloader/external" _ "github.com/xtls/xray-core/main/confloader/external"
// commands // Commands
_ "github.com/xtls/xray-core/main/commands/all" _ "github.com/xtls/xray-core/main/commands/all"
) )

View File

@@ -1,38 +0,0 @@
package json
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
import (
"io"
"os"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/cmdarg"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/main/confloader"
)
func init() {
common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
Name: "JSON",
Extension: []string{"json"},
Loader: func(input interface{}) (*core.Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
r, err := confloader.LoadExtConfig(v, os.Stdin)
if err != nil {
return nil, newError("failed to execute xctl to convert config file.").Base(err).AtWarning()
}
return core.LoadConfig("protobuf", "", r)
case io.Reader:
r, err := confloader.LoadExtConfig([]string{"stdin:"}, os.Stdin)
if err != nil {
return nil, newError("failed to execute xctl to convert config file.").Base(err).AtWarning()
}
return core.LoadConfig("protobuf", "", r)
default:
return nil, newError("unknown type")
}
},
}))
}

View File

@@ -1,4 +1,4 @@
package jsonem package json
import ( import (
"io" "io"
@@ -22,9 +22,13 @@ func init() {
for i, arg := range v { for i, arg := range v {
newError("Reading config: ", arg).AtInfo().WriteToLog() newError("Reading config: ", arg).AtInfo().WriteToLog()
r, err := confloader.LoadConfig(arg) r, err := confloader.LoadConfig(arg)
common.Must(err) if err != nil {
return nil, newError("failed to read config: ", arg).Base(err)
}
c, err := serial.DecodeJSONConfig(r) c, err := serial.DecodeJSONConfig(r)
common.Must(err) if err != nil {
return nil, newError("failed to decode config: ", arg).Base(err)
}
if i == 0 { if i == 0 {
// This ensure even if the muti-json parser do not support a setting, // This ensure even if the muti-json parser do not support a setting,
// It is still respected automatically for the first configure file // It is still respected automatically for the first configure file

View File

@@ -9,12 +9,14 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"runtime/debug"
"strings" "strings"
"syscall" "syscall"
"github.com/xtls/xray-core/common/cmdarg" "github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/main/commands/base" "github.com/xtls/xray-core/main/commands/base"
) )
@@ -64,22 +66,29 @@ func executeRun(cmd *base.Command, args []string) {
printVersion() printVersion()
server, err := startXray() server, err := startXray()
if err != nil { if err != nil {
base.Fatalf("Failed to start: %s", err) fmt.Println("Failed to start:", err)
// Configuration error. Exit with a special value to prevent systemd from restarting.
os.Exit(23)
} }
if *test { if *test {
fmt.Println("Configuration OK.") fmt.Println("Configuration OK.")
base.SetExitStatus(0) os.Exit(0)
base.Exit()
} }
if err := server.Start(); err != nil { if err := server.Start(); err != nil {
base.Fatalf("Failed to start: %s", err) fmt.Println("Failed to start:", err)
os.Exit(-1)
} }
defer server.Close() defer server.Close()
conf.FileCache = nil
conf.IPCache = nil
conf.SiteCache = nil
// Explicitly triggering GC to remove garbage from config loading. // Explicitly triggering GC to remove garbage from config loading.
runtime.GC() runtime.GC()
debug.FreeOSMemory()
{ {
osSignals := make(chan os.Signal, 1) osSignals := make(chan os.Signal, 1)
@@ -147,6 +156,10 @@ func getConfigFormat() string {
switch strings.ToLower(*format) { switch strings.ToLower(*format) {
case "pb", "protobuf": case "pb", "protobuf":
return "protobuf" return "protobuf"
case "yaml", "yml":
return "yaml"
case "toml":
return "toml"
default: default:
return "json" return "json"
} }
@@ -156,8 +169,11 @@ func startXray() (core.Server, error) {
configFiles := getConfigFilePath() configFiles := getConfigFilePath()
config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles) config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
//config, err := core.LoadConfigs(getConfigFormat(), configFiles)
if err != nil { if err != nil {
return nil, newError("failed to read config files: [", configFiles.String(), "]").Base(err) return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err)
} }
server, err := core.New(config) server, err := core.New(config)

View File

@@ -0,0 +1,9 @@
package toml
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

48
main/toml/toml.go Normal file
View File

@@ -0,0 +1,48 @@
package toml
import (
"io"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/infra/conf/serial"
"github.com/xtls/xray-core/main/confloader"
)
func init() {
common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
Name: "TOML",
Extension: []string{"toml"},
Loader: func(input interface{}) (*core.Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
cf := &conf.Config{}
for i, arg := range v {
newError("Reading config: ", arg).AtInfo().WriteToLog()
r, err := confloader.LoadConfig(arg)
if err != nil {
return nil, newError("failed to read config: ", arg).Base(err)
}
c, err := serial.DecodeTOMLConfig(r)
if err != nil {
return nil, newError("failed to decode config: ", arg).Base(err)
}
if i == 0 {
// This ensure even if the muti-json parser do not support a setting,
// It is still respected automatically for the first configure file
*cf = *c
continue
}
cf.Override(c, arg)
}
return cf.Build()
case io.Reader:
return serial.LoadTOMLConfig(v)
default:
return nil, newError("unknow type")
}
},
}))
}

View File

@@ -0,0 +1,9 @@
package yaml
import "github.com/xtls/xray-core/common/errors"
type errPathObjHolder struct{}
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).WithPathObj(errPathObjHolder{})
}

48
main/yaml/yaml.go Normal file
View File

@@ -0,0 +1,48 @@
package yaml
import (
"io"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/infra/conf/serial"
"github.com/xtls/xray-core/main/confloader"
)
func init() {
common.Must(core.RegisterConfigLoader(&core.ConfigFormat{
Name: "YAML",
Extension: []string{"yaml", "yml"},
Loader: func(input interface{}) (*core.Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
cf := &conf.Config{}
for i, arg := range v {
newError("Reading config: ", arg).AtInfo().WriteToLog()
r, err := confloader.LoadConfig(arg)
if err != nil {
return nil, newError("failed to read config: ", arg).Base(err)
}
c, err := serial.DecodeYAMLConfig(r)
if err != nil {
return nil, newError("failed to decode config: ", arg).Base(err)
}
if i == 0 {
// This ensure even if the muti-json parser do not support a setting,
// It is still respected automatically for the first configure file
*cf = *c
continue
}
cf.Override(c, arg)
}
return cf.Build()
case io.Reader:
return serial.LoadYAMLConfig(v)
default:
return nil, newError("unknow type")
}
},
}))
}

View File

@@ -17,6 +17,7 @@ import (
"github.com/xtls/xray-core/core" "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/dns" "github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/policy" "github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/stats"
"github.com/xtls/xray-core/transport" "github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
) )
@@ -148,7 +149,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if destination.Network == net.Network_TCP { if destination.Network == net.Network_TCP {
writer = buf.NewWriter(conn) writer = buf.NewWriter(conn)
} else { } else {
writer = &buf.SequentialWriter{Writer: conn} writer = NewPacketWriter(conn)
} }
if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {
@@ -165,7 +166,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if destination.Network == net.Network_TCP { if destination.Network == net.Network_TCP {
reader = buf.NewReader(conn) reader = buf.NewReader(conn)
} else { } else {
reader = buf.NewPacketReader(conn) reader = NewPacketReader(conn)
} }
if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
return newError("failed to process response").Base(err) return newError("failed to process response").Base(err)
@@ -180,3 +181,93 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return nil return nil
} }
func NewPacketReader(conn net.Conn) buf.Reader {
iConn := conn
statConn, ok := iConn.(*internet.StatCouterConnection)
if ok {
iConn = statConn.Connection
}
var counter stats.Counter
if statConn != nil {
counter = statConn.ReadCounter
}
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
return &PacketReader{
PacketConnWrapper: c,
Counter: counter,
}
}
return &buf.PacketReader{Reader: conn}
}
type PacketReader struct {
*internet.PacketConnWrapper
stats.Counter
}
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
b := buf.New()
b.Resize(0, buf.Size)
n, d, err := r.PacketConnWrapper.ReadFrom(b.Bytes())
if err != nil {
b.Release()
return nil, err
}
b.Resize(0, int32(n))
b.UDP = d.(*net.UDPAddr)
if r.Counter != nil {
r.Counter.Add(int64(n))
}
return buf.MultiBuffer{b}, nil
}
func NewPacketWriter(conn net.Conn) buf.Writer {
iConn := conn
statConn, ok := iConn.(*internet.StatCouterConnection)
if ok {
iConn = statConn.Connection
}
var counter stats.Counter
if statConn != nil {
counter = statConn.WriteCounter
}
if c, ok := iConn.(*internet.PacketConnWrapper); ok {
return &PacketWriter{
PacketConnWrapper: c,
Counter: counter,
}
}
return &buf.SequentialWriter{Writer: conn}
}
type PacketWriter struct {
*internet.PacketConnWrapper
stats.Counter
}
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
for {
mb2, b := buf.SplitFirst(mb)
mb = mb2
if b == nil {
break
}
var n int
var err error
if b.UDP != nil {
n, err = w.PacketConnWrapper.WriteTo(b.Bytes(), b.UDP)
} else {
n, err = w.PacketConnWrapper.Write(b.Bytes())
}
b.Release()
if err != nil {
buf.ReleaseMulti(mb)
return err
}
if w.Counter != nil {
w.Counter.Add(int64(n))
}
}
return nil
}

View File

@@ -168,6 +168,7 @@ func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, u
rawConn.Close() rawConn.Close()
return nil, err return nil, err
} }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
rawConn.Close() rawConn.Close()

View File

@@ -293,6 +293,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
response.Close = true response.Close = true
result = nil result = nil
} }
defer response.Body.Close()
} else { } else {
newError("failed to read response from ", request.Host).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx)) newError("failed to read response from ", request.Host).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
response = &http.Response{ response = &http.Response{

View File

@@ -134,14 +134,15 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
} }
if request.Command == protocol.RequestCommandUDP { if request.Command == protocol.RequestCommandUDP {
writer := &buf.SequentialWriter{Writer: &UDPWriter{
Writer: conn,
Request: request,
}}
requestDone := func() error { requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
writer := &UDPWriter{
Writer: conn,
Request: request,
}
if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all UDP request").Base(err) return newError("failed to transport all UDP request").Base(err)
} }

View File

@@ -230,11 +230,15 @@ func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer.Release() buffer.Release()
return nil, err return nil, err
} }
_, payload, err := DecodeUDPPacket(v.User, buffer) u, payload, err := DecodeUDPPacket(v.User, buffer)
if err != nil { if err != nil {
buffer.Release() buffer.Release()
return nil, err return nil, err
} }
payload.UDP = &net.UDPAddr{
IP: u.Address.IP(),
Port: int(u.Port),
}
return buf.MultiBuffer{payload}, nil return buf.MultiBuffer{payload}, nil
} }
@@ -243,13 +247,36 @@ type UDPWriter struct {
Request *protocol.RequestHeader Request *protocol.RequestHeader
} }
// Write implements io.Writer. func (w *UDPWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
func (w *UDPWriter) Write(payload []byte) (int, error) { for {
packet, err := EncodeUDPPacket(w.Request, payload) mb2, b := buf.SplitFirst(mb)
mb = mb2
if b == nil {
break
}
var packet *buf.Buffer
var err error
if b.UDP != nil {
request := &protocol.RequestHeader{
User: w.Request.User,
Address: net.IPAddress(b.UDP.IP),
Port: net.Port(b.UDP.Port),
}
packet, err = EncodeUDPPacket(request, b.Bytes())
} else {
packet, err = EncodeUDPPacket(w.Request, b.Bytes())
}
b.Release()
if err != nil { if err != nil {
return 0, err buf.ReleaseMulti(mb)
return err
} }
_, err = w.Writer.Write(packet.Bytes()) _, err = w.Writer.Write(packet.Bytes())
packet.Release() packet.Release()
return len(payload), err if err != nil {
buf.ReleaseMulti(mb)
return err
}
}
return nil
} }

View File

@@ -145,7 +145,7 @@ func TestUDPReaderWriter(t *testing.T) {
cache := buf.New() cache := buf.New()
defer cache.Release() defer cache.Release()
writer := &buf.SequentialWriter{Writer: &UDPWriter{ writer := &UDPWriter{
Writer: cache, Writer: cache,
Request: &protocol.RequestHeader{ Request: &protocol.RequestHeader{
Version: Version, Version: Version,
@@ -153,7 +153,7 @@ func TestUDPReaderWriter(t *testing.T) {
Port: 123, Port: 123,
User: user, User: user,
}, },
}} }
reader := &UDPReader{ reader := &UDPReader{
Reader: cache, Reader: cache,

View File

@@ -77,6 +77,15 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
} }
payload := packet.Payload payload := packet.Payload
if payload.UDP != nil {
request = &protocol.RequestHeader{
User: request.User,
Address: net.IPAddress(payload.UDP.IP),
Port: net.Port(payload.UDP.Port),
}
}
data, err := EncodeUDPPacket(request, payload.Bytes()) data, err := EncodeUDPPacket(request, payload.Bytes())
payload.Release() payload.Release()
if err != nil { if err != nil {
@@ -94,6 +103,8 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
} }
inbound.User = s.user inbound.User = s.user
var dest net.Destination
reader := buf.NewPacketReader(conn) reader := buf.NewPacketReader(conn)
for { for {
mpayload, err := reader.ReadMultiBuffer() mpayload, err := reader.ReadMultiBuffer()
@@ -118,17 +129,25 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
} }
currentPacketCtx := ctx currentPacketCtx := ctx
dest := request.Destination()
if inbound.Source.IsValid() { if inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source, From: inbound.Source,
To: dest, To: request.Destination(),
Status: log.AccessAccepted, Status: log.AccessAccepted,
Reason: "", Reason: "",
Email: request.User.Email, Email: request.User.Email,
}) })
} }
newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(currentPacketCtx)) newError("tunnelling request to ", request.Destination()).WriteToLog(session.ExportIDToError(currentPacketCtx))
data.UDP = &net.UDPAddr{
IP: request.Address.IP(),
Port: int(request.Port),
}
if dest.Network == 0 {
dest = request.Destination() // JUST FOLLOW THE FIREST PACKET
}
currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request) currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)
udpServer.Dispatch(currentPacketCtx, dest, data) udpServer.Dispatch(currentPacketCtx, dest, data)

View File

@@ -51,14 +51,19 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
if outbound == nil || !outbound.Target.IsValid() { if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified.") return newError("target not specified.")
} }
// Destination of the inner request.
destination := outbound.Target destination := outbound.Target
// Outbound server.
var server *protocol.ServerSpec var server *protocol.ServerSpec
// Outbound server's destination.
var dest net.Destination
// Connection to the outbound server.
var conn internet.Connection var conn internet.Connection
if err := retry.ExponentialBackoff(5, 100).On(func() error { if err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer() server = c.serverPicker.PickServer()
dest := server.Destination() dest = server.Destination()
rawConn, err := dialer.Dial(ctx, dest) rawConn, err := dialer.Dial(ctx, dest)
if err != nil { if err != nil {
return err return err
@@ -101,6 +106,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
if err != nil { if err != nil {
return newError("failed to establish connection to server").AtWarning().Base(err) return newError("failed to establish connection to server").AtWarning().Base(err)
} }
if udpRequest != nil {
if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
udpRequest.Address = dest.Address
}
}
if err := conn.SetDeadline(time.Time{}); err != nil { if err := conn.SetDeadline(time.Time{}); err != nil {
newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))

View File

@@ -16,7 +16,7 @@ const (
cmdTCPConnect = 0x01 cmdTCPConnect = 0x01
cmdTCPBind = 0x02 cmdTCPBind = 0x02
cmdUDPPort = 0x03 cmdUDPAssociate = 0x03
cmdTorResolve = 0xF0 cmdTorResolve = 0xF0
cmdTorResolvePTR = 0xF1 cmdTorResolvePTR = 0xF1
@@ -40,7 +40,9 @@ var addrParser = protocol.NewAddressParser(
type ServerSession struct { type ServerSession struct {
config *ServerConfig config *ServerConfig
address net.Address
port net.Port port net.Port
clientAddress net.Address
} }
func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
@@ -162,7 +164,7 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR: case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR:
// We don't have a solution for Tor case now. Simply treat it as connect command. // We don't have a solution for Tor case now. Simply treat it as connect command.
request.Command = protocol.RequestCommandTCP request.Command = protocol.RequestCommandTCP
case cmdUDPPort: case cmdUDPAssociate:
if !s.config.UdpEnabled { if !s.config.UdpEnabled {
writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0)) writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
return nil, newError("UDP is not enabled.") return nil, newError("UDP is not enabled.")
@@ -185,15 +187,20 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
request.Address = addr request.Address = addr
request.Port = port request.Port = port
responseAddress := net.AnyIP responseAddress := s.address
responsePort := net.Port(1717) responsePort := s.port
//nolint:gocritic // Use if else chain for clarity
if request.Command == protocol.RequestCommandUDP { if request.Command == protocol.RequestCommandUDP {
addr := s.config.Address.AsAddress() if s.config.Address != nil {
if addr == nil { // Use configured IP as remote address in the response to UdpAssociate
addr = net.LocalHostIP responseAddress = s.config.Address.AsAddress()
} else if s.clientAddress == net.LocalHostIP || s.clientAddress == net.LocalHostIPv6 {
// For localhost clients use loopback IP
responseAddress = s.clientAddress
} else {
// For non-localhost clients use inbound listening address
responseAddress = s.address
} }
responseAddress = addr
responsePort = s.port
} }
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil { if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {
return nil, err return nil, err
@@ -446,7 +453,7 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
command := byte(cmdTCPConnect) command := byte(cmdTCPConnect)
if request.Command == protocol.RequestCommandUDP { if request.Command == protocol.RequestCommandUDP {
command = byte(cmdUDPPort) command = byte(cmdUDPAssociate)
} }
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */})) common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil { if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {

View File

@@ -90,7 +90,9 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
svrSession := &ServerSession{ svrSession := &ServerSession{
config: s.config, config: s.config,
address: inbound.Gateway.Address,
port: inbound.Gateway.Port, port: inbound.Gateway.Port,
clientAddress: inbound.Source.Address,
} }
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)} reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}
@@ -196,6 +198,15 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
if request == nil { if request == nil {
return return
} }
if payload.UDP != nil {
request = &protocol.RequestHeader{
User: request.User,
Address: net.IPAddress(payload.UDP.IP),
Port: net.Port(payload.UDP.Port),
}
}
udpMessage, err := EncodeUDPPacket(request, payload.Bytes()) udpMessage, err := EncodeUDPPacket(request, payload.Bytes())
payload.Release() payload.Release()
@@ -211,6 +222,8 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
newError("client UDP connection from ", inbound.Source).WriteToLog(session.ExportIDToError(ctx)) newError("client UDP connection from ", inbound.Source).WriteToLog(session.ExportIDToError(ctx))
} }
var dest net.Destination
reader := buf.NewPacketReader(conn) reader := buf.NewPacketReader(conn)
for { for {
mpayload, err := reader.ReadMultiBuffer() mpayload, err := reader.ReadMultiBuffer()
@@ -242,8 +255,17 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
}) })
} }
payload.UDP = &net.UDPAddr{
IP: request.Address.IP(),
Port: int(request.Port),
}
if dest.Network == 0 {
dest = request.Destination() // JUST FOLLOW THE FIREST PACKET
}
currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request) currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request)
udpServer.Dispatch(currentPacketCtx, request.Destination(), payload) udpServer.Dispatch(currentPacketCtx, dest, payload)
} }
} }
} }

View File

@@ -79,62 +79,63 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
defer conn.Close() defer conn.Close()
user := server.PickUser()
account, ok := user.Account.(*MemoryAccount)
if !ok {
return newError("user account is not valid")
}
iConn := conn iConn := conn
statConn, ok := iConn.(*internet.StatCouterConnection) statConn, ok := iConn.(*internet.StatCouterConnection)
if ok { if ok {
iConn = statConn.Connection iConn = statConn.Connection
} }
user := server.PickUser()
account, ok := user.Account.(*MemoryAccount)
if !ok {
return newError("user account is not valid")
}
connWriter := &ConnWriter{
Flow: account.Flow,
}
var rawConn syscall.RawConn var rawConn syscall.RawConn
var sctx context.Context var sctx context.Context
connWriter := &ConnWriter{}
allowUDP443 := false allowUDP443 := false
switch account.Flow { switch connWriter.Flow {
case XRO + "-udp443", XRD + "-udp443", XRS + "-udp443": case XRO + "-udp443", XRD + "-udp443", XRS + "-udp443":
allowUDP443 = true allowUDP443 = true
account.Flow = account.Flow[:16] connWriter.Flow = connWriter.Flow[:16]
fallthrough fallthrough
case XRO, XRD, XRS: case XRO, XRD, XRS:
if destination.Address.Family().IsDomain() && destination.Address.Domain() == muxCoolAddress { if destination.Address.Family().IsDomain() && destination.Address.Domain() == muxCoolAddress {
return newError(account.Flow + " doesn't support Mux").AtWarning() return newError(connWriter.Flow + " doesn't support Mux").AtWarning()
} }
if destination.Network == net.Network_UDP { if destination.Network == net.Network_UDP {
if !allowUDP443 && destination.Port == 443 { if !allowUDP443 && destination.Port == 443 {
return newError(account.Flow + " stopped UDP/443").AtInfo() return newError(connWriter.Flow + " stopped UDP/443").AtInfo()
} }
connWriter.Flow = ""
} else { // enable XTLS only if making TCP request } else { // enable XTLS only if making TCP request
if xtlsConn, ok := iConn.(*xtls.Conn); ok { if xtlsConn, ok := iConn.(*xtls.Conn); ok {
xtlsConn.RPRX = true xtlsConn.RPRX = true
xtlsConn.SHOW = trojanXTLSShow xtlsConn.SHOW = xtls_show
xtlsConn.MARK = "XTLS" xtlsConn.MARK = "XTLS"
if account.Flow == XRS { if connWriter.Flow == XRS {
sctx = ctx sctx = ctx
account.Flow = XRD connWriter.Flow = XRD
} }
if account.Flow == XRD { if connWriter.Flow == XRD {
xtlsConn.DirectMode = true xtlsConn.DirectMode = true
if sc, ok := xtlsConn.Connection.(syscall.Conn); ok { if sc, ok := xtlsConn.Connection.(syscall.Conn); ok {
rawConn, _ = sc.SyscallConn() rawConn, _ = sc.SyscallConn()
} }
} }
connWriter.Flow = account.Flow
} else { } else {
return newError(`failed to use ` + account.Flow + `, maybe "security" is not "xtls"`).AtWarning() return newError(`failed to use ` + connWriter.Flow + `, maybe "security" is not "xtls"`).AtWarning()
} }
} }
case "": default:
if _, ok := iConn.(*xtls.Conn); ok { if _, ok := iConn.(*xtls.Conn); ok {
panic(`To avoid misunderstanding, you must fill in Trojan "flow" when using XTLS.`) panic(`To avoid misunderstanding, you must fill in Trojan "flow" when using XTLS.`)
} }
default:
return newError("unsupported flow " + account.Flow).AtWarning()
} }
sessionPolicy := c.policyManager.ForLevel(user.Level) sessionPolicy := c.policyManager.ForLevel(user.Level)
@@ -211,6 +212,6 @@ func init() {
xtlsShow := platform.NewEnvFlag("xray.trojan.xtls.show").GetValue(func() string { return defaultFlagValue }) xtlsShow := platform.NewEnvFlag("xray.trojan.xtls.show").GetValue(func() string { return defaultFlagValue })
if xtlsShow == "true" { if xtlsShow == "true" {
trojanXTLSShow = true xtls_show = true
} }
} }

View File

@@ -28,7 +28,7 @@ var (
protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain), protocol.AddressFamilyByte(0x03, net.AddressFamilyDomain),
) )
trojanXTLSShow = false xtls_show = false
) )
const ( const (
@@ -90,10 +90,10 @@ func (c *ConnWriter) writeHeader() error {
command := commandTCP command := commandTCP
if c.Target.Network == net.Network_UDP { if c.Target.Network == net.Network_UDP {
command = commandUDP command = commandUDP
} else if c.Flow == XRO {
command = commandXRO
} else if c.Flow == XRD { } else if c.Flow == XRD {
command = commandXRD command = commandXRD
} else if c.Flow == XRO {
command = commandXRO
} }
if _, err := buffer.Write(c.Account.Key); err != nil { if _, err := buffer.Write(c.Account.Key); err != nil {
@@ -128,31 +128,43 @@ type PacketWriter struct {
// WriteMultiBuffer implements buf.Writer // WriteMultiBuffer implements buf.Writer
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
b := make([]byte, maxLength) for {
for !mb.IsEmpty() { mb2, b := buf.SplitFirst(mb)
var length int mb = mb2
mb, length = buf.SplitBytes(mb, b) if b == nil {
if _, err := w.writePacket(b[:length], w.Target); err != nil { break
}
target := w.Target
if b.UDP != nil {
target.Address = net.IPAddress(b.UDP.IP)
target.Port = net.Port(b.UDP.Port)
}
if _, err := w.writePacket(b.Bytes(), target); err != nil {
buf.ReleaseMulti(mb) buf.ReleaseMulti(mb)
return err return err
} }
} }
return nil return nil
} }
// WriteMultiBufferWithMetadata writes udp packet with destination specified // WriteMultiBufferWithMetadata writes udp packet with destination specified
func (w *PacketWriter) WriteMultiBufferWithMetadata(mb buf.MultiBuffer, dest net.Destination) error { func (w *PacketWriter) WriteMultiBufferWithMetadata(mb buf.MultiBuffer, dest net.Destination) error {
b := make([]byte, maxLength) for {
for !mb.IsEmpty() { mb2, b := buf.SplitFirst(mb)
var length int mb = mb2
mb, length = buf.SplitBytes(mb, b) if b == nil {
if _, err := w.writePacket(b[:length], dest); err != nil { break
}
source := dest
if b.UDP != nil {
source.Address = net.IPAddress(b.UDP.IP)
source.Port = net.Port(b.UDP.Port)
}
if _, err := w.writePacket(b.Bytes(), source); err != nil {
buf.ReleaseMulti(mb) buf.ReleaseMulti(mb)
return err return err
} }
} }
return nil return nil
} }
@@ -211,10 +223,10 @@ func (c *ConnReader) ParseHeader() error {
network := net.Network_TCP network := net.Network_TCP
if command[0] == commandUDP { if command[0] == commandUDP {
network = net.Network_UDP network = net.Network_UDP
} else if command[0] == commandXRO {
c.Flow = XRO
} else if command[0] == commandXRD { } else if command[0] == commandXRD {
c.Flow = XRD c.Flow = XRD
} else if command[0] == commandXRO {
c.Flow = XRO
} }
addr, port, err := addrParser.ReadAddressPort(nil, c.Reader) addr, port, err := addrParser.ReadAddressPort(nil, c.Reader)
@@ -300,6 +312,10 @@ func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
} }
b := buf.New() b := buf.New()
b.UDP = &net.UDPAddr{
IP: addr.IP(),
Port: int(port.Value()),
}
mb = append(mb, b) mb = append(mb, b)
n, err := b.ReadFullFrom(r, int32(length)) n, err := b.ReadFullFrom(r, int32(length))
if err != nil { if err != nil {
@@ -326,6 +342,9 @@ func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, c
if ok { if ok {
iConn = statConn.Connection iConn = statConn.Connection
} }
if xc, ok := iConn.(*xtls.Conn); ok {
iConn = xc.Connection
}
if tc, ok := iConn.(*net.TCPConn); ok { if tc, ok := iConn.(*net.TCPConn); ok {
if conn.SHOW { if conn.SHOW {
fmt.Println(conn.MARK, "Splice") fmt.Println(conn.MARK, "Splice")

View File

@@ -38,7 +38,7 @@ func init() {
xtlsShow := platform.NewEnvFlag("xray.trojan.xtls.show").GetValue(func() string { return defaultFlagValue }) xtlsShow := platform.NewEnvFlag("xray.trojan.xtls.show").GetValue(func() string { return defaultFlagValue })
if xtlsShow == "true" { if xtlsShow == "true" {
trojanXTLSShow = true xtls_show = true
} }
} }
@@ -219,7 +219,8 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
} }
if xtlsConn, ok := iConn.(*xtls.Conn); ok { if xtlsConn, ok := iConn.(*xtls.Conn); ok {
xtlsConn.RPRX = true xtlsConn.RPRX = true
xtlsConn.SHOW = trojanXTLSShow xtlsConn.SHOW = xtls_show
xtlsConn.MARK = "XTLS"
if clientReader.Flow == XRD { if clientReader.Flow == XRD {
xtlsConn.DirectMode = true xtlsConn.DirectMode = true
if sc, ok := xtlsConn.Connection.(syscall.Conn); ok { if sc, ok := xtlsConn.Connection.(syscall.Conn); ok {
@@ -230,11 +231,9 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
return newError(`failed to use ` + clientReader.Flow + `, maybe "security" is not "xtls"`).AtWarning() return newError(`failed to use ` + clientReader.Flow + `, maybe "security" is not "xtls"`).AtWarning()
} }
} else { } else {
return newError("unable to use ", clientReader.Flow).AtWarning() return newError(account.Password + " is not able to use " + clientReader.Flow).AtWarning()
} }
case "": case "":
default:
return newError("unsupported flow " + account.Flow).AtWarning()
} }
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
@@ -257,6 +256,8 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
user := inbound.User user := inbound.User
var dest net.Destination
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@@ -279,8 +280,12 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
}) })
newError("tunnelling request to ", p.Target).WriteToLog(session.ExportIDToError(ctx)) newError("tunnelling request to ", p.Target).WriteToLog(session.ExportIDToError(ctx))
if dest.Network == 0 {
dest = p.Target // JUST FOLLOW THE FIREST PACKET
}
for _, b := range p.Buffer { for _, b := range p.Buffer {
udpServer.Dispatch(ctx, p.Target, b) udpServer.Dispatch(ctx, dest, b)
} }
} }
} }

View File

@@ -189,6 +189,9 @@ func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, c
if ok { if ok {
iConn = statConn.Connection iConn = statConn.Connection
} }
if xc, ok := iConn.(*xtls.Conn); ok {
iConn = xc.Connection
}
if tc, ok := iConn.(*net.TCPConn); ok { if tc, ok := iConn.(*net.TCPConn); ok {
if conn.SHOW { if conn.SHOW {
fmt.Println(conn.MARK, "Splice") fmt.Println(conn.MARK, "Splice")

View File

@@ -57,14 +57,14 @@ func TestRequestSerialization(t *testing.T) {
defer common.Close(userValidator) defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory) server := NewServerSession(userValidator, sessionHistory)
actualRequest, err := server.DecodeRequestHeader(buffer) actualRequest, err := server.DecodeRequestHeader(buffer, false)
common.Must(err) common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" { if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {
t.Error(r) t.Error(r)
} }
_, err = server.DecodeRequestHeader(buffer2) _, err = server.DecodeRequestHeader(buffer2, false)
// anti replay attack // anti replay attack
if err == nil { if err == nil {
t.Error("nil error") t.Error("nil error")
@@ -107,7 +107,7 @@ func TestInvalidRequest(t *testing.T) {
defer common.Close(userValidator) defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory) server := NewServerSession(userValidator, sessionHistory)
_, err := server.DecodeRequestHeader(buffer) _, err := server.DecodeRequestHeader(buffer, false)
if err == nil { if err == nil {
t.Error("nil error") t.Error("nil error")
} }
@@ -148,7 +148,7 @@ func TestMuxRequest(t *testing.T) {
defer common.Close(userValidator) defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory) server := NewServerSession(userValidator, sessionHistory)
actualRequest, err := server.DecodeRequestHeader(buffer) actualRequest, err := server.DecodeRequestHeader(buffer, false)
common.Must(err) common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" { if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {

View File

@@ -131,7 +131,7 @@ func parseSecurityType(b byte) protocol.SecurityType {
} }
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream. // DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) { func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*protocol.RequestHeader, error) {
buffer := buf.New() buffer := buf.New()
behaviorRand := dice.NewDeterministicDice(int64(s.userValidator.GetBehaviorSeed())) behaviorRand := dice.NewDeterministicDice(int64(s.userValidator.GetBehaviorSeed()))
BaseDrainSize := behaviorRand.Roll(3266) BaseDrainSize := behaviorRand.Roll(3266)
@@ -143,7 +143,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
drainConnection := func(e error) error { drainConnection := func(e error) error {
// We read a deterministic generated length of data before closing the connection to offset padding read pattern // We read a deterministic generated length of data before closing the connection to offset padding read pattern
readSizeRemain -= int(buffer.Len()) readSizeRemain -= int(buffer.Len())
if readSizeRemain > 0 { if readSizeRemain > 0 && isDrain {
err := s.DrainConnN(reader, readSizeRemain) err := s.DrainConnN(reader, readSizeRemain)
if err != nil { if err != nil {
return newError("failed to drain connection DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(err).Base(e) return newError("failed to drain connection DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(err).Base(e)

View File

@@ -220,9 +220,18 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
return newError("unable to set read deadline").Base(err).AtWarning() return newError("unable to set read deadline").Base(err).AtWarning()
} }
iConn := connection
if statConn, ok := iConn.(*internet.StatCouterConnection); ok {
iConn = statConn.Connection
}
_, isDrain := iConn.(*net.TCPConn)
if !isDrain {
_, isDrain = iConn.(*net.UnixConn)
}
reader := &buf.BufferedReader{Reader: buf.NewReader(connection)} reader := &buf.BufferedReader{Reader: buf.NewReader(connection)}
svrSession := encoding.NewServerSession(h.clients, h.sessionHistory) svrSession := encoding.NewServerSession(h.clients, h.sessionHistory)
request, err := svrSession.DecodeRequestHeader(reader) request, err := svrSession.DecodeRequestHeader(reader, isDrain)
if err != nil { if err != nil {
if errors.Cause(err) != io.EOF { if errors.Cause(err) != io.EOF {
log.Record(&log.AccessMessage{ log.Record(&log.AccessMessage{

View File

@@ -136,8 +136,8 @@ func TestHTTPConnectionHeader(t *testing.T) {
} }
func TestDomainSocket(t *testing.T) { func TestDomainSocket(t *testing.T) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" || runtime.GOOS == "android" {
t.Skip("Not supported on windows") t.Skip("Not supported on windows or android")
return return
} }
tcpServer := tcp.Server{ tcpServer := tcp.Server{

View File

@@ -1,4 +1,5 @@
// +build !windows // +build !windows
// +build !android
package domainsocket_test package domainsocket_test

View File

@@ -21,7 +21,7 @@ var (
globalDialerAccess sync.Mutex globalDialerAccess sync.Mutex
) )
func getHTTPClient(_ context.Context, dest net.Destination, tlsSettings *tls.Config) (*http.Client, error) { func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config) (*http.Client, error) {
globalDialerAccess.Lock() globalDialerAccess.Lock()
defer globalDialerAccess.Unlock() defer globalDialerAccess.Unlock()
@@ -48,7 +48,7 @@ func getHTTPClient(_ context.Context, dest net.Destination, tlsSettings *tls.Con
} }
address := net.ParseAddress(rawHost) address := net.ParseAddress(rawHost)
pconn, err := internet.DialSystem(context.Background(), net.TCPDestination(address, port), nil) pconn, err := internet.DialSystem(ctx, net.TCPDestination(address, port), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -60,7 +60,7 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &packetConnWrapper{ return &PacketConnWrapper{
conn: packetConn, conn: packetConn,
dest: destAddr, dest: destAddr,
}, nil }, nil
@@ -98,41 +98,49 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
return dialer.DialContext(ctx, dest.Network.SystemString(), dest.NetAddr()) return dialer.DialContext(ctx, dest.Network.SystemString(), dest.NetAddr())
} }
type packetConnWrapper struct { type PacketConnWrapper struct {
conn net.PacketConn conn net.PacketConn
dest net.Addr dest net.Addr
} }
func (c *packetConnWrapper) Close() error { func (c *PacketConnWrapper) Close() error {
return c.conn.Close() return c.conn.Close()
} }
func (c *packetConnWrapper) LocalAddr() net.Addr { func (c *PacketConnWrapper) LocalAddr() net.Addr {
return c.conn.LocalAddr() return c.conn.LocalAddr()
} }
func (c *packetConnWrapper) RemoteAddr() net.Addr { func (c *PacketConnWrapper) RemoteAddr() net.Addr {
return c.dest return c.dest
} }
func (c *packetConnWrapper) Write(p []byte) (int, error) { func (c *PacketConnWrapper) Write(p []byte) (int, error) {
return c.conn.WriteTo(p, c.dest) return c.conn.WriteTo(p, c.dest)
} }
func (c *packetConnWrapper) Read(p []byte) (int, error) { func (c *PacketConnWrapper) Read(p []byte) (int, error) {
n, _, err := c.conn.ReadFrom(p) n, _, err := c.conn.ReadFrom(p)
return n, err return n, err
} }
func (c *packetConnWrapper) SetDeadline(t time.Time) error { func (c *PacketConnWrapper) WriteTo(p []byte, d net.Addr) (int, error) {
return c.conn.WriteTo(p, d)
}
func (c *PacketConnWrapper) ReadFrom(p []byte) (int, net.Addr, error) {
return c.conn.ReadFrom(p)
}
func (c *PacketConnWrapper) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t) return c.conn.SetDeadline(t)
} }
func (c *packetConnWrapper) SetReadDeadline(t time.Time) error { func (c *PacketConnWrapper) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t) return c.conn.SetReadDeadline(t)
} }
func (c *packetConnWrapper) SetWriteDeadline(t time.Time) error { func (c *PacketConnWrapper) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t) return c.conn.SetWriteDeadline(t)
} }

View File

@@ -54,7 +54,7 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
lc.Control = nil lc.Control = nil
network = addr.Network() network = addr.Network()
address = addr.Name address = addr.Name
if runtime.GOOS == "linux" && address[0] == '@' { if (runtime.GOOS == "linux" || runtime.GOOS == "android") && address[0] == '@' {
// linux abstract unix domain socket is lockfree // linux abstract unix domain socket is lockfree
if len(address) > 1 && address[1] == '@' { if len(address) > 1 && address[1] == '@' {
// but may need padding to work with haproxy // but may need padding to work with haproxy

View File

@@ -48,7 +48,7 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
Net: "unix", Net: "unix",
}, streamSettings.SocketSettings) }, streamSettings.SocketSettings)
if err != nil { if err != nil {
return nil, newError("failed to listen Unix Doman Socket on ", address).Base(err) return nil, newError("failed to listen Unix Domain Socket on ", address).Base(err)
} }
newError("listening Unix Domain Socket on ", address).WriteToLog(session.ExportIDToError(ctx)) newError("listening Unix Domain Socket on ", address).WriteToLog(session.ExportIDToError(ctx))
locker := ctx.Value(address.Domain()) locker := ctx.Value(address.Domain())

View File

@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp"
"github.com/xtls/xray-core/common/protocol/tls/cert" "github.com/xtls/xray-core/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
) )
@@ -53,6 +54,19 @@ func (c *Config) BuildCertificates() []tls.Certificate {
continue continue
} }
certs = append(certs, keyPair) certs = append(certs, keyPair)
if entry.OcspStapling != 0 {
go func(cert *tls.Certificate) {
t := time.NewTicker(time.Duration(entry.OcspStapling) * time.Second)
for {
if newData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newData
}
<-t.C
}
}(&certs[len(certs)-1])
}
} }
return certs return certs
} }
@@ -212,6 +226,42 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
config.NextProtos = []string{"h2", "http/1.1"} config.NextProtos = []string{"h2", "http/1.1"}
} }
switch c.MinVersion {
case "1.0":
config.MinVersion = tls.VersionTLS10
case "1.1":
config.MinVersion = tls.VersionTLS11
case "1.2":
config.MinVersion = tls.VersionTLS12
case "1.3":
config.MinVersion = tls.VersionTLS13
}
switch c.MaxVersion {
case "1.0":
config.MaxVersion = tls.VersionTLS10
case "1.1":
config.MaxVersion = tls.VersionTLS11
case "1.2":
config.MaxVersion = tls.VersionTLS12
case "1.3":
config.MaxVersion = tls.VersionTLS13
}
if len(c.CipherSuites) > 0 {
id := make(map[string]uint16)
for _, s := range tls.CipherSuites() {
id[s.Name] = s.ID
}
for _, n := range strings.Split(c.CipherSuites, ":") {
if id[n] != 0 {
config.CipherSuites = append(config.CipherSuites, id[n])
}
}
}
config.PreferServerCipherSuites = c.PreferServerCipherSuites
return config return config
} }

View File

@@ -80,10 +80,11 @@ type Certificate struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// TLS certificate in x509 format. // TLS certificate in x509 format.
Certificate []byte `protobuf:"bytes,1,opt,name=Certificate,proto3" json:"Certificate,omitempty"` Certificate []byte `protobuf:"bytes,1,opt,name=certificate,proto3" json:"certificate,omitempty"`
// TLS key in x509 format. // TLS key in x509 format.
Key []byte `protobuf:"bytes,2,opt,name=Key,proto3" json:"Key,omitempty"` Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.tls.Certificate_Usage" json:"usage,omitempty"` Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.tls.Certificate_Usage" json:"usage,omitempty"`
OcspStapling int64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
} }
func (x *Certificate) Reset() { func (x *Certificate) Reset() {
@@ -139,6 +140,13 @@ func (x *Certificate) GetUsage() Certificate_Usage {
return Certificate_ENCIPHERMENT return Certificate_ENCIPHERMENT
} }
func (x *Certificate) GetOcspStapling() int64 {
if x != nil {
return x.OcspStapling
}
return 0
}
type Config struct { type Config struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -146,8 +154,6 @@ type Config struct {
// Whether or not to allow self-signed certificates. // Whether or not to allow self-signed certificates.
AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3" json:"allow_insecure,omitempty"` AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3" json:"allow_insecure,omitempty"`
// Whether or not to allow insecure cipher suites.
AllowInsecureCiphers bool `protobuf:"varint,5,opt,name=allow_insecure_ciphers,json=allowInsecureCiphers,proto3" json:"allow_insecure_ciphers,omitempty"`
// List of certificates to be served on server. // List of certificates to be served on server.
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"` Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"`
// Override server name. // Override server name.
@@ -155,10 +161,18 @@ type Config struct {
// Lists of string as ALPN values. // Lists of string as ALPN values.
NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"` NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"`
// Whether or not to disable session (ticket) resumption. // Whether or not to disable session (ticket) resumption.
DisableSessionResumption bool `protobuf:"varint,6,opt,name=disable_session_resumption,json=disableSessionResumption,proto3" json:"disable_session_resumption,omitempty"` DisableSessionResumption bool `protobuf:"varint,5,opt,name=disable_session_resumption,json=disableSessionResumption,proto3" json:"disable_session_resumption,omitempty"`
// If true, root certificates on the system will not be loaded for // If true, root certificates on the system will not be loaded for
// verification. // verification.
DisableSystemRoot bool `protobuf:"varint,7,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"` DisableSystemRoot bool `protobuf:"varint,6,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"`
// The minimum TLS version.
MinVersion string `protobuf:"bytes,7,opt,name=min_version,json=minVersion,proto3" json:"min_version,omitempty"`
// The maximum TLS version.
MaxVersion string `protobuf:"bytes,8,opt,name=max_version,json=maxVersion,proto3" json:"max_version,omitempty"`
// Specify cipher suites, except for TLS 1.3.
CipherSuites string `protobuf:"bytes,9,opt,name=cipher_suites,json=cipherSuites,proto3" json:"cipher_suites,omitempty"`
// Whether the server selects its most preferred ciphersuite.
PreferServerCipherSuites bool `protobuf:"varint,10,opt,name=prefer_server_cipher_suites,json=preferServerCipherSuites,proto3" json:"prefer_server_cipher_suites,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -200,13 +214,6 @@ func (x *Config) GetAllowInsecure() bool {
return false return false
} }
func (x *Config) GetAllowInsecureCiphers() bool {
if x != nil {
return x.AllowInsecureCiphers
}
return false
}
func (x *Config) GetCertificate() []*Certificate { func (x *Config) GetCertificate() []*Certificate {
if x != nil { if x != nil {
return x.Certificate return x.Certificate
@@ -242,6 +249,34 @@ func (x *Config) GetDisableSystemRoot() bool {
return false return false
} }
func (x *Config) GetMinVersion() string {
if x != nil {
return x.MinVersion
}
return ""
}
func (x *Config) GetMaxVersion() string {
if x != nil {
return x.MaxVersion
}
return ""
}
func (x *Config) GetCipherSuites() string {
if x != nil {
return x.CipherSuites
}
return ""
}
func (x *Config) GetPreferServerCipherSuites() bool {
if x != nil {
return x.PreferServerCipherSuites
}
return false
}
var File_transport_internet_tls_config_proto protoreflect.FileDescriptor var File_transport_internet_tls_config_proto protoreflect.FileDescriptor
var file_transport_internet_tls_config_proto_rawDesc = []byte{ var file_transport_internet_tls_config_proto_rawDesc = []byte{
@@ -249,50 +284,59 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74,
0x6c, 0x73, 0x22, 0xcd, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x6c, 0x73, 0x22, 0xf2, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x2e,
0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d,
0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20,
0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e,
0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e,
0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10,
0x10, 0x02, 0x22, 0xe5, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59,
0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f,
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xd5, 0x03, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
0x63, 0x75, 0x72, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65,
0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x18, 0x05, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f,
0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x65, 0x72,
0x75, 0x72, 0x65, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x65, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f,
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76,
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70,
0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3c, 0x0a, 0x1a, 0x64,
0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3c, 0x0a, 0x1a, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72,
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52,
0x52, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x73,
0x52, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x74,
0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x6f, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53,
0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x69, 0x6e,
0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x42, 0x73, 0x0a, 0x1f, 0x63, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x61,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63,
0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01,
0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x74, 0x6c, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73,
0x73, 0xaa, 0x02, 0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x54, 0x6c, 0x73, 0x62, 0x72, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x73, 0x42,
0x73, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x74,
0x6c, 0x73, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2f, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1b, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
0x2e, 0x54, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -8,10 +8,10 @@ option java_multiple_files = true;
message Certificate { message Certificate {
// TLS certificate in x509 format. // TLS certificate in x509 format.
bytes Certificate = 1; bytes certificate = 1;
// TLS key in x509 format. // TLS key in x509 format.
bytes Key = 2; bytes key = 2;
enum Usage { enum Usage {
ENCIPHERMENT = 0; ENCIPHERMENT = 0;
@@ -20,15 +20,14 @@ message Certificate {
} }
Usage usage = 3; Usage usage = 3;
int64 ocsp_stapling = 4;
} }
message Config { message Config {
// Whether or not to allow self-signed certificates. // Whether or not to allow self-signed certificates.
bool allow_insecure = 1; bool allow_insecure = 1;
// Whether or not to allow insecure cipher suites.
bool allow_insecure_ciphers = 5;
// List of certificates to be served on server. // List of certificates to be served on server.
repeated Certificate certificate = 2; repeated Certificate certificate = 2;
@@ -39,9 +38,21 @@ message Config {
repeated string next_protocol = 4; repeated string next_protocol = 4;
// Whether or not to disable session (ticket) resumption. // Whether or not to disable session (ticket) resumption.
bool disable_session_resumption = 6; bool disable_session_resumption = 5;
// If true, root certificates on the system will not be loaded for // If true, root certificates on the system will not be loaded for
// verification. // verification.
bool disable_system_root = 7; bool disable_system_root = 6;
// The minimum TLS version.
string min_version = 7;
// The maximum TLS version.
string max_version = 8;
// Specify cipher suites, except for TLS 1.3.
string cipher_suites = 9;
// Whether the server selects its most preferred ciphersuite.
bool prefer_server_cipher_suites = 10;
} }

View File

@@ -64,9 +64,7 @@ func TestExpiredCertificate(t *testing.T) {
} }
func TestInsecureCertificates(t *testing.T) { func TestInsecureCertificates(t *testing.T) {
c := &Config{ c := &Config{}
AllowInsecureCiphers: true,
}
tlsConfig := c.GetTLSConfig() tlsConfig := c.GetTLSConfig()
if len(tlsConfig.CipherSuites) > 0 { if len(tlsConfig.CipherSuites) > 0 {

View File

@@ -2,12 +2,14 @@ package xtls
import ( import (
"crypto/x509" "crypto/x509"
"strings"
"sync" "sync"
"time" "time"
xtls "github.com/xtls/go" xtls "github.com/xtls/go"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp"
"github.com/xtls/xray-core/common/protocol/tls/cert" "github.com/xtls/xray-core/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
) )
@@ -51,6 +53,19 @@ func (c *Config) BuildCertificates() []xtls.Certificate {
continue continue
} }
certs = append(certs, keyPair) certs = append(certs, keyPair)
if entry.OcspStapling != 0 {
go func(cert *xtls.Certificate) {
t := time.NewTicker(time.Duration(entry.OcspStapling) * time.Second)
for {
if newData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newData
}
<-t.C
}
}(&certs[len(certs)-1])
}
} }
return certs return certs
} }
@@ -202,6 +217,42 @@ func (c *Config) GetXTLSConfig(opts ...Option) *xtls.Config {
config.NextProtos = []string{"h2", "http/1.1"} config.NextProtos = []string{"h2", "http/1.1"}
} }
switch c.MinVersion {
case "1.0":
config.MinVersion = xtls.VersionTLS10
case "1.1":
config.MinVersion = xtls.VersionTLS11
case "1.2":
config.MinVersion = xtls.VersionTLS12
case "1.3":
config.MinVersion = xtls.VersionTLS13
}
switch c.MaxVersion {
case "1.0":
config.MaxVersion = xtls.VersionTLS10
case "1.1":
config.MaxVersion = xtls.VersionTLS11
case "1.2":
config.MaxVersion = xtls.VersionTLS12
case "1.3":
config.MaxVersion = xtls.VersionTLS13
}
if len(c.CipherSuites) > 0 {
id := make(map[string]uint16)
for _, s := range xtls.CipherSuites() {
id[s.Name] = s.ID
}
for _, n := range strings.Split(c.CipherSuites, ":") {
if id[n] != 0 {
config.CipherSuites = append(config.CipherSuites, id[n])
}
}
}
config.PreferServerCipherSuites = c.PreferServerCipherSuites
return config return config
} }

View File

@@ -79,11 +79,12 @@ type Certificate struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// XTLS certificate in x509 format. // TLS certificate in x509 format.
Certificate []byte `protobuf:"bytes,1,opt,name=Certificate,proto3" json:"Certificate,omitempty"` Certificate []byte `protobuf:"bytes,1,opt,name=certificate,proto3" json:"certificate,omitempty"`
// XTLS key in x509 format. // TLS key in x509 format.
Key []byte `protobuf:"bytes,2,opt,name=Key,proto3" json:"Key,omitempty"` Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.xtls.Certificate_Usage" json:"usage,omitempty"` Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.xtls.Certificate_Usage" json:"usage,omitempty"`
OcspStapling int64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
} }
func (x *Certificate) Reset() { func (x *Certificate) Reset() {
@@ -139,6 +140,13 @@ func (x *Certificate) GetUsage() Certificate_Usage {
return Certificate_ENCIPHERMENT return Certificate_ENCIPHERMENT
} }
func (x *Certificate) GetOcspStapling() int64 {
if x != nil {
return x.OcspStapling
}
return 0
}
type Config struct { type Config struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -146,8 +154,6 @@ type Config struct {
// Whether or not to allow self-signed certificates. // Whether or not to allow self-signed certificates.
AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3" json:"allow_insecure,omitempty"` AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3" json:"allow_insecure,omitempty"`
// Whether or not to allow insecure cipher suites.
AllowInsecureCiphers bool `protobuf:"varint,5,opt,name=allow_insecure_ciphers,json=allowInsecureCiphers,proto3" json:"allow_insecure_ciphers,omitempty"`
// List of certificates to be served on server. // List of certificates to be served on server.
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"` Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"`
// Override server name. // Override server name.
@@ -155,10 +161,18 @@ type Config struct {
// Lists of string as ALPN values. // Lists of string as ALPN values.
NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"` NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"`
// Whether or not to disable session (ticket) resumption. // Whether or not to disable session (ticket) resumption.
DisableSessionResumption bool `protobuf:"varint,6,opt,name=disable_session_resumption,json=disableSessionResumption,proto3" json:"disable_session_resumption,omitempty"` DisableSessionResumption bool `protobuf:"varint,5,opt,name=disable_session_resumption,json=disableSessionResumption,proto3" json:"disable_session_resumption,omitempty"`
// If true, root certificates on the system will not be loaded for // If true, root certificates on the system will not be loaded for
// verification. // verification.
DisableSystemRoot bool `protobuf:"varint,7,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"` DisableSystemRoot bool `protobuf:"varint,6,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"`
// The minimum TLS version.
MinVersion string `protobuf:"bytes,7,opt,name=min_version,json=minVersion,proto3" json:"min_version,omitempty"`
// The maximum TLS version.
MaxVersion string `protobuf:"bytes,8,opt,name=max_version,json=maxVersion,proto3" json:"max_version,omitempty"`
// Specify cipher suites, except for TLS 1.3.
CipherSuites string `protobuf:"bytes,9,opt,name=cipher_suites,json=cipherSuites,proto3" json:"cipher_suites,omitempty"`
// Whether the server selects its most preferred ciphersuite.
PreferServerCipherSuites bool `protobuf:"varint,10,opt,name=prefer_server_cipher_suites,json=preferServerCipherSuites,proto3" json:"prefer_server_cipher_suites,omitempty"`
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -200,13 +214,6 @@ func (x *Config) GetAllowInsecure() bool {
return false return false
} }
func (x *Config) GetAllowInsecureCiphers() bool {
if x != nil {
return x.AllowInsecureCiphers
}
return false
}
func (x *Config) GetCertificate() []*Certificate { func (x *Config) GetCertificate() []*Certificate {
if x != nil { if x != nil {
return x.Certificate return x.Certificate
@@ -242,6 +249,34 @@ func (x *Config) GetDisableSystemRoot() bool {
return false return false
} }
func (x *Config) GetMinVersion() string {
if x != nil {
return x.MinVersion
}
return ""
}
func (x *Config) GetMaxVersion() string {
if x != nil {
return x.MaxVersion
}
return ""
}
func (x *Config) GetCipherSuites() string {
if x != nil {
return x.CipherSuites
}
return ""
}
func (x *Config) GetPreferServerCipherSuites() bool {
if x != nil {
return x.PreferServerCipherSuites
}
return false
}
var File_transport_internet_xtls_config_proto protoreflect.FileDescriptor var File_transport_internet_xtls_config_proto protoreflect.FileDescriptor
var file_transport_internet_xtls_config_proto_rawDesc = []byte{ var file_transport_internet_xtls_config_proto_rawDesc = []byte{
@@ -249,50 +284,60 @@ var file_transport_internet_xtls_config_proto_rawDesc = []byte{
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
0x78, 0x74, 0x6c, 0x73, 0x22, 0xce, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x78, 0x74, 0x6c, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67,
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x22, 0x74, 0x65, 0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x12,
0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e, 0x43, 0x49, 0x23, 0x0a, 0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67,
0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x55, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70,
0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59, 0x10, 0x01, 0x6c, 0x69, 0x6e, 0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a,
0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x53, 0x0c, 0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12,
0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xe6, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x14, 0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52,
0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x49, 0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49,
0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x53, 0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xd6, 0x03, 0x0a, 0x06, 0x43,
0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69,
0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61,
0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x4b, 0x0a, 0x0b,
0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x12, 0x4b, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73,
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74, 0x6c, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x65,
0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x65,
0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x78, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x28,
0x65, 0x78, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12,
0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x3c, 0x0a, 0x1a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69,
0x12, 0x3c, 0x0a, 0x1a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20,
0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x01, 0x28, 0x08, 0x52, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x73,
0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a,
0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f,
0x0a, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61,
0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73, 0x62, 0x6c, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a,
0x61, 0x62, 0x6c, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x42, 0x76, 0x0b, 0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01,
0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x69, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74, 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20,
0x6c, 0x73, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x23, 0x0a, 0x0d, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75,
0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1c, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x69, 0x74, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x1b, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x5f, 0x73,
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69,
0x74, 0x2e, 0x58, 0x74, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x74, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x70, 0x72, 0x65, 0x66, 0x65,
0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69,
0x74, 0x65, 0x73, 0x42, 0x76, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x65, 0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d,
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1c, 0x58,
0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x58, 0x74, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -7,11 +7,11 @@ option java_package = "com.xray.transport.internet.xtls";
option java_multiple_files = true; option java_multiple_files = true;
message Certificate { message Certificate {
// XTLS certificate in x509 format. // TLS certificate in x509 format.
bytes Certificate = 1; bytes certificate = 1;
// XTLS key in x509 format. // TLS key in x509 format.
bytes Key = 2; bytes key = 2;
enum Usage { enum Usage {
ENCIPHERMENT = 0; ENCIPHERMENT = 0;
@@ -20,15 +20,14 @@ message Certificate {
} }
Usage usage = 3; Usage usage = 3;
int64 ocsp_stapling = 4;
} }
message Config { message Config {
// Whether or not to allow self-signed certificates. // Whether or not to allow self-signed certificates.
bool allow_insecure = 1; bool allow_insecure = 1;
// Whether or not to allow insecure cipher suites.
bool allow_insecure_ciphers = 5;
// List of certificates to be served on server. // List of certificates to be served on server.
repeated Certificate certificate = 2; repeated Certificate certificate = 2;
@@ -39,9 +38,21 @@ message Config {
repeated string next_protocol = 4; repeated string next_protocol = 4;
// Whether or not to disable session (ticket) resumption. // Whether or not to disable session (ticket) resumption.
bool disable_session_resumption = 6; bool disable_session_resumption = 5;
// If true, root certificates on the system will not be loaded for // If true, root certificates on the system will not be loaded for
// verification. // verification.
bool disable_system_root = 7; bool disable_system_root = 6;
// The minimum TLS version.
string min_version = 7;
// The maximum TLS version.
string max_version = 8;
// Specify cipher suites, except for TLS 1.3.
string cipher_suites = 9;
// Whether the server selects its most preferred ciphersuite.
bool prefer_server_cipher_suites = 10;
} }

View File

@@ -65,9 +65,7 @@ func TestExpiredCertificate(t *testing.T) {
} }
func TestInsecureCertificates(t *testing.T) { func TestInsecureCertificates(t *testing.T) {
c := &Config{ c := &Config{}
AllowInsecureCiphers: true,
}
xtlsConfig := c.GetXTLSConfig() xtlsConfig := c.GetXTLSConfig()
if len(xtlsConfig.CipherSuites) > 0 { if len(xtlsConfig.CipherSuites) > 0 {