mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-27 05:27:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
816f1d6123 | ||
|
|
75c08917e3 | ||
|
|
98d7b719c5 | ||
|
|
5b21e5dcbd | ||
|
|
36bff1bfe7 | ||
|
|
20d107a28a |
@@ -41,35 +41,16 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout codebase
|
- name: Checkout codebase
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v7
|
||||||
- name: Set up Go
|
- name: Check Proto Version Header
|
||||||
uses: actions/setup-go@v7
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
- name: Cache protoc
|
|
||||||
id: cache-protoc
|
|
||||||
uses: actions/cache@v6
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/protoc
|
|
||||||
key: protoc-linux-x86_64-33.5
|
|
||||||
- name: Download protoc
|
|
||||||
if: steps.cache-protoc.outputs.cache-hit != 'true'
|
|
||||||
working-directory: ${{ runner.temp }}
|
|
||||||
run: |
|
run: |
|
||||||
curl -fsSL --retry 3 -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v33.5/protoc-33.5-linux-x86_64.zip
|
head -n 4 core/config.pb.go > ref.txt
|
||||||
unzip -q protoc.zip -d protoc
|
find . -name "*.pb.go" ! -name "*_grpc.pb.go" -print0 | while IFS= read -r -d '' file; do
|
||||||
- name: Install pinned protobuf tools
|
if ! cmp -s ref.txt <(head -n 4 "$file"); then
|
||||||
run: |
|
echo "Error: Header mismatch in $file"
|
||||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11
|
head -n 4 "$file"
|
||||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.6.0
|
exit 1
|
||||||
- name: Check generated protobuf files
|
fi
|
||||||
run: |
|
done
|
||||||
export PATH="$RUNNER_TEMP/protoc/bin:$PATH"
|
|
||||||
# Remove old outputs so orphaned pb files are also detected.
|
|
||||||
git ls-files -z -- '*.pb.go' | xargs -0 -r rm --
|
|
||||||
go run ./infra/vprotogen
|
|
||||||
# Include newly generated files in the diff without committing.
|
|
||||||
git add --intent-to-add --force -- '*.pb.go'
|
|
||||||
git diff --exit-code HEAD -- '*.pb.go'
|
|
||||||
|
|
||||||
check-format:
|
check-format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -152,23 +152,23 @@ func (x *HealthPingMeasurementResult) GetMin() int64 {
|
|||||||
type OutboundStatus struct {
|
type OutboundStatus struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
// @Document Whether this outbound is usable
|
// @Document Whether this outbound is usable
|
||||||
//@Restriction ReadOnlyForUser
|
// @Restriction ReadOnlyForUser
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
||||||
// @Document The time for probe request to finish.
|
// @Document The time for probe request to finish.
|
||||||
//@Type time.ms
|
// @Type time.ms
|
||||||
//@Restriction ReadOnlyForUser
|
// @Restriction ReadOnlyForUser
|
||||||
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
||||||
// @Document The last error caused this outbound failed to relay probe request
|
// @Document The last error caused this outbound failed to relay probe request
|
||||||
//@Restriction NotMachineReadable
|
// @Restriction NotMachineReadable
|
||||||
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
||||||
// @Document The outbound tag for this Server
|
// @Document The outbound tag for this Server
|
||||||
//@Type id.outboundTag
|
// @Type id.outboundTag
|
||||||
OutboundTag string `protobuf:"bytes,4,opt,name=outbound_tag,json=outboundTag,proto3" json:"outbound_tag,omitempty"`
|
OutboundTag string `protobuf:"bytes,4,opt,name=outbound_tag,json=outboundTag,proto3" json:"outbound_tag,omitempty"`
|
||||||
// @Document The time this outbound is known to be alive
|
// @Document The time this outbound is known to be alive
|
||||||
//@Type id.outboundTag
|
// @Type id.outboundTag
|
||||||
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
|
LastSeenTime int64 `protobuf:"varint,5,opt,name=last_seen_time,json=lastSeenTime,proto3" json:"last_seen_time,omitempty"`
|
||||||
// @Document The time this outbound is tried
|
// @Document The time this outbound is tried
|
||||||
//@Type id.outboundTag
|
// @Type id.outboundTag
|
||||||
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
|
LastTryTime int64 `protobuf:"varint,6,opt,name=last_try_time,json=lastTryTime,proto3" json:"last_try_time,omitempty"`
|
||||||
HealthPing *HealthPingMeasurementResult `protobuf:"bytes,7,opt,name=health_ping,json=healthPing,proto3" json:"health_ping,omitempty"`
|
HealthPing *HealthPingMeasurementResult `protobuf:"bytes,7,opt,name=health_ping,json=healthPing,proto3" json:"health_ping,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
@@ -257,14 +257,14 @@ func (x *OutboundStatus) GetHealthPing() *HealthPingMeasurementResult {
|
|||||||
type ProbeResult struct {
|
type ProbeResult struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
// @Document Whether this outbound is usable
|
// @Document Whether this outbound is usable
|
||||||
//@Restriction ReadOnlyForUser
|
// @Restriction ReadOnlyForUser
|
||||||
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
Alive bool `protobuf:"varint,1,opt,name=alive,proto3" json:"alive,omitempty"`
|
||||||
// @Document The time for probe request to finish.
|
// @Document The time for probe request to finish.
|
||||||
//@Type time.ms
|
// @Type time.ms
|
||||||
//@Restriction ReadOnlyForUser
|
// @Restriction ReadOnlyForUser
|
||||||
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
Delay int64 `protobuf:"varint,2,opt,name=delay,proto3" json:"delay,omitempty"`
|
||||||
// @Document The error caused this outbound failed to relay probe request
|
// @Document The error caused this outbound failed to relay probe request
|
||||||
//@Restriction NotMachineReadable
|
// @Restriction NotMachineReadable
|
||||||
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
LastErrorReason string `protobuf:"bytes,3,opt,name=last_error_reason,json=lastErrorReason,proto3" json:"last_error_reason,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -324,7 +324,7 @@ func (x *ProbeResult) GetLastErrorReason() string {
|
|||||||
type Intensity struct {
|
type Intensity struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
// @Document The time interval for a probe request in ms.
|
// @Document The time interval for a probe request in ms.
|
||||||
//@Type time.ms
|
// @Type time.ms
|
||||||
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
ProbeInterval uint32 `protobuf:"varint,1,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/xtls/xray-core/common/base64"
|
"github.com/xtls/xray-core/common/base64"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/platform"
|
"github.com/xtls/xray-core/common/platform/filesystem"
|
||||||
glua "github.com/yuin/gopher-lua"
|
glua "github.com/yuin/gopher-lua"
|
||||||
"github.com/yuin/gopher-lua/parse"
|
"github.com/yuin/gopher-lua/parse"
|
||||||
)
|
)
|
||||||
@@ -36,7 +36,7 @@ func Compile(script string) (*Program, error) {
|
|||||||
// TODO: Restore inline script support and re-enable the related tests.
|
// TODO: Restore inline script support and re-enable the related tests.
|
||||||
return nil, errors.New("currently unavailable")
|
return nil, errors.New("currently unavailable")
|
||||||
code, err = base64.Decode(script)
|
code, err = base64.Decode(script)
|
||||||
} else if name, err = platform.ResolveLuaFile(script); err == nil {
|
} else if name, err = filesystem.ResolveLuaFile(script); err == nil {
|
||||||
code, err = os.ReadFile(name)
|
code, err = os.ReadFile(name)
|
||||||
// TODO: Restore privileged signature authorization and re-enable the related tests and CLI entries.
|
// TODO: Restore privileged signature authorization and re-enable the related tests and CLI entries.
|
||||||
// if err == nil {
|
// if err == nil {
|
||||||
|
|||||||
@@ -187,18 +187,19 @@ func TestCompileInlineDiagnostics(t *testing.T) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
func TestCompileFileExtension(t *testing.T) {
|
func TestCompileFileExtension(t *testing.T) {
|
||||||
for _, name := range []string{"script", "script.dat", "script.lua.txt", "script.LUA"} {
|
for _, name := range []string{"script", "script.dat", "script.lua.txt"} {
|
||||||
|
if program, err := Compile(name); program != nil || err == nil || !strings.Contains(err.Error(), "Lua file extension must be .lua") {
|
||||||
|
t.Fatalf("Compile(%q) = %v, %v; want nil program and .lua extension error", name, program, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, name := range []string{"script.lua", "script.LUA", "script.Lua", "script.lUa"} {
|
||||||
path := filepath.Join(t.TempDir(), name)
|
path := filepath.Join(t.TempDir(), name)
|
||||||
if err := os.WriteFile(path, []byte("value = 42"), 0o600); err != nil {
|
if err := os.WriteFile(path, []byte("value = 42"), 0o600); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if program, err := Compile(path); program != nil || err == nil || !strings.Contains(err.Error(), "Lua file extension must be .lua") {
|
|
||||||
t.Fatalf("Compile(%q) = %v, %v; want nil program and .lua extension error", path, program, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
path := writeTestScript(t, "value = 42") + string(filepath.Separator) + "."
|
|
||||||
if program, err := Compile(path); program == nil || err != nil {
|
if program, err := Compile(path); program == nil || err != nil {
|
||||||
t.Fatalf("Compile(%q) = %v, %v; want acceptance of the resolved .lua path", path, program, err)
|
t.Fatalf("Compile(%q) = %v, %v; want successful compilation", path, program, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,10 +235,6 @@ func writeTestScript(t *testing.T, code string) string {
|
|||||||
if err := os.WriteFile(path, []byte(code), 0o600); err != nil {
|
if err := os.WriteFile(path, []byte(code), 0o600); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
path, err := filepath.EvalSymlinks(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/platform"
|
"github.com/xtls/xray-core/common/platform"
|
||||||
@@ -26,14 +27,6 @@ func ReadFile(path string) ([]byte, error) {
|
|||||||
return buf.ReadAllToBytes(reader)
|
return buf.ReadAllToBytes(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadAsset(file string) ([]byte, error) {
|
|
||||||
path, _, err := getAssetFileLocation(file)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ReadFile(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func OpenAsset(file string) (io.ReadCloser, int64, error) {
|
func OpenAsset(file string) (io.ReadCloser, int64, error) {
|
||||||
path, info, err := getAssetFileLocation(file)
|
path, info, err := getAssetFileLocation(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -43,11 +36,6 @@ func OpenAsset(file string) (io.ReadCloser, int64, error) {
|
|||||||
return r, info.Size(), err
|
return r, info.Size(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatAsset(file string) (os.FileInfo, error) {
|
|
||||||
_, info, err := getAssetFileLocation(file)
|
|
||||||
return info, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResolveAsset(file string) (string, error) {
|
func ResolveAsset(file string) (string, error) {
|
||||||
path, _, err := getAssetFileLocation(file)
|
path, _, err := getAssetFileLocation(file)
|
||||||
return path, err
|
return path, err
|
||||||
@@ -79,17 +67,29 @@ func ReadCert(file string) ([]byte, error) {
|
|||||||
return ReadFile(platform.GetCertLocation(file))
|
return ReadFile(platform.GetCertLocation(file))
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyFile(dst string, src string) error {
|
// ResolveLuaFile finds a local .lua script and returns its absolute path.
|
||||||
bytes, err := ReadFile(src)
|
// Relative paths: XRAY_LOCATION_CONFDIR > XRAY_LOCATION_CONFIG > working dir > executable dir.
|
||||||
if err != nil {
|
func ResolveLuaFile(path string) (string, error) {
|
||||||
return err
|
if !strings.EqualFold(filepath.Ext(path), ".lua") {
|
||||||
|
return "", errors.New("Lua file extension must be .lua")
|
||||||
}
|
}
|
||||||
f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0o644)
|
if filepath.IsAbs(path) {
|
||||||
if err != nil {
|
return path, nil
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
defer f.Close()
|
for _, dir := range []string{
|
||||||
|
platform.GetConfDirPath(),
|
||||||
_, err = f.Write(bytes)
|
platform.NewEnvFlag(platform.ConfigLocation).GetValue(func() string { return "" }),
|
||||||
return err
|
".",
|
||||||
|
platform.GetExecutableDir(),
|
||||||
|
} {
|
||||||
|
if dir != "" {
|
||||||
|
resolved := filepath.Join(dir, path)
|
||||||
|
if _, err := os.Stat(resolved); err == nil {
|
||||||
|
return filepath.Abs(resolved)
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", os.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
package filesystem_test
|
package filesystem_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/platform"
|
||||||
. "github.com/xtls/xray-core/common/platform/filesystem"
|
. "github.com/xtls/xray-core/common/platform/filesystem"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStatAssetRejectsInvalidPath(t *testing.T) {
|
func TestResolveAssetRejectsInvalidPath(t *testing.T) {
|
||||||
for _, file := range []string{
|
for _, file := range []string{
|
||||||
"",
|
"",
|
||||||
".",
|
".",
|
||||||
@@ -25,8 +29,49 @@ func TestStatAssetRejectsInvalidPath(t *testing.T) {
|
|||||||
`nested\..\geoip.dat`,
|
`nested\..\geoip.dat`,
|
||||||
filepath.Join(t.TempDir(), "geoip.dat"),
|
filepath.Join(t.TempDir(), "geoip.dat"),
|
||||||
} {
|
} {
|
||||||
if _, err := StatAsset(file); err == nil {
|
if _, err := ResolveAsset(file); err == nil {
|
||||||
t.Fatalf("expected error for %q", file)
|
t.Fatalf("expected error for %q", file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResolveLuaFile(t *testing.T) {
|
||||||
|
t.Chdir(t.TempDir())
|
||||||
|
workingDir, err := os.Getwd()
|
||||||
|
common.Must(err)
|
||||||
|
executable, err := os.Executable()
|
||||||
|
common.Must(err)
|
||||||
|
file, err := os.CreateTemp(filepath.Dir(executable), "lua-*.lua")
|
||||||
|
common.Must(err)
|
||||||
|
common.Must(file.Close())
|
||||||
|
defer os.Remove(file.Name())
|
||||||
|
|
||||||
|
name := filepath.Base(file.Name())
|
||||||
|
paths := []string{
|
||||||
|
filepath.Join(t.TempDir(), name),
|
||||||
|
filepath.Join(t.TempDir(), name),
|
||||||
|
filepath.Join(workingDir, name),
|
||||||
|
file.Name(),
|
||||||
|
}
|
||||||
|
t.Setenv(platform.ConfdirLocation, filepath.Dir(paths[0]))
|
||||||
|
t.Setenv(platform.ConfigLocation, filepath.Dir(paths[1]))
|
||||||
|
for _, path := range paths[:3] {
|
||||||
|
common.Must(os.WriteFile(path, nil, 0o600))
|
||||||
|
}
|
||||||
|
if got, err := ResolveLuaFile(paths[2]); err != nil || got != paths[2] {
|
||||||
|
t.Fatalf("absolute path = %q, %v; want %q", got, err, paths[2])
|
||||||
|
}
|
||||||
|
for i, want := range paths {
|
||||||
|
if i == 2 {
|
||||||
|
t.Setenv(platform.ConfdirLocation, "")
|
||||||
|
t.Setenv(platform.ConfigLocation, "")
|
||||||
|
}
|
||||||
|
if got, err := ResolveLuaFile(name); err != nil || got != want {
|
||||||
|
t.Fatalf("resolved path = %q, %v; want %q", got, err, want)
|
||||||
|
}
|
||||||
|
common.Must(os.Remove(want))
|
||||||
|
}
|
||||||
|
if _, err := ResolveLuaFile(name); !errors.Is(err, os.ErrNotExist) {
|
||||||
|
t.Fatalf("missing file error = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func LineSeparator() string {
|
|||||||
|
|
||||||
// GetAssetLocation searches for `file` in the env dir, the executable dir, and certain locations
|
// GetAssetLocation searches for `file` in the env dir, the executable dir, and certain locations
|
||||||
func GetAssetLocation(file string) string {
|
func GetAssetLocation(file string) string {
|
||||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
assetPath := NewEnvFlag(AssetLocation).GetValue(GetExecutableDir)
|
||||||
defPath := filepath.Join(assetPath, file)
|
defPath := filepath.Join(assetPath, file)
|
||||||
for _, p := range []string{
|
for _, p := range []string{
|
||||||
defPath,
|
defPath,
|
||||||
@@ -36,6 +36,6 @@ func GetAssetLocation(file string) string {
|
|||||||
|
|
||||||
// GetCertLocation searches for `file` in the env dir and the executable dir
|
// GetCertLocation searches for `file` in the env dir and the executable dir
|
||||||
func GetCertLocation(file string) string {
|
func GetCertLocation(file string) string {
|
||||||
certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir)
|
certPath := NewEnvFlag(CertLocation).GetValue(GetExecutableDir)
|
||||||
return filepath.Join(certPath, file)
|
return filepath.Join(certPath, file)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package platform // import "github.com/xtls/xray-core/common/platform"
|
package platform // import "github.com/xtls/xray-core/common/platform"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -74,7 +72,7 @@ func NormalizeEnvName(name string) string {
|
|||||||
return strings.ReplaceAll(strings.ToUpper(strings.TrimSpace(name)), ".", "_")
|
return strings.ReplaceAll(strings.ToUpper(strings.TrimSpace(name)), ".", "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExecutableDir() string {
|
func GetExecutableDir() string {
|
||||||
exec, err := os.Executable()
|
exec, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
@@ -83,7 +81,7 @@ func getExecutableDir() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetConfigurationPath() string {
|
func GetConfigurationPath() string {
|
||||||
configPath := NewEnvFlag(ConfigLocation).GetValue(getExecutableDir)
|
configPath := NewEnvFlag(ConfigLocation).GetValue(GetExecutableDir)
|
||||||
return filepath.Join(configPath, "config.json")
|
return filepath.Join(configPath, "config.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,64 +90,3 @@ func GetConfDirPath() string {
|
|||||||
configPath := NewEnvFlag(ConfdirLocation).GetValue(func() string { return "" })
|
configPath := NewEnvFlag(ConfdirLocation).GetValue(func() string { return "" })
|
||||||
return configPath
|
return configPath
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveLuaFile finds a local .lua script and returns its resolved absolute path.
|
|
||||||
// Relative paths: XRAY_LOCATION_CONFDIR > XRAY_LOCATION_CONFIG > working dir > executable dir.
|
|
||||||
func ResolveLuaFile(path string) (string, error) {
|
|
||||||
if path == "" {
|
|
||||||
return "", errors.New("Lua file path is empty")
|
|
||||||
}
|
|
||||||
paths := []string{path}
|
|
||||||
if !filepath.IsAbs(path) {
|
|
||||||
paths = nil
|
|
||||||
for _, dir := range []string{
|
|
||||||
GetConfDirPath(),
|
|
||||||
NewEnvFlag(ConfigLocation).GetValue(func() string { return "" }),
|
|
||||||
".",
|
|
||||||
getExecutableDir(),
|
|
||||||
} {
|
|
||||||
if dir != "" {
|
|
||||||
paths = append(paths, filepath.Join(dir, path))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
path, err := resolveFile(paths)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return resolveLuaTarget(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveLuaTarget(path string) (string, error) {
|
|
||||||
path, err := filepath.EvalSymlinks(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to resolve Lua file symlinks: %w", err)
|
|
||||||
}
|
|
||||||
if filepath.Ext(path) != ".lua" {
|
|
||||||
return "", errors.New("Lua file extension must be .lua")
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveFile(paths []string) (string, error) {
|
|
||||||
var tried []string
|
|
||||||
for _, path := range paths {
|
|
||||||
path, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to resolve file path: %w", err)
|
|
||||||
}
|
|
||||||
tried = append(tried, path)
|
|
||||||
info, err := os.Stat(path)
|
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to inspect file %q: %w", path, err)
|
|
||||||
}
|
|
||||||
if !info.Mode().IsRegular() {
|
|
||||||
return "", fmt.Errorf("file is not a regular file: %s", path)
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("file not found; tried %q: %w", tried, os.ErrNotExist)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package platform_test
|
package platform_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
@@ -66,89 +64,3 @@ func TestGetAssetLocation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveLuaFile(t *testing.T) {
|
|
||||||
workingDir := t.TempDir()
|
|
||||||
t.Chdir(workingDir)
|
|
||||||
executable, err := os.Executable()
|
|
||||||
common.Must(err)
|
|
||||||
file, err := os.CreateTemp(filepath.Dir(executable), "lua-*.lua")
|
|
||||||
common.Must(err)
|
|
||||||
common.Must(file.Close())
|
|
||||||
defer os.Remove(file.Name())
|
|
||||||
|
|
||||||
name := filepath.Base(file.Name())
|
|
||||||
paths := []string{
|
|
||||||
filepath.Join(t.TempDir(), name),
|
|
||||||
filepath.Join(t.TempDir(), name),
|
|
||||||
filepath.Join(workingDir, name),
|
|
||||||
file.Name(),
|
|
||||||
}
|
|
||||||
t.Setenv(ConfdirLocation, filepath.Dir(paths[0]))
|
|
||||||
t.Setenv(ConfigLocation, filepath.Dir(paths[1]))
|
|
||||||
for _, path := range paths[:3] {
|
|
||||||
common.Must(os.WriteFile(path, nil, 0o600))
|
|
||||||
}
|
|
||||||
for i, path := range paths {
|
|
||||||
paths[i], err = filepath.EvalSymlinks(path)
|
|
||||||
common.Must(err)
|
|
||||||
}
|
|
||||||
if got, err := ResolveLuaFile(paths[2]); err != nil || got != paths[2] {
|
|
||||||
t.Fatalf("absolute path = %q, %v; want %q", got, err, paths[2])
|
|
||||||
}
|
|
||||||
for i, want := range paths {
|
|
||||||
if i == 2 {
|
|
||||||
t.Setenv(ConfdirLocation, "")
|
|
||||||
t.Setenv(ConfigLocation, "")
|
|
||||||
}
|
|
||||||
if got, err := ResolveLuaFile(name); err != nil || got != want {
|
|
||||||
t.Fatalf("resolved path = %q, %v; want %q", got, err, want)
|
|
||||||
}
|
|
||||||
common.Must(os.Remove(want))
|
|
||||||
}
|
|
||||||
if _, err := ResolveLuaFile(name); !errors.Is(err, os.ErrNotExist) {
|
|
||||||
t.Fatalf("missing file error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Setenv(ConfdirLocation, filepath.Dir(paths[0]))
|
|
||||||
t.Setenv(ConfigLocation, filepath.Dir(paths[1]))
|
|
||||||
common.Must(os.Mkdir(paths[0], 0o700))
|
|
||||||
common.Must(os.WriteFile(paths[1], nil, 0o600))
|
|
||||||
for _, path := range []string{"", name, filepath.Join(t.TempDir(), name)} {
|
|
||||||
if _, err := ResolveLuaFile(path); err == nil {
|
|
||||||
t.Fatalf("accepted invalid path %q", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResolveLuaFileSymlink(t *testing.T) {
|
|
||||||
for _, tc := range []struct {
|
|
||||||
link, target string
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{"alias.lua", "data.dat", false},
|
|
||||||
{"alias.dat", "script.lua", true},
|
|
||||||
} {
|
|
||||||
t.Run(tc.link, func(t *testing.T) {
|
|
||||||
dir, err := filepath.EvalSymlinks(t.TempDir())
|
|
||||||
common.Must(err)
|
|
||||||
target := filepath.Join(dir, tc.target)
|
|
||||||
common.Must(os.WriteFile(target, nil, 0o600))
|
|
||||||
link := filepath.Join(dir, tc.link)
|
|
||||||
if err := os.Symlink(tc.target, link); err != nil {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
t.Skipf("cannot create symlinks: %v", err)
|
|
||||||
}
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
got, err := ResolveLuaFile(link)
|
|
||||||
if tc.valid {
|
|
||||||
if err != nil || got != target {
|
|
||||||
t.Fatalf("ResolveLuaFile(%q) = %q, %v; want %q", link, got, err, target)
|
|
||||||
}
|
|
||||||
} else if err == nil || got != "" || !strings.Contains(err.Error(), "Lua file extension must be .lua") {
|
|
||||||
t.Fatalf("ResolveLuaFile(%q) = %q, %v; want .lua extension error", link, got, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ func LineSeparator() string {
|
|||||||
|
|
||||||
// GetAssetLocation searches for `file` in the env dir and the executable dir
|
// GetAssetLocation searches for `file` in the env dir and the executable dir
|
||||||
func GetAssetLocation(file string) string {
|
func GetAssetLocation(file string) string {
|
||||||
assetPath := NewEnvFlag(AssetLocation).GetValue(getExecutableDir)
|
assetPath := NewEnvFlag(AssetLocation).GetValue(GetExecutableDir)
|
||||||
return filepath.Join(assetPath, file)
|
return filepath.Join(assetPath, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCertLocation searches for `file` in the env dir and the executable dir
|
// GetCertLocation searches for `file` in the env dir and the executable dir
|
||||||
func GetCertLocation(file string) string {
|
func GetCertLocation(file string) string {
|
||||||
certPath := NewEnvFlag(CertLocation).GetValue(getExecutableDir)
|
certPath := NewEnvFlag(CertLocation).GetValue(GetExecutableDir)
|
||||||
return filepath.Join(certPath, file)
|
return filepath.Join(certPath, file)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11
|
//go:generate go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||||
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.6.0
|
//go:generate go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||||
//go:generate go run ../infra/vprotogen/main.go -pwd ./..
|
//go:generate go run ../infra/vprotogen/main.go -pwd ./..
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func (c *GeodataAssetConfig) Build() (*geodata.Asset, error) {
|
|||||||
if err := validateHTTPS(c.URL); err != nil {
|
if err := validateHTTPS(c.URL); err != nil {
|
||||||
return nil, errors.New("invalid geodata asset url: ", c.URL).Base(err)
|
return nil, errors.New("invalid geodata asset url: ", c.URL).Base(err)
|
||||||
}
|
}
|
||||||
if _, err := filesystem.StatAsset(c.File); err != nil {
|
if _, err := filesystem.ResolveAsset(c.File); err != nil {
|
||||||
return nil, errors.New("invalid geodata asset file: ", c.File).Base(err)
|
return nil, errors.New("invalid geodata asset file: ", c.File).Base(err)
|
||||||
}
|
}
|
||||||
return &geodata.Asset{
|
return &geodata.Asset{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package lua
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
xlua "github.com/xtls/xray-core/common/lua"
|
xlua "github.com/xtls/xray-core/common/lua"
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
@@ -32,14 +33,13 @@ func executeSign(cmd *base.Command, args []string) {
|
|||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(filepath.Ext(args[0]), ".lua") {
|
||||||
|
base.Fatalf("Lua file extension must be .lua")
|
||||||
|
}
|
||||||
info, err := os.Stat(args[0])
|
info, err := os.Stat(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("failed to inspect Lua file: %s", err)
|
base.Fatalf("failed to inspect Lua file: %s", err)
|
||||||
}
|
}
|
||||||
if !info.Mode().IsRegular() {
|
|
||||||
base.Fatalf("Lua input is not a regular file: %s", args[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
code, err := os.ReadFile(args[0])
|
code, err := os.ReadFile(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("failed to read Lua file: %s", err)
|
base.Fatalf("failed to read Lua file: %s", err)
|
||||||
@@ -67,14 +67,7 @@ func executeSign(cmd *base.Command, args []string) {
|
|||||||
|
|
||||||
func writeSignedFile(path string, code []byte, mode os.FileMode) error {
|
func writeSignedFile(path string, code []byte, mode os.FileMode) error {
|
||||||
if info, err := os.Stat(path); err == nil {
|
if info, err := os.Stat(path); err == nil {
|
||||||
if !info.Mode().IsRegular() {
|
|
||||||
return &os.PathError{Op: "write", Path: path, Err: os.ErrInvalid}
|
|
||||||
}
|
|
||||||
mode = info.Mode().Perm()
|
mode = info.Mode().Perm()
|
||||||
path, err = filepath.EvalSymlinks(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if !os.IsNotExist(err) {
|
} else if !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-10
@@ -58,18 +58,10 @@ func readConfigFile(file *os.File) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if info.Mode().IsRegular() {
|
if info.Mode().IsRegular() {
|
||||||
path, err := filepath.Abs(file.Name())
|
switch strings.ToLower(filepath.Ext(file.Name())) {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
path, err = filepath.EvalSymlinks(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch strings.ToLower(filepath.Ext(path)) {
|
|
||||||
case ".jsonc", ".json", ".yml", ".yaml", ".toml", ".pb", ".protobuf":
|
case ".jsonc", ".json", ".yml", ".yaml", ".toml", ".pb", ".protobuf":
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unsupported config file extension: ", path)
|
return nil, errors.New("unsupported config file extension: ", file.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return io.ReadAll(file)
|
return io.ReadAll(file)
|
||||||
|
|||||||
+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,13 +65,6 @@ 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
|
||||||
@@ -93,6 +86,13 @@ 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\x12C\n" +
|
"\x06Config\x12D\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\x12'\n" +
|
"\bport_map\x18\x03 \x03(\v2(.xray.proxy.dokodemo.Config.PortMapEntryR\aportMap\x12C\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.Network)(0), // 2: xray.common.net.Network
|
(*net.IPOrDomain)(nil), // 2: xray.common.net.IPOrDomain
|
||||||
(*net.IPOrDomain)(nil), // 3: xray.common.net.IPOrDomain
|
(net.Network)(0), // 3: xray.common.net.Network
|
||||||
}
|
}
|
||||||
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
var file_proxy_dokodemo_config_proto_depIdxs = []int32{
|
||||||
2, // 0: xray.proxy.dokodemo.Config.allowed_networks:type_name -> xray.common.net.Network
|
2, // 0: xray.proxy.dokodemo.Config.rewrite_address:type_name -> xray.common.net.IPOrDomain
|
||||||
3, // 1: xray.proxy.dokodemo.Config.rewrite_address:type_name -> xray.common.net.IPOrDomain
|
1, // 1: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
|
||||||
1, // 2: xray.proxy.dokodemo.Config.port_map:type_name -> xray.proxy.dokodemo.Config.PortMapEntry
|
3, // 2: xray.proxy.dokodemo.Config.allowed_networks:type_name -> xray.common.net.Network
|
||||||
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,11 +7,12 @@
|
|||||||
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