mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-27 21:46:58 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1be7c52f3 | ||
|
|
f45f546654 | ||
|
|
9a77d85656 | ||
|
|
75c076b744 | ||
|
|
97e53af8c2 | ||
|
|
0a8b761d12 | ||
|
|
e006c2487c |
@@ -82,7 +82,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v4.7.0
|
uses: docker/login-action@v4.6.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
|
|||||||
@@ -35,24 +35,7 @@ jobs:
|
|||||||
if: steps.check-assets.outputs.missing == 'true'
|
if: steps.check-assets.outputs.missing == 'true'
|
||||||
run: sleep 90
|
run: sleep 90
|
||||||
|
|
||||||
check-proto:
|
check-format-and-proto:
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
||||||
steps:
|
|
||||||
- name: Checkout codebase
|
|
||||||
uses: actions/checkout@v7
|
|
||||||
- name: Check Proto Version Header
|
|
||||||
run: |
|
|
||||||
head -n 4 core/config.pb.go > ref.txt
|
|
||||||
find . -name "*.pb.go" ! -name "*_grpc.pb.go" -print0 | while IFS= read -r -d '' file; do
|
|
||||||
if ! cmp -s ref.txt <(head -n 4 "$file"); then
|
|
||||||
echo "Error: Header mismatch in $file"
|
|
||||||
head -n 4 "$file"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
check-format:
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
||||||
permissions:
|
permissions:
|
||||||
@@ -68,6 +51,8 @@ jobs:
|
|||||||
cache: false
|
cache: false
|
||||||
- name: Check Format
|
- name: Check Format
|
||||||
run: go run ./infra/vformat/main.go -mode check -pwd ./
|
run: go run ./infra/vformat/main.go -mode check -pwd ./
|
||||||
|
- name: Check Protobuf
|
||||||
|
run: go run ./infra/vprotogen/main.go -mode check -pwd ./
|
||||||
|
|
||||||
test:
|
test:
|
||||||
needs: check-assets
|
needs: check-assets
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ message RoutingContext {
|
|||||||
// - attributes: Select connection's additional attributes.
|
// - attributes: Select connection's additional attributes.
|
||||||
// - outbound: Equivalent as "outbound" and "outbound_group", select both
|
// - outbound: Equivalent as "outbound" and "outbound_group", select both
|
||||||
// outbound tag and outbound group tags.
|
// outbound tag and outbound group tags.
|
||||||
|
//
|
||||||
// * If FieldSelectors is left empty, all fields will be returned.
|
// * If FieldSelectors is left empty, all fields will be returned.
|
||||||
message SubscribeRoutingStatsRequest {
|
message SubscribeRoutingStatsRequest {
|
||||||
repeated string FieldSelectors = 1;
|
repeated string FieldSelectors = 1;
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11
|
||||||
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.6.0
|
||||||
//go:generate go run ../infra/vprotogen/main.go -pwd ./..
|
//go:generate go run ../infra/vprotogen/main.go -pwd ./..
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ go 1.27
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e
|
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e
|
||||||
|
github.com/bufbuild/protocompile v0.14.1
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344
|
||||||
github.com/golang/mock v1.7.0-rc.1
|
github.com/golang/mock v1.7.0-rc.1
|
||||||
github.com/google/go-cmp v0.7.0
|
github.com/google/go-cmp v0.7.0
|
||||||
@@ -14,7 +15,7 @@ require (
|
|||||||
github.com/miekg/dns v1.1.73
|
github.com/miekg/dns v1.1.73
|
||||||
github.com/pelletier/go-toml v1.9.5
|
github.com/pelletier/go-toml v1.9.5
|
||||||
github.com/pion/stun/v3 v3.1.7
|
github.com/pion/stun/v3 v3.1.7
|
||||||
github.com/pires/go-proxyproto v0.16.0
|
github.com/pires/go-proxyproto v0.15.0
|
||||||
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af
|
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/stretchr/testify v1.12.1
|
github.com/stretchr/testify v1.12.1
|
||||||
@@ -32,7 +33,7 @@ require (
|
|||||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||||
golang.zx2c4.com/wireguard/windows v1.1.1
|
golang.zx2c4.com/wireguard/windows v1.1.1
|
||||||
google.golang.org/grpc v1.84.0
|
google.golang.org/grpc v1.84.0
|
||||||
google.golang.org/protobuf v1.36.12
|
google.golang.org/protobuf v1.36.11
|
||||||
h12.io/socks v1.0.3
|
h12.io/socks v1.0.3
|
||||||
layeh.com/gopher-luar v1.0.11
|
layeh.com/gopher-luar v1.0.11
|
||||||
lukechampine.com/blake3 v1.4.1
|
lukechampine.com/blake3 v1.4.1
|
||||||
@@ -58,6 +59,12 @@ require (
|
|||||||
golang.org/x/text v0.43.0 // indirect
|
golang.org/x/text v0.43.0 // indirect
|
||||||
golang.org/x/tools v0.51.0 // indirect
|
golang.org/x/tools v0.51.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 // indirect
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 // indirect
|
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tool (
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc
|
||||||
|
google.golang.org/protobuf/cmd/protoc-gen-go
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ github.com/andybalholm/brotli v1.2.3 h1:8H1qwOkl2LPfjf3YezB90JnCliZb6SInJ/OJkEbA
|
|||||||
github.com/andybalholm/brotli v1.2.3/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
github.com/andybalholm/brotli v1.2.3/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||||
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e h1:5mgtR5gwIgBKMiGI1QdXldZZ+SNor06Nbu1wCBulQBg=
|
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e h1:5mgtR5gwIgBKMiGI1QdXldZZ+SNor06Nbu1wCBulQBg=
|
||||||
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e/go.mod h1:x7qxEvX6MCVtDuBKHj3E+88+BtrbEMuAL5qGUKItjW8=
|
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e/go.mod h1:x7qxEvX6MCVtDuBKHj3E+88+BtrbEMuAL5qGUKItjW8=
|
||||||
|
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
|
||||||
|
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
@@ -59,8 +61,8 @@ github.com/pion/stun/v3 v3.1.7 h1:uRXMTlGLf89WgItGNyZ6aR5jMTX0NBbybXADpQCzn+E=
|
|||||||
github.com/pion/stun/v3 v3.1.7/go.mod h1:Nq77RW4aRrSNrltf2ksUJLjxWeipj4lnlgdsYIxC8g8=
|
github.com/pion/stun/v3 v3.1.7/go.mod h1:Nq77RW4aRrSNrltf2ksUJLjxWeipj4lnlgdsYIxC8g8=
|
||||||
github.com/pion/transport/v4 v4.1.0 h1:8S+nF2reM2cJuqC6g78OVy2BBgmbdns+acx3jA97BvQ=
|
github.com/pion/transport/v4 v4.1.0 h1:8S+nF2reM2cJuqC6g78OVy2BBgmbdns+acx3jA97BvQ=
|
||||||
github.com/pion/transport/v4 v4.1.0/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBPfviSVcjgM=
|
github.com/pion/transport/v4 v4.1.0/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBPfviSVcjgM=
|
||||||
github.com/pires/go-proxyproto v0.16.0 h1:9KYT/fM3wpjT8bdMEj/7FBcoiUG1KyzEjRYnPu+vz7A=
|
github.com/pires/go-proxyproto v0.15.0 h1:dTshmNbFm/D+0+sbrxUuddPOZ5Y0B7c5NhtsBkm6LqI=
|
||||||
github.com/pires/go-proxyproto v0.16.0/go.mod h1:n7yhg8yIfNl3KgYDCwBzmeUHNpKTVnUhcWpc7rV4RW4=
|
github.com/pires/go-proxyproto v0.15.0/go.mod h1:OXsCrKwrK2tXS9YrI5tkHx5xaQlO8FH3lFW76orFh24=
|
||||||
github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
|
github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
|
||||||
github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk=
|
github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk=
|
||||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||||
@@ -152,6 +154,10 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 h1:
|
|||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0=
|
google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0=
|
||||||
google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0=
|
google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0=
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0 h1:6Al3kEFFP9VJhRz3DID6quisgPnTeZVr4lep9kkxdPA=
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0/go.mod h1:QLvsjh0OIR0TYBeiu2bkWGTJBUNQ64st52iWj/yA93I=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||||
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
+166
-201
@@ -1,149 +1,87 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"bytes"
|
||||||
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"io/fs"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bufbuild/protocompile"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protodesc"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/types/descriptorpb"
|
||||||
|
"google.golang.org/protobuf/types/pluginpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
var directory = flag.String("pwd", "", "Working directory of Xray vprotogen.")
|
var (
|
||||||
|
directory = flag.String("pwd", "", "Working directory of Xray vprotogen.")
|
||||||
|
mode = flag.String("mode", "generate", "Execution mode. 'generate' (default) compiles and saves changes. 'check' reports out-of-date files and exits with non-zero.")
|
||||||
|
)
|
||||||
|
|
||||||
// envFile returns the name of the Go environment configuration file.
|
// topoSort sorts file descriptors so each dependency appears before files importing it.
|
||||||
// Copy from https://github.com/golang/go/blob/c4f2a9788a7be04daf931ac54382fbe2cb754938/src/cmd/go/internal/cfg/cfg.go#L150-L166
|
func topoSort(files []protoreflect.FileDescriptor) []*descriptorpb.FileDescriptorProto {
|
||||||
func envFile() (string, error) {
|
fileMap := make(map[string]protoreflect.FileDescriptor)
|
||||||
if file := os.Getenv("GOENV"); file != "" {
|
for _, f := range files {
|
||||||
if file == "off" {
|
fileMap[f.Path()] = f
|
||||||
return "", errors.New("GOENV=off")
|
|
||||||
}
|
}
|
||||||
return file, nil
|
|
||||||
|
visited := make(map[string]bool)
|
||||||
|
var sorted []*descriptorpb.FileDescriptorProto
|
||||||
|
|
||||||
|
var visit func(fd protoreflect.FileDescriptor)
|
||||||
|
visit = func(fd protoreflect.FileDescriptor) {
|
||||||
|
if visited[fd.Path()] {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
dir, err := os.UserConfigDir()
|
visited[fd.Path()] = true
|
||||||
|
|
||||||
|
imports := fd.Imports()
|
||||||
|
for i := 0; i < imports.Len(); i++ {
|
||||||
|
if dep, ok := fileMap[imports.Get(i).Path()]; ok {
|
||||||
|
visit(dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sorted = append(sorted, protodesc.ToFileDescriptorProto(fd))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
visit(f)
|
||||||
|
}
|
||||||
|
return sorted
|
||||||
|
}
|
||||||
|
|
||||||
|
func runPlugin(pluginName, pwd string, req *pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorResponse, error) {
|
||||||
|
reqBytes, err := proto.Marshal(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
|
||||||
if dir == "" {
|
|
||||||
return "", errors.New("missing user-config dir")
|
|
||||||
}
|
|
||||||
return filepath.Join(dir, "go", "env"), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRuntimeEnv returns the value of runtime environment variable,
|
cmd := exec.Command("go", "tool", pluginName)
|
||||||
// that is set by running following command: `go env -w key=value`.
|
cmd.Dir = pwd
|
||||||
func GetRuntimeEnv(key string) (string, error) {
|
cmd.Stdin = bytes.NewReader(reqBytes)
|
||||||
file, err := envFile()
|
cmd.Env = os.Environ()
|
||||||
if err != nil {
|
var stdout, stderr bytes.Buffer
|
||||||
return "", err
|
cmd.Stdout = &stdout
|
||||||
}
|
cmd.Stderr = &stderr
|
||||||
if file == "" {
|
|
||||||
return "", errors.New("missing runtime env file")
|
if err := cmd.Run(); err != nil {
|
||||||
}
|
return nil, fmt.Errorf("%v: %s", err, stderr.String())
|
||||||
var data []byte
|
|
||||||
var runtimeEnv string
|
|
||||||
data, readErr := os.ReadFile(file)
|
|
||||||
if readErr != nil {
|
|
||||||
return "", readErr
|
|
||||||
}
|
|
||||||
envStrings := strings.Split(string(data), "\n")
|
|
||||||
for _, envItem := range envStrings {
|
|
||||||
envItem = strings.TrimSuffix(envItem, "\r")
|
|
||||||
envKeyValue := strings.Split(envItem, "=")
|
|
||||||
if strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {
|
|
||||||
runtimeEnv = strings.TrimSpace(envKeyValue[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return runtimeEnv, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGOBIN returns GOBIN environment variable as a string. It will NOT be empty.
|
var resp pluginpb.CodeGeneratorResponse
|
||||||
func GetGOBIN() string {
|
if err := proto.Unmarshal(stdout.Bytes(), &resp); err != nil {
|
||||||
// The one set by user explicitly by `export GOBIN=/path` or `env GOBIN=/path command`
|
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||||
GOBIN := os.Getenv("GOBIN")
|
|
||||||
if GOBIN == "" {
|
|
||||||
var err error
|
|
||||||
// The one set by user by running `go env -w GOBIN=/path`
|
|
||||||
GOBIN, err = GetRuntimeEnv("GOBIN")
|
|
||||||
if err != nil {
|
|
||||||
// The default one that Golang uses
|
|
||||||
return filepath.Join(build.Default.GOPATH, "bin")
|
|
||||||
}
|
}
|
||||||
if GOBIN == "" {
|
if resp.GetError() != "" {
|
||||||
return filepath.Join(build.Default.GOPATH, "bin")
|
return nil, fmt.Errorf("%s", resp.GetError())
|
||||||
}
|
}
|
||||||
return GOBIN
|
return &resp, nil
|
||||||
}
|
|
||||||
return GOBIN
|
|
||||||
}
|
|
||||||
|
|
||||||
func whichProtoc(suffix, targetedVersion string) (string, error) {
|
|
||||||
protoc := "protoc" + suffix
|
|
||||||
|
|
||||||
path, err := exec.LookPath(protoc)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf(`
|
|
||||||
Command "%s" not found.
|
|
||||||
Make sure that %s is in your system path or current path.
|
|
||||||
Download %s v%s or later from https://github.com/protocolbuffers/protobuf/releases
|
|
||||||
`, protoc, protoc, protoc, targetedVersion)
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProjectProtocVersion(url string) (string, error) {
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("can not get the version of protobuf used in xray project")
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.New("can not read from body")
|
|
||||||
}
|
|
||||||
versionRegexp := regexp.MustCompile(`\/\/\s*protoc\s*v\d+\.(\d+\.\d+)`)
|
|
||||||
matched := versionRegexp.FindStringSubmatch(string(body))
|
|
||||||
return matched[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInstalledProtocVersion(protocPath string) (string, error) {
|
|
||||||
cmd := exec.Command(protocPath, "--version")
|
|
||||||
cmd.Env = append(cmd.Env, os.Environ()...)
|
|
||||||
output, cmdErr := cmd.CombinedOutput()
|
|
||||||
if cmdErr != nil {
|
|
||||||
return "", cmdErr
|
|
||||||
}
|
|
||||||
versionRegexp := regexp.MustCompile(`protoc\s*(\d+\.\d+)`)
|
|
||||||
matched := versionRegexp.FindStringSubmatch(string(output))
|
|
||||||
return matched[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseVersion(s string, width int) int64 {
|
|
||||||
strList := strings.Split(s, ".")
|
|
||||||
format := fmt.Sprintf("%%s%%0%ds", width)
|
|
||||||
v := ""
|
|
||||||
for _, value := range strList {
|
|
||||||
v = fmt.Sprintf(format, v, value)
|
|
||||||
}
|
|
||||||
var result int64
|
|
||||||
var err error
|
|
||||||
if result, err = strconv.ParseInt(v, 10, 64); err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func needToUpdate(targetedVersion, installedVersion string) bool {
|
|
||||||
vt := parseVersion(targetedVersion, 4)
|
|
||||||
vi := parseVersion(installedVersion, 4)
|
|
||||||
return vt > vi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -154,106 +92,133 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if !filepath.IsAbs(*directory) {
|
if !filepath.IsAbs(*directory) {
|
||||||
pwd, wdErr := os.Getwd()
|
pwd, err := os.Getwd()
|
||||||
if wdErr != nil {
|
if err != nil {
|
||||||
fmt.Println("Can not get current working directory.")
|
fmt.Println("Can not get current working directory.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
*directory = filepath.Join(pwd, *directory)
|
*directory = filepath.Join(pwd, *directory)
|
||||||
}
|
}
|
||||||
|
|
||||||
pwd := *directory
|
pwd := *directory
|
||||||
GOBIN := GetGOBIN()
|
|
||||||
binPath := os.Getenv("PATH")
|
|
||||||
pathSlice := []string{pwd, GOBIN, binPath}
|
|
||||||
binPath = strings.Join(pathSlice, string(os.PathListSeparator))
|
|
||||||
os.Setenv("PATH", binPath)
|
|
||||||
|
|
||||||
suffix := ""
|
isCheck := false
|
||||||
if runtime.GOOS == "windows" {
|
switch *mode {
|
||||||
suffix = ".exe"
|
case "generate", "":
|
||||||
}
|
isCheck = false
|
||||||
|
case "check":
|
||||||
/*
|
isCheck = true
|
||||||
targetedVersion, err := getProjectProtocVersion("https://raw.githubusercontent.com/XTLS/Xray-core/HEAD/core/config.pb.go")
|
default:
|
||||||
if err != nil {
|
fmt.Fprintf(os.Stderr, "Unrecognized 'mode': %s. Use 'generate' or 'check'.\n", *mode)
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
targetedVersion := ""
|
|
||||||
|
|
||||||
protoc, err := whichProtoc(suffix, targetedVersion)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
installedVersion, err := getInstalledProtocVersion(protoc)
|
if isCheck {
|
||||||
if err != nil {
|
fmt.Println("Checking for out-of-date Protobuf generated files...")
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if needToUpdate(targetedVersion, installedVersion) {
|
var protoFiles []string
|
||||||
fmt.Printf(`
|
err := filepath.WalkDir(pwd, func(path string, d fs.DirEntry, err error) error {
|
||||||
You are using an old protobuf version, please update to v%s or later.
|
if err != nil || d.IsDir() {
|
||||||
Download it from https://github.com/protocolbuffers/protobuf/releases
|
|
||||||
|
|
||||||
* Protobuf version used in xray project: v%s
|
|
||||||
* Protobuf version you have installed: v%s
|
|
||||||
|
|
||||||
`, targetedVersion, targetedVersion, installedVersion)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
protoFilesMap := make(map[string][]string)
|
|
||||||
walkErr := filepath.Walk(pwd, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if strings.HasSuffix(d.Name(), ".proto") {
|
||||||
if info.IsDir() {
|
rel, _ := filepath.Rel(pwd, path)
|
||||||
return nil
|
protoFiles = append(protoFiles, filepath.ToSlash(rel))
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := filepath.Dir(path)
|
|
||||||
filename := filepath.Base(path)
|
|
||||||
if strings.HasSuffix(filename, ".proto") {
|
|
||||||
path = path[len(pwd)+1:]
|
|
||||||
protoFilesMap[dir] = append(protoFilesMap[dir], path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if walkErr != nil {
|
if err != nil {
|
||||||
fmt.Println(walkErr)
|
fmt.Println("Walk error:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if len(protoFiles) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler := protocompile.Compiler{
|
||||||
|
Resolver: protocompile.WithStandardImports(&protocompile.SourceResolver{
|
||||||
|
ImportPaths: []string{pwd},
|
||||||
|
}),
|
||||||
|
SourceInfoMode: protocompile.SourceInfoStandard,
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedFiles, err := compiler.Compile(context.Background(), protoFiles...)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Protobuf compilation failed:\n%v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, files := range protoFilesMap {
|
var fdList []protoreflect.FileDescriptor
|
||||||
for _, relProtoFile := range files {
|
for _, f := range linkedFiles {
|
||||||
args := []string{
|
fdList = append(fdList, f)
|
||||||
"--go_out", pwd,
|
|
||||||
"--go_opt", "paths=source_relative",
|
|
||||||
"--go-grpc_out", pwd,
|
|
||||||
"--go-grpc_opt", "paths=source_relative",
|
|
||||||
"--plugin", "protoc-gen-go=" + filepath.Join(GOBIN, "protoc-gen-go"+suffix),
|
|
||||||
"--plugin", "protoc-gen-go-grpc=" + filepath.Join(GOBIN, "protoc-gen-go-grpc"+suffix),
|
|
||||||
}
|
}
|
||||||
args = append(args, relProtoFile)
|
|
||||||
cmd := exec.Command(protoc, args...)
|
req := &pluginpb.CodeGeneratorRequest{
|
||||||
cmd.Env = append(cmd.Env, os.Environ()...)
|
FileToGenerate: protoFiles,
|
||||||
cmd.Dir = pwd
|
Parameter: proto.String("paths=source_relative"),
|
||||||
output, cmdErr := cmd.CombinedOutput()
|
ProtoFile: topoSort(fdList),
|
||||||
if len(output) > 0 {
|
// TODO: replace with unknown in the future
|
||||||
fmt.Println(string(output))
|
CompilerVersion: &pluginpb.Version{
|
||||||
|
Major: proto.Int32(6),
|
||||||
|
Minor: proto.Int32(33),
|
||||||
|
Patch: proto.Int32(5),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
if cmdErr != nil {
|
|
||||||
fmt.Println(cmdErr)
|
var diffCount int
|
||||||
|
for _, plugin := range []string{"protoc-gen-go", "protoc-gen-go-grpc"} {
|
||||||
|
resp, err := runPlugin(plugin, pwd, req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s failed: %v\n", plugin, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range resp.File {
|
||||||
|
targetPath := filepath.Join(pwd, filepath.FromSlash(f.GetName()))
|
||||||
|
content := []byte(f.GetContent())
|
||||||
|
|
||||||
|
hasDiff := false
|
||||||
|
existing, err := os.ReadFile(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
hasDiff = true
|
||||||
|
} else {
|
||||||
|
oldNorm := bytes.ReplaceAll(existing, []byte("\r\n"), []byte("\n"))
|
||||||
|
newNorm := bytes.ReplaceAll(content, []byte("\r\n"), []byte("\n"))
|
||||||
|
if !bytes.Equal(oldNorm, newNorm) {
|
||||||
|
hasDiff = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasDiff {
|
||||||
|
diffCount++
|
||||||
|
fmt.Println(targetPath)
|
||||||
|
|
||||||
|
if isCheck {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(targetPath), 0o755); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error creating directory: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
mode := os.FileMode(0o644)
|
||||||
|
if stat, err := os.Stat(targetPath); err == nil {
|
||||||
|
mode = stat.Mode().Perm()
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(targetPath, content, mode); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error writing %s: %v\n", targetPath, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isCheck {
|
||||||
|
if diffCount > 0 {
|
||||||
|
fmt.Println("Protobuf generated file problem(s) found.")
|
||||||
|
fmt.Println("Please run 'go run ./infra/vprotogen' to regenerate them.")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println("All Protobuf generated file check has been passed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+17
-17
@@ -24,11 +24,11 @@ const (
|
|||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
// List of networks that the Dokodemo accepts.
|
||||||
|
AllowedNetworks []net.Network `protobuf:"varint,7,rep,packed,name=allowed_networks,json=allowedNetworks,proto3,enum=xray.common.net.Network" json:"allowed_networks,omitempty"`
|
||||||
RewriteAddress *net.IPOrDomain `protobuf:"bytes,1,opt,name=rewrite_address,json=rewriteAddress,proto3" json:"rewrite_address,omitempty"`
|
RewriteAddress *net.IPOrDomain `protobuf:"bytes,1,opt,name=rewrite_address,json=rewriteAddress,proto3" json:"rewrite_address,omitempty"`
|
||||||
RewritePort uint32 `protobuf:"varint,2,opt,name=rewrite_port,json=rewritePort,proto3" json:"rewrite_port,omitempty"`
|
RewritePort uint32 `protobuf:"varint,2,opt,name=rewrite_port,json=rewritePort,proto3" json:"rewrite_port,omitempty"`
|
||||||
PortMap map[string]string `protobuf:"bytes,3,rep,name=port_map,json=portMap,proto3" json:"port_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
PortMap map[string]string `protobuf:"bytes,3,rep,name=port_map,json=portMap,proto3" json:"port_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||||
// List of networks that the Dokodemo accepts.
|
|
||||||
AllowedNetworks []net.Network `protobuf:"varint,7,rep,packed,name=allowed_networks,json=allowedNetworks,proto3,enum=xray.common.net.Network" json:"allowed_networks,omitempty"`
|
|
||||||
FollowRedirect bool `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
|
FollowRedirect bool `protobuf:"varint,5,opt,name=follow_redirect,json=followRedirect,proto3" json:"follow_redirect,omitempty"`
|
||||||
UserLevel uint32 `protobuf:"varint,6,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
UserLevel uint32 `protobuf:"varint,6,opt,name=user_level,json=userLevel,proto3" json:"user_level,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
@@ -65,6 +65,13 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
return file_proxy_dokodemo_config_proto_rawDescGZIP(), []int{0}
|
return file_proxy_dokodemo_config_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetAllowedNetworks() []net.Network {
|
||||||
|
if x != nil {
|
||||||
|
return x.AllowedNetworks
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Config) GetRewriteAddress() *net.IPOrDomain {
|
func (x *Config) GetRewriteAddress() *net.IPOrDomain {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.RewriteAddress
|
return x.RewriteAddress
|
||||||
@@ -86,13 +93,6 @@ func (x *Config) GetPortMap() map[string]string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetAllowedNetworks() []net.Network {
|
|
||||||
if x != nil {
|
|
||||||
return x.AllowedNetworks
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetFollowRedirect() bool {
|
func (x *Config) GetFollowRedirect() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.FollowRedirect
|
return x.FollowRedirect
|
||||||
@@ -112,11 +112,11 @@ var File_proxy_dokodemo_config_proto protoreflect.FileDescriptor
|
|||||||
const file_proxy_dokodemo_config_proto_rawDesc = "" +
|
const file_proxy_dokodemo_config_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x1bproxy/dokodemo/config.proto\x12\x13xray.proxy.dokodemo\x1a\x18common/net/address.proto\x1a\x18common/net/network.proto\"\xff\x02\n" +
|
"\x1bproxy/dokodemo/config.proto\x12\x13xray.proxy.dokodemo\x1a\x18common/net/address.proto\x1a\x18common/net/network.proto\"\xff\x02\n" +
|
||||||
"\x06Config\x12D\n" +
|
"\x06Config\x12C\n" +
|
||||||
|
"\x10allowed_networks\x18\a \x03(\x0e2\x18.xray.common.net.NetworkR\x0fallowedNetworks\x12D\n" +
|
||||||
"\x0frewrite_address\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\x0erewriteAddress\x12!\n" +
|
"\x0frewrite_address\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\x0erewriteAddress\x12!\n" +
|
||||||
"\frewrite_port\x18\x02 \x01(\rR\vrewritePort\x12C\n" +
|
"\frewrite_port\x18\x02 \x01(\rR\vrewritePort\x12C\n" +
|
||||||
"\bport_map\x18\x03 \x03(\v2(.xray.proxy.dokodemo.Config.PortMapEntryR\aportMap\x12C\n" +
|
"\bport_map\x18\x03 \x03(\v2(.xray.proxy.dokodemo.Config.PortMapEntryR\aportMap\x12'\n" +
|
||||||
"\x10allowed_networks\x18\a \x03(\x0e2\x18.xray.common.net.NetworkR\x0fallowedNetworks\x12'\n" +
|
|
||||||
"\x0ffollow_redirect\x18\x05 \x01(\bR\x0efollowRedirect\x12\x1d\n" +
|
"\x0ffollow_redirect\x18\x05 \x01(\bR\x0efollowRedirect\x12\x1d\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"user_level\x18\x06 \x01(\rR\tuserLevel\x1a:\n" +
|
"user_level\x18\x06 \x01(\rR\tuserLevel\x1a:\n" +
|
||||||
@@ -141,13 +141,13 @@ var file_proxy_dokodemo_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|||||||
var file_proxy_dokodemo_config_proto_goTypes = []any{
|
var file_proxy_dokodemo_config_proto_goTypes = []any{
|
||||||
(*Config)(nil), // 0: xray.proxy.dokodemo.Config
|
(*Config)(nil), // 0: xray.proxy.dokodemo.Config
|
||||||
nil, // 1: xray.proxy.dokodemo.Config.PortMapEntry
|
nil, // 1: xray.proxy.dokodemo.Config.PortMapEntry
|
||||||
(*net.IPOrDomain)(nil), // 2: xray.common.net.IPOrDomain
|
(net.Network)(0), // 2: xray.common.net.Network
|
||||||
(net.Network)(0), // 3: xray.common.net.Network
|
(*net.IPOrDomain)(nil), // 3: xray.common.net.IPOrDomain
|
||||||
}
|
}
|
||||||
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
||||||
2, // 0: xray.proxy.dokodemo.Config.rewrite_address:type_name -> xray.common.net.IPOrDomain
|
2, // 0: xray.proxy.dokodemo.Config.allowed_networks:type_name -> xray.common.net.Network
|
||||||
1, // 1: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
|
3, // 1: xray.proxy.dokodemo.Config.rewrite_address:type_name -> xray.common.net.IPOrDomain
|
||||||
3, // 2: xray.proxy.dokodemo.Config.allowed_networks:type_name -> xray.common.net.Network
|
1, // 2: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
|
||||||
3, // [3:3] is the sub-list for method output_type
|
3, // [3:3] is the sub-list for method output_type
|
||||||
3, // [3:3] is the sub-list for method input_type
|
3, // [3:3] is the sub-list for method input_type
|
||||||
3, // [3:3] is the sub-list for extension type_name
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
|
|||||||
@@ -7,12 +7,11 @@
|
|||||||
package tun
|
package tun
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
unsafe "unsafe"
|
||||||
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
Reference in New Issue
Block a user