Compare commits

...

31 Commits

Author SHA1 Message Date
AkinoKaede
d67cf3d598 v1.3.1 2021-03-02 22:59:27 +08:00
kokeri
ca633fc8c5 Chore: Add GitHub Actions (#251)
Co-authored-by: xinb <netwhilt@outlook.com>
Co-authored-by: 秋のかえで <autmaple@protonmail.com>
Co-authored-by: Jim Han <50871214+JimhHan@users.noreply.github.com>
2021-03-02 22:46:50 +08:00
Xray9
c345d4818e Fix available mux picker in reverse portal (#274) 2021-03-01 07:26:53 +00:00
Jim Han
7fb1f65354 Fix https://github.com/XTLS/Xray-core/issues/289 (#300) 2021-03-01 02:43:27 +00:00
RPRX
4b97edae74 Fix https://github.com/XTLS/Xray-core/issues/320 2021-03-01 01:29:17 +00:00
Kid
8aabbeefe1 Add /opt to assets location (#312) 2021-02-27 23:09:44 +08:00
RPRX
48fab4d398 Add Xray_onekey 2021-02-22 02:21:17 +00:00
RPRX
8b9c0ae593 Enable (X)TLS hot reloading by default (#281)
Super BiuBiu
2021-02-20 02:15:57 +00:00
秋のかえで
347d9735da Remove (x)tls.WithNextProto("h2") in tcp/hub.go (#260) 2021-02-18 11:50:09 +00:00
Jim Han
9aa49be703 Restrict tag to be unique (#258) 2021-02-18 09:53:10 +00:00
RPRX
fed8610d3f Fix Freedom Outbound UDP redirect
已检查 b.UDP 各源头:Mux(VLESS、VMess)、Trojan、Shadowsocks、Socks、TPROXY(Dokodemo-door)
2021-02-17 13:37:55 +00:00
RPRX
d22c2d034c Avoid panic in KDF func for Go 1.16
2a206c7fcc
2021-02-17 03:02:03 +00:00
RPRX
4c10a9eb4e Add Xray-yes 2021-02-15 10:50:30 +00:00
RPRX
4ff1ff1d7d Add Netch (NetFilter & TUN/TAP) 2021-02-15 09:10:19 +00:00
RPRX
573b7807c0 v1.3.0 2021-02-12 15:59:56 +00:00
eMeab
81d993158f Support hot reloading of certificate and key files (#225) 2021-02-12 15:33:19 +00:00
秋のかえで
df39991bb3 Refactor: Add Shadowsocks Validator (#233) 2021-02-12 15:17:31 +00:00
Monsoon
1b87264c53 Support loading config from different formats (#228) 2021-02-12 14:12:58 +00:00
秋のかえで
96d7156eba Fix a typo (#236) 2021-02-12 13:23:30 +00:00
RPRX
d170416219 Add environment variable XRAY_CONE_DISABLED option 2021-02-11 15:37:02 +00:00
RPRX
8ca8a7126b Add XUDP support by simply renaming vudp to xudp
https://t.me/projectXray/243505
2021-02-11 11:33:08 +00:00
RPRX
1174ff3090 Refactor: VLESS & VMess & Mux UDP FullCone NAT
https://t.me/projectXray/242770
2021-02-11 01:28:21 +00:00
RPRX
523c416bb5 v1.2.4 2021-01-31 11:56:39 +00:00
eMeab
c13b8ec9bb Fix OCSP Stapling (#172)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-30 23:17:07 +00:00
Jim Han
4cd343f2d5 Fix tests (#201)
Co-authored-by: RPRX <63339210+rprx@users.noreply.github.com>
2021-01-30 13:01:20 +00:00
RPRX
d032a8deb7 Fix acceptProxyProtocol
https://github.com/XTLS/Xray-core/pull/182#issuecomment-768336178
2021-01-28 12:08:57 +00:00
RPRX
303fd6e261 Standardize Socks Outbound Authentication Behavior 2021-01-28 03:11:17 +00:00
RPRX
c880b916ee Avoid panic in BytesTo func 2021-01-27 01:09:58 +00:00
RPRX
ceff4185dc Improve the request for UDP Associate in Socks5 2021-01-26 23:53:01 +00:00
RPRX
59c7c4897c Add luci-app-xray (openwrt-xray) 2021-01-26 22:50:28 +00:00
RPRX
8ffc430351 Fix VLESS & Trojan fallbacks xver 2021-01-23 21:06:15 +00:00
52 changed files with 1269 additions and 311 deletions

33
.github/build/friendly-filenames.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"android-arm64": { "friendlyName": "android-arm64-v8a"},
"darwin-amd64": { "friendlyName": "macos-64" },
"darwin-arm64": { "friendlyName": "macos-arm64-v8a" },
"dragonfly-amd64": { "friendlyName": "dragonfly-64" },
"freebsd-386": { "friendlyName": "freebsd-32" },
"freebsd-amd64": { "friendlyName": "freebsd-64" },
"freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" },
"freebsd-arm7": { "friendlyName": "freebsd-arm32-v7a" },
"linux-386": { "friendlyName": "linux-32" },
"linux-amd64": { "friendlyName": "linux-64" },
"linux-arm5": { "friendlyName": "linux-arm32-v5" },
"linux-arm64": { "friendlyName": "linux-arm64-v8a" },
"linux-arm6": { "friendlyName": "linux-arm32-v6" },
"linux-arm7": { "friendlyName": "linux-arm32-v7a" },
"linux-mips64le": { "friendlyName": "linux-mips64le" },
"linux-mips64": { "friendlyName": "linux-mips64" },
"linux-mipsle": { "friendlyName": "linux-mips32le" },
"linux-mipslesoftfloat": { "friendlyName": "linux-mips32le-softfloat" },
"linux-mips": { "friendlyName": "linux-mips32" },
"linux-mipssoftfloat": { "friendlyName": "linux-mips32-softfloat" },
"linux-riscv64": { "friendlyName": "linux-riscv64" },
"linux-ppc64": { "friendlyName": "linux-ppc64" },
"linux-ppc64le": { "friendlyName": "linux-rppc64le" },
"linux-s390x": { "friendlyName": "linux-s390x" },
"openbsd-386": { "friendlyName": "openbsd-32" },
"openbsd-amd64": { "friendlyName": "openbsd-64" },
"openbsd-arm64": { "friendlyName": "openbsd-arm64-v8a" },
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
"windows-amd64": { "friendlyName": "windows-64" },
"windows-386": { "friendlyName": "windows-32" },
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
}

212
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,212 @@
name: Build and Release
on:
workflow_dispatch:
release:
types: [published]
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
build:
strategy:
matrix:
# Include amd64 on all platforms.
goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
goarch: [amd64, 386]
exclude:
# Exclude i386 on darwin and dragonfly.
- goarch: 386
goos: dragonfly
- goarch: 386
goos: darwin
include:
# BEIGIN MacOS ARM64
- goos: darwin
goarch: arm64
# END MacOS ARM64
# BEGIN Linux ARM 5 6 7
- goos: linux
goarch: arm
goarm: 7
- goos: linux
goarch: arm
goarm: 6
- goos: linux
goarch: arm
goarm: 5
# END Linux ARM 5 6 7
# BEGIN Android ARM 8
- goos: android
goarch: arm64
# END Android ARM 8
# Windows ARM 7
- goos: windows
goarch: arm
goarm: 7
# BEGIN Other architectures
# BEGIN riscv64 & ARM64
- goos: linux
goarch: arm64
- goos: linux
goarch: riscv64
# END riscv64 & ARM64
# BEGIN MIPS
- goos: linux
goarch: mips64
- goos: linux
goarch: mips64le
- goos: linux
goarch: mipsle
- goos: linux
goarch: mips
# END MIPS
# BEGIN PPC
- goos: linux
goarch: ppc64
- goos: linux
goarch: ppc64le
# END PPC
# BEGIN FreeBSD ARM
- goos: freebsd
goarch: arm64
- goos: freebsd
goarch: arm
goarm: 7
# END FreeBSD ARM
# BEGIN S390X
- goos: linux
goarch: s390x
# END S390X
# END Other architectures
# BEGIN OPENBSD ARM
- goos: openbsd
goarch: arm64
- goos: openbsd
goarch: arm
goarm: 7
# END OPENBSD ARM
fail-fast: false
#配置编译环境
runs-on: ubuntu-20.04
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
CGO_ENABLED: 0
steps:
- name: Checkout codebase
uses: actions/checkout@v2
- name: Show workflow information
id: get_filename
run: |
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
echo "::set-output name=ASSET_NAME::$_NAME"
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.16
- name: Get project dependencies
run: go mod download
- name: Replace Custom to Commit ID
if: github.event_name != 'release'
run: |
ID=$(git rev-parse --short ${{ github.sha }})
if [ "${{ github.event_name }}" == 'pull_request' ]
then
ID=$(git rev-parse --short ${{ github.event.pull_request.head.sha }})
fi
sed -i '/build/ s/Custom/'$ID'/' ./core/core.go
- name: Build Xray
run: |
mkdir -p build_assets
go build -v -o build_assets/xray -trimpath -ldflags "-s -w -buildid=" ./main
- name: Build Mips softfloat Xray
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
run: |
GOMIPS=softfloat go build -v -o build_assets/xray_softfloat -trimpath -ldflags "-s -w -buildid=" ./main
- name: Rename Windows Xray
if: matrix.goos == 'windows'
run: |
cd ./build_assets || exit 1
mv xray xray.exe
- name: Prepare to release
run: |
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
LIST=('geoip geoip geoip' 'domain-list-community dlc geosite')
for i in "${LIST[@]}"
do
INFO=($(echo $i | awk 'BEGIN{FS=" ";OFS=" "} {print $1,$2,$3}'))
LASTEST_TAG="$(curl -sL "https://api.github.com/repos/v2fly/${INFO[0]}/releases" | jq -r ".[0].tag_name" || echo "latest")"
FILE_NAME="${INFO[2]}.dat"
echo -e "Downloading ${FILE_NAME}..."
curl -L "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat" -o ./build_assets/${FILE_NAME}
echo -e "Verifying HASH key..."
HASH="$(curl -sL "https://github.com/v2fly/${INFO[0]}/releases/download/${LASTEST_TAG}/${INFO[1]}.dat.sha256sum" | awk -F ' ' '{print $1}')"
[ "$(sha256sum "./build_assets/${FILE_NAME}" | awk -F ' ' '{print $1}')" == "${HASH}" ] || { echo -e "The HASH key of ${FILE_NAME} does not match cloud one."; exit 1; }
done
- name: Create ZIP archive
shell: bash
run: |
pushd build_assets || exit 1
touch -mt 202101010000 *
zip -9vr ../Xray-$ASSET_NAME.zip .
for CORE in $(ls xray*)
do
COREDGST=$CORE.dgst
for METHOD in {"md5","sha1","sha256","sha512"}
do
openssl dgst -$METHOD $CORE | sed 's/([^)]*)//g' >>$COREDGST
done
done
popd || exit 1
FILE=./Xray-$ASSET_NAME.zip
DGST=$FILE.dgst
for METHOD in {"md5","sha1","sha256","sha512"}
do
openssl dgst -$METHOD $FILE | sed 's/([^)]*)//g' >>$DGST
done
- name: Change the name
run: |
mv build_assets Xray-$ASSET_NAME
- name: Upload files to Artifacts
uses: actions/upload-artifact@v2
with:
name: Xray-${{ steps.get_filename.outputs.ASSET_NAME }}
path: |
./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}/*
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
if: github.event_name == 'release'
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./Xray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip*
tag: ${{ github.ref }}
file_glob: true

48
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Test
on:
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ^1.16
- name: Checkout codebase
uses: actions/checkout@v2
- name: Prepare geo*dat
if: ${{ matrix.os != 'windows-latest' }}
run: |
mkdir resources
wget -O ./resources/geoip.dat https://github.com/v2fly/geoip/releases/latest/download/geoip.dat
wget -O ./resources/geosite.dat https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat
- name: Prepare geo*dat for Windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
mkdir resources
Invoke-WebRequest -Uri "https://github.com/v2fly/geoip/releases/latest/download/geoip.dat" -OutFile "./resources/geoip.dat"
Invoke-WebRequest -Uri "https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat" -OutFile "./resources/geosite.dat"
- name: Test
run: go test -timeout 1h -v ./...

View File

@@ -17,6 +17,8 @@
- One Click
- [ProxySU](https://github.com/proxysu/ProxySU)
- [v2ray-agent](https://github.com/mack-a/v2ray-agent)
- [Xray-yes](https://github.com/jiuqi9997/Xray-yes)
- [Xray_onekey](https://github.com/wulabing/Xray_onekey)
- Magisk
- [Xray4Magisk](https://github.com/CerteKim/Xray4Magisk)
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
@@ -34,9 +36,11 @@
- [PassWall](https://github.com/xiaorouji/openwrt-passwall)
- [Hello World](https://github.com/jerrykuku/luci-app-vssr)
- [ShadowSocksR Plus+](https://github.com/fw876/helloworld)
- [luci-app-xray](https://github.com/yichya/luci-app-xray) ([openwrt-xray](https://github.com/yichya/openwrt-xray))
- Windows
- [v2rayN](https://github.com/2dust/v2rayN)
- [Qv2ray](https://github.com/Qv2ray/Qv2ray)
- [Netch (NetFilter & TUN/TAP)](https://github.com/NetchX/Netch)
- Android
- [v2rayNG](https://github.com/2dust/v2rayNG)
- [Kitsunebi](https://github.com/rurirei/Kitsunebi/tree/release_xtls)

View File

@@ -101,8 +101,8 @@ func (*staticHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
rr, _ := dns.NewRR("localhost-b. IN A 127.0.0.4")
ans.Answer = append(ans.Answer, rr)
case q.Name == "Mijia\\ Cloud." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("Mijia\\ Cloud. IN A 127.0.0.1")
case q.Name == "mijia\\ cloud." && q.Qtype == dns.TypeA:
rr, _ := dns.NewRR("mijia\\ cloud. IN A 127.0.0.1")
ans.Answer = append(ans.Answer, rr)
}
}

View File

@@ -42,6 +42,9 @@ func (m *Manager) AddHandler(ctx context.Context, handler inbound.Handler) error
tag := handler.Tag()
if len(tag) > 0 {
if _, found := m.taggedHandlers[tag]; found {
return newError("existing tag found: " + tag)
}
m.taggedHandlers[tag] = handler
} else {
m.untaggedHandler = append(m.untaggedHandler, handler)

View File

@@ -109,6 +109,9 @@ func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) erro
tag := handler.Tag()
if len(tag) > 0 {
if _, found := m.taggedHandler[tag]; found {
return newError("existing tag found: " + tag)
}
m.taggedHandler[tag] = handler
} else {
m.untaggedHandlers = append(m.untaggedHandlers, handler)

View File

@@ -157,6 +157,9 @@ func (p *StaticMuxPicker) PickAvailable() (*mux.ClientWorker, error) {
if w.draining {
continue
}
if w.client.Closed() {
continue
}
if w.client.ActiveConnections() < minConn {
minConn = w.client.ActiveConnections()
minIdx = i

View File

@@ -18,10 +18,10 @@ func init() {
common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat")))
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat")))
}
if _, err := os.Stat(platform.GetAssetLocation("geosite.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "release", "config", "geosite.dat")))
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geosite.dat"), filepath.Join(wd, "..", "..", "resources", "geosite.dat")))
}
}

View File

@@ -110,6 +110,9 @@ func (b *Buffer) BytesTo(to int32) []byte {
if to < 0 {
to += b.Len()
}
if to < 0 {
to = 0
}
return b.v[b.start : b.start+to]
}

View File

@@ -330,7 +330,7 @@ func (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
rr := s.NewReader(reader)
rr := s.NewReader(reader, &meta.Target)
err := buf.Copy(rr, s.output)
if err != nil && buf.IsWriteError(err) {
newError("failed to write to downstream. closing session ", s.ID).Base(err).WriteToLog()

View File

@@ -81,6 +81,9 @@ func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
return err
}
} else if b.UDP != nil {
b.WriteByte(byte(TargetNetworkUDP))
addrParser.WriteAddressPort(b, b.UDP.Address, b.UDP.Port)
}
len1 := b.Len()
@@ -119,7 +122,7 @@ func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
f.Option = bitmask.Byte(b.Byte(3))
f.Target.Network = net.Network_Unknown
if f.SessionStatus == SessionStatusNew {
if f.SessionStatus == SessionStatusNew || (f.SessionStatus == SessionStatusKeep && b.Len() != 4) {
if b.Len() < 8 {
return newError("insufficient buffer: ", b.Len())
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial"
)
@@ -12,13 +13,15 @@ import (
type PacketReader struct {
reader io.Reader
eof bool
dest *net.Destination
}
// NewPacketReader creates a new PacketReader.
func NewPacketReader(reader io.Reader) *PacketReader {
func NewPacketReader(reader io.Reader, dest *net.Destination) *PacketReader {
return &PacketReader{
reader: reader,
eof: false,
dest: dest,
}
}
@@ -43,6 +46,9 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return nil, err
}
r.eof = true
if r.dest != nil && r.dest.Network == net.Network_UDP {
b.UDP = r.dest
}
return buf.MultiBuffer{b}, nil
}

View File

@@ -145,7 +145,7 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
return nil
}
rr := s.NewReader(reader)
rr := s.NewReader(reader, &meta.Target)
if err := buf.Copy(rr, s.output); err != nil {
buf.Copy(rr, buf.Discard)
common.Interrupt(s.input)
@@ -168,7 +168,7 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
return buf.Copy(NewStreamReader(reader), buf.Discard)
}
rr := s.NewReader(reader)
rr := s.NewReader(reader, &meta.Target)
err := buf.Copy(rr, s.output)
if err != nil && buf.IsWriteError(err) {

View File

@@ -5,6 +5,7 @@ import (
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
)
@@ -152,9 +153,9 @@ func (s *Session) Close() error {
}
// NewReader creates a buf.Reader based on the transfer type of this Session.
func (s *Session) NewReader(reader *buf.BufferedReader) buf.Reader {
func (s *Session) NewReader(reader *buf.BufferedReader, dest *net.Destination) buf.Reader {
if s.transferType == protocol.TransferTypeStream {
return NewStreamReader(reader)
}
return NewPacketReader(reader)
return NewPacketReader(reader, dest)
}

View File

@@ -63,6 +63,9 @@ func (w *Writer) writeMetaOnly() error {
func writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error {
frame := buf.New()
if len(data) == 1 {
frame.UDP = data[0].UDP
}
if err := meta.WriteTo(frame); err != nil {
return err
}

View File

@@ -30,6 +30,7 @@ func GetAssetLocation(file string) string {
defPath,
filepath.Join("/usr/local/share/xray/", file),
filepath.Join("/usr/share/xray/", file),
filepath.Join("/opt/share/xray/", file),
} {
if _, err := os.Stat(p); os.IsNotExist(err) {
continue

View File

@@ -55,7 +55,7 @@ func TestAddressReading(t *testing.T) {
},
{
Options: []AddressOption{AddressFamilyByte(0x03, net.AddressFamilyDomain)},
Input: []byte{3, 9, 118, 50, 114, 97, 121, 46, 99, 111, 109, 0, 80},
Input: []byte{3, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109, 0, 80},
Address: net.DomainAddress("example.com"),
Port: net.Port(80),
},
@@ -84,8 +84,9 @@ func TestAddressReading(t *testing.T) {
}
for _, tc := range data {
b := buf.New()
parser := NewAddressParser(tc.Options...)
b := buf.New()
addr, port, err := parser.ReadAddressPort(b, bytes.NewReader(tc.Input))
b.Release()
if tc.Error {

137
common/xudp/xudp.go Normal file
View File

@@ -0,0 +1,137 @@
package xudp
import (
"io"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
)
var addrParser = protocol.NewAddressParser(
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6),
protocol.PortThenAddress(),
)
func NewPacketWriter(writer buf.Writer, dest net.Destination) *PacketWriter {
return &PacketWriter{
Writer: writer,
Dest: dest,
}
}
type PacketWriter struct {
Writer buf.Writer
Dest net.Destination
}
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
defer buf.ReleaseMulti(mb)
mb2Write := make(buf.MultiBuffer, 0, len(mb))
for _, b := range mb {
length := b.Len()
if length == 0 || length+666 > buf.Size {
continue
}
eb := buf.New()
eb.Write([]byte{0, 0, 0, 0})
if w.Dest.Network == net.Network_UDP {
eb.WriteByte(1) // New
eb.WriteByte(1) // Opt
eb.WriteByte(2) // UDP
addrParser.WriteAddressPort(eb, w.Dest.Address, w.Dest.Port)
w.Dest.Network = net.Network_Unknown
} else {
eb.WriteByte(2) // Keep
eb.WriteByte(1)
if b.UDP != nil {
eb.WriteByte(2)
addrParser.WriteAddressPort(eb, b.UDP.Address, b.UDP.Port)
}
}
l := eb.Len() - 2
eb.SetByte(0, byte(l>>8))
eb.SetByte(1, byte(l))
eb.WriteByte(byte(length >> 8))
eb.WriteByte(byte(length))
eb.Write(b.Bytes())
mb2Write = append(mb2Write, eb)
}
if mb2Write.IsEmpty() {
return nil
}
return w.Writer.WriteMultiBuffer(mb2Write)
}
func NewPacketReader(reader io.Reader) *PacketReader {
return &PacketReader{
Reader: reader,
cache: make([]byte, 2),
}
}
type PacketReader struct {
Reader io.Reader
cache []byte
}
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
for {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil {
return nil, err
}
l := int32(r.cache[0])<<8 | int32(r.cache[1])
if l < 4 {
return nil, io.EOF
}
b := buf.New()
if _, err := b.ReadFullFrom(r.Reader, l); err != nil {
b.Release()
return nil, err
}
discard := false
switch b.Byte(2) {
case 2:
if l != 4 {
b.Advance(5)
addr, port, err := addrParser.ReadAddressPort(nil, b)
if err != nil {
b.Release()
return nil, err
}
b.UDP = &net.Destination{
Network: net.Network_UDP,
Address: addr,
Port: port,
}
}
case 4:
discard = true
default:
b.Release()
return nil, io.EOF
}
if b.Byte(3) == 1 {
if _, err := io.ReadFull(r.Reader, r.cache); err != nil {
b.Release()
return nil, err
}
length := int32(r.cache[0])<<8 | int32(r.cache[1])
if length > 0 {
b.Clear()
if _, err := b.ReadFullFrom(r.Reader, length); err != nil {
b.Release()
return nil, err
}
if !discard {
return buf.MultiBuffer{b}, nil
}
}
}
b.Release()
}
}

View File

@@ -22,9 +22,13 @@ type ConfigFormat struct {
// ConfigLoader is a utility to load Xray config from external source.
type ConfigLoader func(input interface{}) (*Config, error)
// ConfigBuilder is a builder to build core.Config from filenames and formats
type ConfigBuilder func(files []string, formats []string) (*Config, error)
var (
configLoaderByName = make(map[string]*ConfigFormat)
configLoaderByExt = make(map[string]*ConfigFormat)
configLoaderByName = make(map[string]*ConfigFormat)
configLoaderByExt = make(map[string]*ConfigFormat)
ConfigBuilderForFiles ConfigBuilder
)
// RegisterConfigLoader add a new ConfigLoader.
@@ -46,6 +50,21 @@ func RegisterConfigLoader(format *ConfigFormat) error {
return nil
}
func GetFormatByExtension(ext string) string {
switch strings.ToLower(ext) {
case "pb", "protobuf":
return "protobuf"
case "yaml", "yml":
return "yaml"
case "toml":
return "toml"
case "json":
return "json"
default:
return ""
}
}
func getExtension(filename string) string {
idx := strings.LastIndexByte(filename, '.')
if idx == -1 {
@@ -54,23 +73,48 @@ func getExtension(filename string) string {
return filename[idx+1:]
}
// LoadConfig loads config with given format from given source.
// input accepts 2 different types:
// * []string slice of multiple filename/url(s) to open to read
// * io.Reader that reads a config content (the original way)
func LoadConfig(formatName string, filename string, input interface{}) (*Config, error) {
ext := getExtension(filename)
if len(ext) > 0 {
if f, found := configLoaderByExt[ext]; found {
return f.Loader(input)
func getFormat(filename string) string {
return GetFormatByExtension(getExtension(filename))
}
func LoadConfig(formatName string, input interface{}) (*Config, error) {
switch v := input.(type) {
case cmdarg.Arg:
formats := make([]string, len(v))
hasProtobuf := false
for i, file := range v {
f := getFormat(file)
if f == "" {
f = formatName
}
if f == "protobuf" {
hasProtobuf = true
}
formats[i] = f
}
// only one protobuf config file is allowed
if hasProtobuf {
if len(v) == 1 {
return configLoaderByName["protobuf"].Loader(v)
} else {
return nil, newError("Only one protobuf config file is allowed").AtWarning()
}
}
// to avoid import cycle
return ConfigBuilderForFiles(v, formats)
case io.Reader:
if f, found := configLoaderByName[formatName]; found {
return f.Loader(v)
} else {
return nil, newError("Unable to load config in", formatName).AtWarning()
}
}
if f, found := configLoaderByName[formatName]; found {
return f.Loader(input)
}
return nil, newError("Unable to load config in ", formatName).AtWarning()
return nil, newError("Unable to load config").AtWarning()
}
func loadProtobufConfig(data []byte) (*Config, error) {

View File

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

View File

@@ -25,7 +25,7 @@ func CreateObject(v *Instance, config interface{}) (interface{}, error) {
//
// xray:api:stable
func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
config, err := LoadConfig(configFormat, "", bytes.NewReader(configBytes))
config, err := LoadConfig(configFormat, bytes.NewReader(configBytes))
if err != nil {
return nil, err
}

View File

@@ -2,14 +2,10 @@ package core
import (
"context"
"os"
"reflect"
"runtime/debug"
"strings"
"sync"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/features"
@@ -184,30 +180,7 @@ func NewWithContext(ctx context.Context, config *Config) (*Instance, error) {
}
func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
cone := true
v, t := false, false
for _, outbound := range config.Outbound {
s := strings.ToLower(outbound.ProxySettings.Type)
l := len(s)
if l >= 16 && s[11:16] == "vless" || l >= 16 && s[11:16] == "vmess" {
v = true
continue
}
if l >= 17 && s[11:17] == "trojan" || l >= 22 && s[11:22] == "shadowsocks" {
t = true
var m proxyman.SenderConfig
proto.Unmarshal(outbound.SenderSettings.Value, &m)
if m.MultiplexSettings != nil && m.MultiplexSettings.Enabled {
cone = false
break
}
}
}
if v && !t {
cone = false
}
server.ctx = context.WithValue(server.ctx, "cone", cone)
defer debug.FreeOSMemory()
server.ctx = context.WithValue(server.ctx, "cone", os.Getenv("XRAY_CONE_DISABLED") != "true")
if config.Transport != nil {
features.PrintDeprecatedFeatureWarning("global transport settings")

18
go.mod
View File

@@ -4,23 +4,23 @@ go 1.15
require (
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/golang/mock v1.4.4
github.com/golang/mock v1.5.0
github.com/golang/protobuf v1.4.3
github.com/google/go-cmp v0.5.4
github.com/gorilla/websocket v1.4.2
github.com/lucas-clemente/quic-go v0.19.3
github.com/miekg/dns v1.1.35
github.com/miekg/dns v1.1.40
github.com/pelletier/go-toml v1.8.1
github.com/pires/go-proxyproto v0.4.1
github.com/pires/go-proxyproto v0.4.2
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.7.0
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
go.starlark.net v0.0.0-20210121225809-cea917ab6e0f
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
google.golang.org/grpc v1.35.0
go.starlark.net v0.0.0-20210223155950-e043a3d3c984
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b
google.golang.org/grpc v1.36.0
google.golang.org/protobuf v1.25.0
h12.io/socks v1.0.2
)

45
go.sum
View File

@@ -49,8 +49,9 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -69,6 +70,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
@@ -107,8 +109,8 @@ github.com/marten-seemann/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07Vxb
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA=
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
@@ -127,8 +129,8 @@ github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNC
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pires/go-proxyproto v0.4.1 h1:30QkyOjKU3FcTLiu1359sSQ7ml56wpM4i/uViqODSsI=
github.com/pires/go-proxyproto v0.4.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pires/go-proxyproto v0.4.2 h1:VRAvsUCTrmiahoU5fqQqkbY0GWcJ1Q0F7b7CkFaipSU=
github.com/pires/go-proxyproto v0.4.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -169,7 +171,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -180,8 +181,8 @@ github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 h1:QHESTXtfgc1ABV+ArlbPVqU
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.starlark.net v0.0.0-20210121225809-cea917ab6e0f h1:MfDkeyR3bphbh1zJ3Z7cTsZ8Ydd4mXQiBEhcZRltwaM=
go.starlark.net v0.0.0-20210121225809-cea917ab6e0f/go.mod h1:vxxlMsgCAPH7BR2LtxjJC4WhhZhCGd/b01+CIpj8H4k=
go.starlark.net v0.0.0-20210223155950-e043a3d3c984 h1:xwwDQW5We85NaTk2APgoN9202w/l0DVGp+GZMfsrh7s=
go.starlark.net v0.0.0-20210223155950-e043a3d3c984/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -190,14 +191,15 @@ 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-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-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -212,8 +214,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-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-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/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-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -225,8 +227,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -242,10 +244,10 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b h1:kHlr0tATeLRMEiZJu5CknOw/E8V6h69sXXQFGoPtjcc=
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -264,10 +266,13 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
@@ -292,8 +297,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -21,7 +21,7 @@ func init() {
common.Must(err)
if _, err := os.Stat(platform.GetAssetLocation("geoip.dat")); err != nil && os.IsNotExist(err) {
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "release", "config", "geoip.dat")))
common.Must(filesystem.CopyFile(platform.GetAssetLocation("geoip.dat"), filepath.Join(wd, "..", "..", "resources", "geoip.dat")))
}
geositeFilePath := filepath.Join(wd, "geosite.dat")
@@ -112,6 +112,11 @@ func TestDNSConfigParsing(t *testing.T) {
Domain: "example.com",
ProxiedDomain: "google.com",
},
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}},
},
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
@@ -127,11 +132,6 @@ func TestDNSConfigParsing(t *testing.T) {
Domain: ".*\\.com",
Ip: [][]byte{{8, 8, 4, 4}},
},
{
Type: dns.DomainMatchingType_Full,
Domain: "example.com",
Ip: [][]byte{{127, 0, 0, 1}},
},
},
ClientIp: []byte{10, 0, 0, 1},
},

View File

@@ -0,0 +1,44 @@
package serial
import (
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/main/confloader"
"io"
)
func BuildConfig(files []string, formats []string) (*core.Config, error) {
cf := &conf.Config{}
for i, file := range files {
newError("Reading config: ", file).AtInfo().WriteToLog()
r, err := confloader.LoadConfig(file)
if err != nil {
return nil, newError("failed to read config: ", file).Base(err)
}
c, err := ReaderDecoderByFormat[formats[i]](r)
if err != nil {
return nil, newError("failed to decode config: ", file).Base(err)
}
if i == 0 {
*cf = *c
continue
}
cf.Override(c, file)
}
return cf.Build()
}
type readerDecoder func(io.Reader) (*conf.Config, error)
var (
ReaderDecoderByFormat = make(map[string]readerDecoder)
)
func init() {
ReaderDecoderByFormat["json"] = DecodeJSONConfig
ReaderDecoderByFormat["yaml"] = DecodeYAMLConfig
ReaderDecoderByFormat["toml"] = DecodeTOMLConfig
core.ConfigBuilderForFiles = BuildConfig
}

View File

@@ -247,12 +247,13 @@ func readFileOrString(f string, s []string) ([]byte, error) {
}
type TLSCertConfig struct {
CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"`
CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
OcspStapling uint64 `json:"ocspStapling"`
OneTimeLoading bool `json:"oneTimeLoading"`
}
// Build implements Buildable.
@@ -264,6 +265,7 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
return nil, newError("failed to parse certificate").Base(err)
}
certificate.Certificate = cert
certificate.CertificatePath = c.CertFile
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr)
@@ -271,6 +273,7 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
return nil, newError("failed to parse key").Base(err)
}
certificate.Key = key
certificate.KeyPath = c.KeyFile
}
switch strings.ToLower(c.Usage) {
@@ -283,7 +286,11 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
default:
certificate.Usage = tls.Certificate_ENCIPHERMENT
}
if certificate.KeyPath == "" && certificate.CertificatePath == "" {
certificate.OneTimeLoading = true
} else {
certificate.OneTimeLoading = c.OneTimeLoading
}
certificate.OcspStapling = c.OcspStapling
return certificate, nil
@@ -331,23 +338,24 @@ func (c *TLSConfig) Build() (proto.Message, error) {
}
type XTLSCertConfig struct {
CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
OcspStapling int64 `json:"ocspStapling"`
CertFile string `json:"certificateFile"`
CertStr []string `json:"certificate"`
KeyFile string `json:"keyFile"`
KeyStr []string `json:"key"`
Usage string `json:"usage"`
OcspStapling uint64 `json:"ocspStapling"`
OneTimeLoading bool `json:"oneTimeLoading"`
}
// Build implements Buildable.
func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
certificate := new(xtls.Certificate)
cert, err := readFileOrString(c.CertFile, c.CertStr)
if err != nil {
return nil, newError("failed to parse certificate").Base(err)
}
certificate.Certificate = cert
certificate.CertificatePath = c.CertFile
if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
key, err := readFileOrString(c.KeyFile, c.KeyStr)
@@ -355,6 +363,7 @@ func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
return nil, newError("failed to parse key").Base(err)
}
certificate.Key = key
certificate.KeyPath = c.KeyFile
}
switch strings.ToLower(c.Usage) {
@@ -367,7 +376,11 @@ func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
default:
certificate.Usage = xtls.Certificate_ENCIPHERMENT
}
if certificate.KeyPath == "" && certificate.CertificatePath == "" {
certificate.OneTimeLoading = true
} else {
certificate.OneTimeLoading = c.OneTimeLoading
}
certificate.OcspStapling = c.OcspStapling
return certificate, nil

View File

@@ -11,13 +11,11 @@ import (
"regexp"
"runtime"
"runtime/debug"
"strings"
"syscall"
"github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/main/commands/base"
)
@@ -83,9 +81,11 @@ func executeRun(cmd *base.Command, args []string) {
}
defer server.Close()
conf.FileCache = nil
conf.IPCache = nil
conf.SiteCache = nil
/*
conf.FileCache = nil
conf.IPCache = nil
conf.SiteCache = nil
*/
// Explicitly triggering GC to remove garbage from config loading.
runtime.GC()
@@ -158,30 +158,25 @@ func getConfigFilePath() cmdarg.Arg {
}
func getConfigFormat() string {
switch strings.ToLower(*format) {
case "pb", "protobuf":
return "protobuf"
case "yaml", "yml":
return "yaml"
case "toml":
return "toml"
default:
return "json"
f := core.GetFormatByExtension(*format)
if f == "" {
f = "json"
}
return f
}
func startXray() (core.Server, error) {
configFiles := getConfigFilePath()
config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
//config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
//config, err := core.LoadConfigs(getConfigFormat(), configFiles)
c, err := core.LoadConfig(getConfigFormat(), configFiles)
if err != nil {
return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err)
}
server, err := core.New(config)
server, err := core.New(c)
if err != nil {
return nil, newError("failed to create server").Base(err)
}

View File

@@ -97,13 +97,16 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return newError("target not specified.")
}
destination := outbound.Target
UDPOverride := net.UDPDestination(nil, 0)
if h.config.DestinationOverride != nil {
server := h.config.DestinationOverride.Server
if isValidAddress(server.Address) {
destination.Address = server.Address.AsAddress()
UDPOverride.Address = destination.Address
}
if server.Port != 0 {
destination.Port = net.Port(server.Port)
UDPOverride.Port = destination.Port
}
}
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
@@ -149,7 +152,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if destination.Network == net.Network_TCP {
writer = buf.NewWriter(conn)
} else {
writer = NewPacketWriter(conn, h, ctx)
writer = NewPacketWriter(conn, h, ctx, UDPOverride)
}
if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {
@@ -226,7 +229,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return buf.MultiBuffer{b}, nil
}
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context) buf.Writer {
func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride net.Destination) buf.Writer {
iConn := conn
statConn, ok := iConn.(*internet.StatCouterConnection)
if ok {
@@ -242,6 +245,7 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context) buf.Writer
Counter: counter,
Handler: h,
Context: ctx,
UDPOverride: UDPOverride,
}
}
return &buf.SequentialWriter{Writer: conn}
@@ -252,6 +256,7 @@ type PacketWriter struct {
stats.Counter
*Handler
context.Context
UDPOverride net.Destination
}
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
@@ -264,6 +269,12 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
var n int
var err error
if b.UDP != nil {
if w.UDPOverride.Address != nil {
b.UDP.Address = w.UDPOverride.Address
}
if w.UDPOverride.Port != 0 {
b.UDP.Port = w.UDPOverride.Port
}
if w.Handler.config.useIP() && b.UDP.Address.Family().IsDomain() {
ip := w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
if ip != nil {

View File

@@ -7,6 +7,8 @@ import (
"crypto/md5"
"crypto/sha1"
"io"
"reflect"
"strconv"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf"
@@ -31,6 +33,31 @@ func (a *MemoryAccount) Equals(another protocol.Account) bool {
return false
}
func (a *MemoryAccount) GetCipherName() string {
switch a.Cipher.(type) {
case *AesCfb:
keyBytes := a.Cipher.(*AesCfb).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_CFB"
case *ChaCha20:
if a.Cipher.(*ChaCha20).IVBytes == 8 {
return "CHACHA20"
}
return "CHACHA20_IETF"
case *AEADCipher:
switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
case reflect.ValueOf(createAesGcm).Pointer():
keyBytes := a.Cipher.(*AEADCipher).KeyBytes
return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
case reflect.ValueOf(createChacha20Poly1305).Pointer():
return "CHACHA20_POLY1305"
}
case *NoneCipher:
return "NONE"
}
return ""
}
func createAesGcm(key []byte) cipher.AEAD {
block, err := aes.NewCipher(key)
common.Must(err)

View File

@@ -54,12 +54,9 @@ func (r *FullReader) Read(p []byte) (n int, err error) {
}
// ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
user := users[0]
account := user.Account.(*MemoryAccount)
func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
hashkdf.Write(account.Key)
behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
@@ -71,10 +68,20 @@ func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.R
readSizeRemain := DrainSize
var r2 buf.Reader
buffer := buf.New()
defer buffer.Release()
if len(users) > 1 {
buffer := buf.New()
defer buffer.Release()
var user *protocol.MemoryUser
var ivLen int32
var err error
count := validator.Count()
if count == 0 {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("invalid user")
} else if count > 1 {
var aead cipher.AEAD
if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
readSizeRemain -= int(buffer.Len())
@@ -83,45 +90,26 @@ func ReadTCPSession(users []*protocol.MemoryUser, reader io.Reader) (*protocol.R
}
bs := buffer.Bytes()
user, aead, _, ivLen, err = validator.Get(bs, protocol.RequestCommandTCP)
var aeadCipher *AEADCipher
var ivLen int32
subkey := make([]byte, 32)
length := make([]byte, 16)
var aead cipher.AEAD
var err error
for _, user = range users {
account = user.Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
_, err = aead.Open(length[:0], length[4:16], bs[ivLen:ivLen+18], nil)
if err == nil {
reader = &FullReader{reader, bs[ivLen:]}
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: crypto.GenerateInitialAEADNonce(),
}
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream, nil)
break
if user != nil {
reader = &FullReader{reader, bs[ivLen:]}
auth := &crypto.AEADAuthenticator{
AEAD: aead,
NonceGenerator: crypto.GenerateInitialAEADNonce(),
}
}
if err != nil {
r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
Auth: auth,
}, reader, protocol.TransferTypeStream, nil)
} else {
readSizeRemain -= int(buffer.Len())
DrainConnN(reader, readSizeRemain)
return nil, nil, newError("failed to match an user").Base(err)
}
}
buffer := buf.New()
defer buffer.Release()
if r2 == nil {
ivLen := account.Cipher.IVSize()
} else {
user, ivLen = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
hashkdf.Write(account.Key)
var iv []byte
if ivLen > 0 {
if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
@@ -261,40 +249,31 @@ func EncodeUDPPacket(request *protocol.RequestHeader, payload []byte) (*buf.Buff
return buffer, nil
}
func DecodeUDPPacket(users []*protocol.MemoryUser, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) {
bs := payload.Bytes()
if len(bs) <= 32 {
return nil, nil, newError("len(bs) <= 32")
}
var user *protocol.MemoryUser
var account *MemoryAccount
var err error
if len(users) > 1 {
bs := payload.Bytes()
if len(bs) <= 32 {
return nil, nil, newError("len(bs) <= 32")
}
var aeadCipher *AEADCipher
var ivLen int32
subkey := make([]byte, 32)
data := make([]byte, 8192)
var aead cipher.AEAD
count := validator.Count()
if count == 0 {
return nil, nil, newError("invalid user")
} else if count > 1 {
var d []byte
for _, user = range users {
account = user.Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
d, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
if err == nil {
payload.Clear()
payload.Write(d)
break
}
user, _, d, _, err = validator.Get(bs, protocol.RequestCommandUDP)
if user != nil {
payload.Clear()
payload.Write(d)
} else {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
} else {
user = users[0]
account = user.Account.(*MemoryAccount)
user, _ = validator.GetOnlyUser()
account := user.Account.(*MemoryAccount)
var iv []byte
if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
@@ -302,12 +281,9 @@ func DecodeUDPPacket(users []*protocol.MemoryUser, payload *buf.Buffer) (*protoc
iv = make([]byte, account.Cipher.IVSize())
copy(iv, payload.BytesTo(account.Cipher.IVSize()))
}
err = account.Cipher.DecodePacket(account.Key, payload)
}
if err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
return nil, nil, newError("failed to decrypt UDP payload").Base(err)
}
}
request := &protocol.RequestHeader{
@@ -341,7 +317,10 @@ func (v *UDPReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer.Release()
return nil, err
}
u, payload, err := DecodeUDPPacket([]*protocol.MemoryUser{v.User}, buffer)
validator := new(Validator)
validator.Add(v.User)
u, payload, err := DecodeUDPPacket(validator, buffer)
if err != nil {
buffer.Release()
return nil, err

View File

@@ -38,14 +38,16 @@ func TestUDPEncoding(t *testing.T) {
encodedData, err := EncodeUDPPacket(request, data.Bytes())
common.Must(err)
decodedRequest, decodedData, err := DecodeUDPPacket([]*protocol.MemoryUser{request.User}, encodedData)
validator := new(Validator)
validator.Add(request.User)
decodedRequest, decodedData, err := DecodeUDPPacket(validator, encodedData)
common.Must(err)
if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" {
t.Error("data: ", r)
}
if r := cmp.Diff(decodedRequest, request); r != "" {
if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" {
t.Error("request: ", r)
}
}
@@ -117,9 +119,11 @@ func TestTCPRequest(t *testing.T) {
common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
decodedRequest, reader, err := ReadTCPSession([]*protocol.MemoryUser{request.User}, cache)
validator := new(Validator)
validator.Add(request.User)
decodedRequest, reader, err := ReadTCPSession(validator, cache)
common.Must(err)
if r := cmp.Diff(decodedRequest, request); r != "" {
if r := cmp.Diff(decodedRequest, request, cmp.Comparer(func(a1, a2 protocol.Account) bool { return a1.Equals(a2) })); r != "" {
t.Error("request: ", r)
}

View File

@@ -22,35 +22,46 @@ import (
type Server struct {
config *ServerConfig
users []*protocol.MemoryUser
validator *Validator
policyManager policy.Manager
cone bool
}
// NewServer create a new Shadowsocks server.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if config.Users == nil {
return nil, newError("empty users")
validator := new(Validator)
for _, user := range config.Users {
u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to get shadowsocks user").Base(err).AtError()
}
if err := validator.Add(u); err != nil {
return nil, newError("failed to add user").Base(err).AtError()
}
}
v := core.MustFromContext(ctx)
s := &Server{
config: config,
validator: validator,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
for _, user := range config.Users {
u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to parse user account").Base(err)
}
s.users = append(s.users, u)
}
return s, nil
}
// AddUser implements proxy.UserManager.AddUser().
func (s *Server) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
return s.validator.Add(u)
}
// RemoveUser implements proxy.UserManager.RemoveUser().
func (s *Server) RemoveUser(ctx context.Context, e string) error {
return s.validator.Del(e)
}
func (s *Server) Network() []net.Network {
list := s.config.Network
if len(list) == 0 {
@@ -64,13 +75,13 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
case net.Network_TCP:
return s.handleConnection(ctx, conn, dispatcher)
case net.Network_UDP:
return s.handlerUDPPayload(ctx, conn, dispatcher)
return s.handleUDPPayload(ctx, conn, dispatcher)
default:
return newError("unknown network: ", network)
}
}
func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error {
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
request := protocol.RequestHeaderFromContext(ctx)
if request == nil {
@@ -102,8 +113,9 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
if inbound == nil {
panic("no inbound metadata")
}
if len(s.users) == 1 {
inbound.User = s.users[0]
if s.validator.Count() == 1 {
inbound.User, _ = s.validator.GetOnlyUser()
}
var dest *net.Destination
@@ -121,9 +133,11 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
var err error
if inbound.User != nil {
request, data, err = DecodeUDPPacket([]*protocol.MemoryUser{inbound.User}, payload)
validator := new(Validator)
validator.Add(inbound.User)
request, data, err = DecodeUDPPacket(validator, payload)
} else {
request, data, err = DecodeUDPPacket(s.users, payload)
request, data, err = DecodeUDPPacket(s.validator, payload)
if err == nil {
inbound.User = request.User
}
@@ -178,7 +192,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
}
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
request, bodyReader, err := ReadTCPSession(s.users, &bufferedReader)
request, bodyReader, err := ReadTCPSession(s.validator, &bufferedReader)
if err != nil {
log.Record(&log.AccessMessage{
From: conn.RemoteAddr(),

View File

@@ -0,0 +1,113 @@
package shadowsocks
import (
"crypto/cipher"
"strings"
"sync"
"github.com/xtls/xray-core/common/protocol"
)
// Validator stores valid Shadowsocks users.
type Validator struct {
// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.
email sync.Map
users sync.Map
}
// Add a Shadowsocks user, Email must be empty or unique.
func (v *Validator) Add(u *protocol.MemoryUser) error {
account := u.Account.(*MemoryAccount)
if !account.Cipher.IsAEAD() && v.Count() > 0 {
return newError("The cipher do not support Single-port Multi-user")
}
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
return newError("User ", u.Email, " already exists.")
}
}
v.users.Store(string(account.Key)+"&"+account.GetCipherName(), u)
return nil
}
// Del a Shadowsocks user with a non-empty Email.
func (v *Validator) Del(e string) error {
if e == "" {
return newError("Email must not be empty.")
}
le := strings.ToLower(e)
u, _ := v.email.Load(le)
if u == nil {
return newError("User ", e, " not found.")
}
account := u.(*protocol.MemoryUser).Account.(*MemoryAccount)
v.email.Delete(le)
v.users.Delete(string(account.Key) + "&" + account.GetCipherName())
return nil
}
// Count the number of Shadowsocks users
func (v *Validator) Count() int {
length := 0
v.users.Range(func(_, _ interface{}) bool {
length++
return true
})
return length
}
// Get a Shadowsocks user and the user's cipher.
func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) {
var dataSize int
switch command {
case protocol.RequestCommandTCP:
dataSize = 16
case protocol.RequestCommandUDP:
dataSize = 8192
}
var aeadCipher *AEADCipher
subkey := make([]byte, 32)
data := make([]byte, dataSize)
v.users.Range(func(key, user interface{}) bool {
account := user.(*protocol.MemoryUser).Account.(*MemoryAccount)
aeadCipher = account.Cipher.(*AEADCipher)
ivLen = aeadCipher.IVSize()
subkey = subkey[:aeadCipher.KeyBytes]
hkdfSHA1(account.Key, bs[:ivLen], subkey)
aead = aeadCipher.AEADAuthCreator(subkey)
switch command {
case protocol.RequestCommandTCP:
ret, err = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil)
case protocol.RequestCommandUDP:
ret, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
}
if err == nil {
u = user.(*protocol.MemoryUser)
return false
}
return true
})
return
}
// Get the only user without authentication
func (v *Validator) GetOnlyUser() (u *protocol.MemoryUser, ivLen int32) {
v.users.Range(func(_, user interface{}) bool {
u = user.(*protocol.MemoryUser)
return false
})
ivLen = u.Account.(*MemoryAccount).Cipher.IVSize()
return
}

View File

@@ -422,16 +422,6 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
defer b.Release()
common.Must2(b.Write([]byte{socks5Version, 0x01, authByte}))
if authByte == authPassword {
account := request.User.Account.(*Account)
common.Must(b.WriteByte(0x01))
common.Must(b.WriteByte(byte(len(account.Username))))
common.Must2(b.WriteString(account.Username))
common.Must(b.WriteByte(byte(len(account.Password))))
common.Must2(b.WriteString(account.Password))
}
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
return nil, err
}
@@ -449,6 +439,17 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
}
if authByte == authPassword {
b.Clear()
account := request.User.Account.(*Account)
common.Must(b.WriteByte(0x01))
common.Must(b.WriteByte(byte(len(account.Username))))
common.Must2(b.WriteString(account.Username))
common.Must(b.WriteByte(byte(len(account.Password))))
common.Must2(b.WriteString(account.Password))
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {
return nil, err
}
b.Clear()
if _, err := b.ReadFullFrom(reader, 2); err != nil {
return nil, err
@@ -465,8 +466,12 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
command = byte(cmdUDPAssociate)
}
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
return nil, err
if request.Command == protocol.RequestCommandUDP {
common.Must2(b.Write([]byte{1, 0, 0, 0, 0, 0, 0 /* RFC 1928 */}))
} else {
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
return nil, err
}
}
if err := buf.WriteAllBytes(writer, b.Bytes()); err != nil {

View File

@@ -500,19 +500,16 @@ func (s *Server) fallback(ctx context.Context, sid errors.ExportOption, err erro
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 {
var remoteAddr, remotePort, localAddr, localPort string
ipType, network := 0, connection.RemoteAddr().Network()
if len(network) >= 3 && network[:3] == "tcp" {
var err error
remoteAddr, remotePort, err = net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
return err
}
localAddr, localPort, err = net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
return err
}
ipType = 4
ipType := 4
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
ipType = 0
}
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
ipType = 0
}
if ipType == 4 {
for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' {
ipType = 6

View File

@@ -335,19 +335,16 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if fb.Xver != 0 {
var remoteAddr, remotePort, localAddr, localPort string
ipType, network := 0, connection.RemoteAddr().Network()
if len(network) >= 3 && network[:3] == "tcp" {
var err error
remoteAddr, remotePort, err = net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
return err
}
localAddr, localPort, err = net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
return err
}
ipType = 4
ipType := 4
remoteAddr, remotePort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
ipType = 0
}
localAddr, localPort, err := net.SplitHostPort(connection.LocalAddr().String())
if err != nil {
ipType = 0
}
if ipType == 4 {
for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' {
ipType = 6

View File

@@ -16,6 +16,7 @@ import (
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/features/stats"
@@ -48,6 +49,7 @@ type Handler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
policyManager policy.Manager
cone bool
}
// New creates a new VLess outbound handler.
@@ -66,6 +68,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
return handler, nil
@@ -175,6 +178,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
clientReader := link.Reader // .(*pipe.Reader)
clientWriter := link.Writer // .(*pipe.Writer)
if request.Command == protocol.RequestCommandUDP && h.cone {
request.Command = protocol.RequestCommandMux
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = net.Port(666)
}
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
@@ -185,6 +194,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
// default: serverWriter := bufferWriter
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
serverWriter = xudp.NewPacketWriter(serverWriter, target)
}
if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return err // ...
}
@@ -216,6 +228,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
// default: serverReader := buf.NewReader(conn)
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
serverReader = xudp.NewPacketReader(conn)
}
if rawConn != nil {
var counter stats.Counter

View File

@@ -6,11 +6,20 @@ import (
"hash"
)
type hash2 struct {
hash.Hash
}
func KDF(key []byte, path ...string) []byte {
hmacf := hmac.New(sha256.New, []byte(KDFSaltConstVMessAEADKDF))
for _, v := range path {
first := true
hmacf = hmac.New(func() hash.Hash {
if first {
first = false
return hash2{hmacf}
}
return hmacf
}, []byte(v))
}

View File

@@ -15,6 +15,7 @@ import (
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/common/xudp"
core "github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/policy"
"github.com/xtls/xray-core/proxy/vmess"
@@ -28,6 +29,7 @@ type Handler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
policyManager policy.Manager
cone bool
}
// New creates a new VMess outbound handler.
@@ -46,6 +48,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
return handler, nil
@@ -122,6 +125,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
if request.Command == protocol.RequestCommandUDP && h.cone {
request.Command = protocol.RequestCommandMux
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = net.Port(666)
}
requestDone := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
@@ -131,6 +140,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
bodyWriter := session.EncodeRequestBody(request, writer)
bodyWriter2 := bodyWriter
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
bodyWriter = xudp.NewPacketWriter(bodyWriter, target)
}
if err := buf.CopyOnceTimeout(input, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return newError("failed to write first payload").Base(err)
}
@@ -144,7 +157,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
if request.Option.Has(protocol.RequestOptionChunkStream) {
if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
if err := bodyWriter2.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
return err
}
}
@@ -163,6 +176,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
h.handleCommand(rec.Destination(), header.Command)
bodyReader := session.DecodeResponseBody(request, reader)
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
bodyReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: bodyReader})
}
return buf.Copy(bodyReader, output, buf.UpdateActivity(timer))
}

View File

@@ -118,7 +118,7 @@ func genTestBinaryPath() {
}
func GetSourcePath() string {
return filepath.Join("example.com", "core", "main")
return filepath.Join("github.com", "xtls", "xray-core", "main")
}
func CloseAllServers(servers []*exec.Cmd) {

View File

@@ -17,6 +17,8 @@ func BuildXray() error {
fmt.Printf("Building Xray into path (%s)\n", testBinaryPath)
cmd := exec.Command("go", "build", "-o="+testBinaryPath, GetSourcePath())
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

View File

@@ -583,7 +583,7 @@ func TestHTTP2(t *testing.T) {
var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*40))
}
if err := errg.Wait(); err != nil {
t.Error(err)

View File

@@ -11,6 +11,7 @@ import (
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe"
@@ -22,7 +23,7 @@ var (
globalDialerAccess sync.Mutex
)
func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config) (*http.Client, error) {
func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.Config, sockopt *internet.SocketConfig) (*http.Client, error) {
globalDialerAccess.Lock()
defer globalDialerAccess.Unlock()
@@ -49,17 +50,24 @@ func getHTTPClient(ctx context.Context, dest net.Destination, tlsSettings *tls.C
}
address := net.ParseAddress(rawHost)
pconn, err := internet.DialSystem(ctx, net.TCPDestination(address, port), nil)
dctx := context.Background()
dctx = session.ContextWithID(dctx, session.IDFromContext(ctx))
dctx = session.ContextWithOutbound(dctx, session.OutboundFromContext(ctx))
pconn, err := internet.DialSystem(dctx, net.TCPDestination(address, port), sockopt)
if err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err
}
cn := gotls.Client(pconn, tlsConfig)
if err := cn.Handshake(); err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err
}
if !tlsConfig.InsecureSkipVerify {
if err := cn.VerifyHostname(tlsConfig.ServerName); err != nil {
newError("failed to dial to " + addr).Base(err).AtError().WriteToLog()
return nil, err
}
}
@@ -90,7 +98,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if tlsConfig == nil {
return nil, newError("TLS must be enabled for http transport.").AtWarning()
}
client, err := getHTTPClient(ctx, dest, tlsConfig)
client, err := getHTTPClient(ctx, dest, tlsConfig, streamSettings.SocketSettings)
if err != nil {
return nil, err
}

View File

@@ -73,10 +73,10 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
l.listener = listener
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
l.tlsConfig = config.GetTLSConfig(tls.WithNextProto("h2"))
l.tlsConfig = config.GetTLSConfig()
}
if config := xtls.ConfigFromStreamSettings(streamSettings); config != nil {
l.xtlsConfig = config.GetXTLSConfig(xtls.WithNextProto("h2"))
l.xtlsConfig = config.GetXTLSConfig()
}
if tcpSettings.HeaderSettings != nil {

View File

@@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp"
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet"
)
@@ -42,8 +43,8 @@ func (c *Config) loadSelfCertPool() (*x509.CertPool, error) {
}
// BuildCertificates builds a list of TLS certificates from proto definition.
func (c *Config) BuildCertificates() []tls.Certificate {
certs := make([]tls.Certificate, 0, len(c.Certificate))
func (c *Config) BuildCertificates() []*tls.Certificate {
certs := make([]*tls.Certificate, 0, len(c.Certificate))
for _, entry := range c.Certificate {
if entry.Usage != Certificate_ENCIPHERMENT {
continue
@@ -53,19 +54,62 @@ func (c *Config) BuildCertificates() []tls.Certificate {
newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, keyPair)
if entry.OcspStapling != 0 {
go func(cert *tls.Certificate) {
t := time.NewTicker(time.Duration(entry.OcspStapling) * time.Second)
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if err != nil {
newError("ignoring invalid certificate").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, &keyPair)
if !entry.OneTimeLoading {
var isOcspstapling bool
hotReloadCertInterval := uint64(3600)
if entry.OcspStapling != 0 {
hotReloadCertInterval = entry.OcspStapling
isOcspstapling = true
}
index := len(certs) - 1
go func(cert *tls.Certificate, index int) {
t := time.NewTicker(time.Duration(hotReloadCertInterval) * 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
if entry.CertificatePath != "" && entry.KeyPath != "" {
newCert, err := filesystem.ReadFile(entry.CertificatePath)
if err != nil {
newError("failed to parse certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
newKey, err := filesystem.ReadFile(entry.KeyPath)
if err != nil {
newError("failed to parse key").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if string(newCert) != string(entry.Certificate) && string(newKey) != string(entry.Key) {
newKeyPair, err := tls.X509KeyPair(newCert, newKey)
if err != nil {
newError("ignoring invalid X509 key pair").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if newKeyPair.Leaf, err = x509.ParseCertificate(newKeyPair.Certificate[0]); err != nil {
newError("ignoring invalid certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
cert = &newKeyPair
}
}
if isOcspstapling {
if newOCSPData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newOCSPData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newOCSPData
}
}
certs[index] = cert
<-t.C
}
}(&certs[len(certs)-1])
}(certs[len(certs)-1], index)
}
}
return certs
@@ -169,6 +213,33 @@ func getGetCertificateFunc(c *tls.Config, ca []*Certificate) func(hello *tls.Cli
}
}
func getNewGetCertficateFunc(certs []*tls.Certificate) func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
return func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if len(certs) == 0 {
return nil, newError("empty certs")
}
sni := strings.ToLower(hello.ServerName)
if len(certs) == 1 || sni == "" {
return certs[0], nil
}
gsni := "*"
if index := strings.IndexByte(sni, '.'); index != -1 {
gsni += sni[index:]
}
for _, keyPair := range certs {
if keyPair.Leaf.Subject.CommonName == sni || keyPair.Leaf.Subject.CommonName == gsni {
return keyPair, nil
}
for _, name := range keyPair.Leaf.DNSNames {
if name == sni || name == gsni {
return keyPair, nil
}
}
}
return certs[0], nil
}
}
func (c *Config) IsExperiment8357() bool {
return strings.HasPrefix(c.ServerName, exp8357)
}
@@ -210,12 +281,11 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
opt(config)
}
config.Certificates = c.BuildCertificates()
config.BuildNameToCertificate()
caCerts := c.getCustomCA()
if len(caCerts) > 0 {
config.GetCertificate = getGetCertificateFunc(config, caCerts)
} else {
config.GetCertificate = getNewGetCertficateFunc(c.BuildCertificates())
}
if sn := c.parseServerName(); len(sn) > 0 {

View File

@@ -84,7 +84,13 @@ type Certificate struct {
// TLS key in x509 format.
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"`
OcspStapling int64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
OcspStapling uint64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
// TLS certificate path
CertificatePath string `protobuf:"bytes,5,opt,name=certificate_path,json=certificatePath,proto3" json:"certificate_path,omitempty"`
// TLS Key path
KeyPath string `protobuf:"bytes,6,opt,name=key_path,json=keyPath,proto3" json:"key_path,omitempty"`
// If true, one-Time Loading
OneTimeLoading bool `protobuf:"varint,7,opt,name=One_time_loading,json=OneTimeLoading,proto3" json:"One_time_loading,omitempty"`
}
func (x *Certificate) Reset() {
@@ -140,13 +146,34 @@ func (x *Certificate) GetUsage() Certificate_Usage {
return Certificate_ENCIPHERMENT
}
func (x *Certificate) GetOcspStapling() int64 {
func (x *Certificate) GetOcspStapling() uint64 {
if x != nil {
return x.OcspStapling
}
return 0
}
func (x *Certificate) GetCertificatePath() string {
if x != nil {
return x.CertificatePath
}
return ""
}
func (x *Certificate) GetKeyPath() string {
if x != nil {
return x.KeyPath
}
return ""
}
func (x *Certificate) GetOneTimeLoading() bool {
if x != nil {
return x.OneTimeLoading
}
return false
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -284,7 +311,7 @@ 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,
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,
0x6c, 0x73, 0x22, 0xf2, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x6c, 0x73, 0x22, 0xe2, 0x02, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 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, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
@@ -294,7 +321,14 @@ var file_transport_internet_tls_config_proto_rawDesc = []byte{
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, 0x12, 0x23, 0x0a, 0x0d,
0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20,
0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e,
0x01, 0x28, 0x04, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e,
0x67, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x65, 0x72,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08,
0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x4f, 0x6e, 0x65, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0e, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e,
0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e,
0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10,
0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59,

View File

@@ -21,7 +21,16 @@ message Certificate {
Usage usage = 3;
int64 ocsp_stapling = 4;
uint64 ocsp_stapling = 4;
// TLS certificate path
string certificate_path = 5;
// TLS Key path
string key_path = 6;
// If true, one-Time Loading
bool One_time_loading = 7;
}
message Config {

View File

@@ -10,6 +10,7 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/ocsp"
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/protocol/tls/cert"
"github.com/xtls/xray-core/transport/internet"
)
@@ -41,8 +42,8 @@ func (c *Config) loadSelfCertPool() (*x509.CertPool, error) {
}
// BuildCertificates builds a list of TLS certificates from proto definition.
func (c *Config) BuildCertificates() []xtls.Certificate {
certs := make([]xtls.Certificate, 0, len(c.Certificate))
func (c *Config) BuildCertificates() []*xtls.Certificate {
certs := make([]*xtls.Certificate, 0, len(c.Certificate))
for _, entry := range c.Certificate {
if entry.Usage != Certificate_ENCIPHERMENT {
continue
@@ -52,19 +53,62 @@ func (c *Config) BuildCertificates() []xtls.Certificate {
newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, keyPair)
if entry.OcspStapling != 0 {
go func(cert *xtls.Certificate) {
t := time.NewTicker(time.Duration(entry.OcspStapling) * time.Second)
keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
if err != nil {
newError("ignoring invalid certificate").Base(err).AtWarning().WriteToLog()
continue
}
certs = append(certs, &keyPair)
if !entry.OneTimeLoading {
var isOcspstapling bool
hotRelodaInterval := uint64(3600)
if entry.OcspStapling != 0 {
hotRelodaInterval = entry.OcspStapling
isOcspstapling = true
}
index := len(certs) - 1
go func(cert *xtls.Certificate, index int) {
t := time.NewTicker(time.Duration(hotRelodaInterval) * 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
if entry.CertificatePath != "" && entry.KeyPath != "" {
newCert, err := filesystem.ReadFile(entry.CertificatePath)
if err != nil {
newError("failed to parse certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
newKey, err := filesystem.ReadFile(entry.KeyPath)
if err != nil {
newError("failed to parse key").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if string(newCert) != string(entry.Certificate) && string(newKey) != string(entry.Key) {
newKeyPair, err := xtls.X509KeyPair(newCert, newKey)
if err != nil {
newError("ignoring invalid X509 key pair").Base(err).AtError().WriteToLog()
<-t.C
continue
}
if newKeyPair.Leaf, err = x509.ParseCertificate(newKeyPair.Certificate[0]); err != nil {
newError("ignoring invalid certificate").Base(err).AtError().WriteToLog()
<-t.C
continue
}
cert = &newKeyPair
}
}
if isOcspstapling {
if newOCSPData, err := ocsp.GetOCSPForCert(cert.Certificate); err != nil {
newError("ignoring invalid OCSP").Base(err).AtWarning().WriteToLog()
} else if string(newOCSPData) != string(cert.OCSPStaple) {
cert.OCSPStaple = newOCSPData
}
}
certs[index] = cert
<-t.C
}
}(&certs[len(certs)-1])
}(certs[len(certs)-1], index)
}
}
return certs
@@ -168,6 +212,33 @@ func getGetCertificateFunc(c *xtls.Config, ca []*Certificate) func(hello *xtls.C
}
}
func getNewGetCertficateFunc(certs []*xtls.Certificate) func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
return func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
if len(certs) == 0 {
return nil, newError("empty certs")
}
sni := strings.ToLower(hello.ServerName)
if len(certs) == 1 || sni == "" {
return certs[0], nil
}
gsni := "*"
if index := strings.IndexByte(sni, '.'); index != -1 {
gsni += sni[index:]
}
for _, keyPair := range certs {
if keyPair.Leaf.Subject.CommonName == sni || keyPair.Leaf.Subject.CommonName == gsni {
return keyPair, nil
}
for _, name := range keyPair.Leaf.DNSNames {
if name == sni || name == gsni {
return keyPair, nil
}
}
}
return certs[0], nil
}
}
func (c *Config) parseServerName() string {
return c.ServerName
}
@@ -201,12 +272,11 @@ func (c *Config) GetXTLSConfig(opts ...Option) *xtls.Config {
opt(config)
}
config.Certificates = c.BuildCertificates()
config.BuildNameToCertificate()
caCerts := c.getCustomCA()
if len(caCerts) > 0 {
config.GetCertificate = getGetCertificateFunc(config, caCerts)
} else {
config.GetCertificate = getNewGetCertficateFunc(c.BuildCertificates())
}
if sn := c.parseServerName(); len(sn) > 0 {

View File

@@ -84,7 +84,13 @@ type Certificate struct {
// TLS key in x509 format.
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"`
OcspStapling int64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
OcspStapling uint64 `protobuf:"varint,4,opt,name=ocsp_stapling,json=ocspStapling,proto3" json:"ocsp_stapling,omitempty"`
// TLS certificate path
CertificatePath string `protobuf:"bytes,5,opt,name=certificate_path,json=certificatePath,proto3" json:"certificate_path,omitempty"`
// TLS Key path
KeyPath string `protobuf:"bytes,6,opt,name=key_path,json=keyPath,proto3" json:"key_path,omitempty"`
// If true, one-Time Loading
OneTimeLoading bool `protobuf:"varint,7,opt,name=One_time_loading,json=OneTimeLoading,proto3" json:"One_time_loading,omitempty"`
}
func (x *Certificate) Reset() {
@@ -140,13 +146,34 @@ func (x *Certificate) GetUsage() Certificate_Usage {
return Certificate_ENCIPHERMENT
}
func (x *Certificate) GetOcspStapling() int64 {
func (x *Certificate) GetOcspStapling() uint64 {
if x != nil {
return x.OcspStapling
}
return 0
}
func (x *Certificate) GetCertificatePath() string {
if x != nil {
return x.CertificatePath
}
return ""
}
func (x *Certificate) GetKeyPath() string {
if x != nil {
return x.KeyPath
}
return ""
}
func (x *Certificate) GetOneTimeLoading() bool {
if x != nil {
return x.OneTimeLoading
}
return false
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -284,7 +311,7 @@ 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,
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,
0x78, 0x74, 0x6c, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x78, 0x74, 0x6c, 0x73, 0x22, 0xe3, 0x02, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
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, 0x63, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
@@ -294,8 +321,15 @@ var file_transport_internet_xtls_config_proto_rawDesc = []byte{
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, 0x12,
0x23, 0x0a, 0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67,
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70,
0x6c, 0x69, 0x6e, 0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a,
0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x53, 0x74, 0x61, 0x70,
0x6c, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12,
0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x4f, 0x6e,
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x6f, 0x61,
0x64, 0x69, 0x6e, 0x67, 0x22, 0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a,
0x0c, 0x45, 0x4e, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12,
0x14, 0x0a, 0x10, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52,
0x49, 0x46, 0x59, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49,

View File

@@ -21,7 +21,16 @@ message Certificate {
Usage usage = 3;
int64 ocsp_stapling = 4;
uint64 ocsp_stapling = 4;
// TLS certificate path
string certificate_path = 5;
// TLS Key path
string key_path = 6;
// If true, one-Time Loading
bool One_time_loading = 7;
}
message Config {