Merge pull request #2667 from v2fly/master

merge fly
pull/2700/head v4.27.0
Kslr 4 years ago committed by GitHub
commit 90a61a5b04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,43 @@
name: Release Docker Image
on:
push:
tags:
- v*
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Set up Checkout
uses: actions/checkout@v2
- name: Install Buildx and QEMU
run: |
export DOCKER_BUILDKIT=1
docker build --platform=local -o . git://github.com/docker/buildx
mkdir -p ~/.docker/cli-plugins
mv buildx ~/.docker/cli-plugins/docker-buildx
docker run --rm --privileged multiarch/qemu-user-static:latest --reset -p yes --credential yes
docker buildx create --use --name build --node build --driver-opt network=host
- name: Log in to Docker Hub
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
echo "${DOCKER_PASSWORD}" | docker login --username ${DOCKER_USERNAME} --password-stdin
- name: Build and push Docker image
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_IMAGE_PLATFORM: linux/386,linux/amd64,linux/arm/v7,linux/arm64
run: |
DOCKER_IMAGE_NAME=$(echo $DOCKER_USERNAME | tr '[:upper:]' '[:lower:]')/v2fly-core
DOCKER_IMAGE_VERSION=${GITHUB_REF#refs/*/}
docker buildx build \
--platform "$DOCKER_IMAGE_PLATFORM" \
--output "type=image,push=true" \
--tag "$DOCKER_IMAGE_NAME":"$DOCKER_IMAGE_VERSION" \
--tag "$DOCKER_IMAGE_NAME":latest \
--file ./Dockerfile .

@ -2,7 +2,7 @@
# STEP 1 build executable binary
############################
FROM golang:alpine AS builder
RUN apk update && apk add --no-cache git bash wget
RUN apk update && apk add --no-cache git bash wget curl
WORKDIR /go/src/v2ray.com/core
RUN git clone --progress https://github.com/v2fly/v2ray-core.git . && \
bash ./release/user-package.sh nosource noconf codename=$(git describe --tags) buildname=docker-fly abpathtgz=/tmp/v2ray.tgz

@ -58,6 +58,7 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, clientIP net.
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
@ -89,7 +90,8 @@ func NewDoHLocalNameServer(url *url.URL, clientIP net.IP) *DoHNameServer {
url.Scheme = "https"
s := baseDOHNameServer(url, "DOHL", clientIP)
tr := &http.Transport{
IdleConnTimeout: 90 * time.Second,
IdleConnTimeout: 90 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {

@ -150,6 +150,13 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
return nil, newError("not a ReceiverConfig").AtError()
}
streamSettings := receiverSettings.StreamSettings
if streamSettings != nil && streamSettings.SocketSettings != nil {
ctx = session.ContextWithSockopt(ctx, &session.Sockopt{
Mark: streamSettings.SocketSettings.Mark,
})
}
allocStrategy := receiverSettings.AllocationStrategy
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)

@ -1,22 +0,0 @@
jobs:
- job: ${{ parameters.name }}
timeoutInMinutes: 30
pool:
vmImage: ${{ parameters.vmImage }}
steps:
- checkout: self
- task: GoTool@0
inputs:
version: '1.14'
- script: |
go test -p 1 -v -timeout 30m ./...
workingDirectory: '$(Build.SourcesDirectory)'
displayName: 'Test'
- script: |
go build ./common/buf
condition: always()
workingDirectory: '$(Build.SourcesDirectory)'
displayName: 'Test Buf error'

@ -2,71 +2,25 @@ trigger:
batch: true
branches:
include:
- master
- dev*
- refs/tags/*
- master
- dev*
- refs/tags/*
pr:
- master
- dev*
pool:
vmImage: 'ubuntu-latest'
jobs:
- template: azure-pipelines.template.yml
parameters:
name: linux
vmImage: 'ubuntu-latest'
variables:
- group: GithubToken
- name: GOPATH
value: '$(system.defaultWorkingDirectory)/gopath'
- name: BAZEL_VER
value: '0.23.0'
- template: azure-pipelines.template.yml
parameters:
name: windows
vmImage: 'windows-latest'
- template: azure-pipelines.template.yml
parameters:
name: macos
vmImage: 'macOS-latest'
- job: linux_coverage
dependsOn: linux
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
timeoutInMinutes: 30
pool:
vmImage: 'ubuntu-latest'
#variables:
# CODECOV_TOKEN: '$(coverage.token)'
steps:
- checkout: self
- task: GoTool@0
inputs:
version: '1.14.4'
- script: |
bash ./testing/coverage/coverall
workingDirectory: '$(Build.SourcesDirectory)'
displayName: 'Coverage'
- job: make_release
dependsOn: linux
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
timeoutInMinutes: 60
pool:
vmImage: 'ubuntu-latest'
variables:
- group: GithubToken
- name: GOPATH
value: '$(system.defaultWorkingDirectory)/gopath'
- name: BAZEL_VER
value: '0.23.0'
steps:
steps:
- checkout: self
- task: GoTool@0
inputs:
version: '1.14.4'
version: '1.14.6'
- script: |
mkdir triggersrc
ls -I "triggersrc" | xargs cp -rf -t triggersrc

@ -22,7 +22,7 @@ func TestBufferClear(t *testing.T) {
buffer.Clear()
if buffer.Len() != 0 {
t.Error("expect 0 lenght, but got ", buffer.Len())
t.Error("expect 0 length, but got ", buffer.Len())
}
}

@ -248,13 +248,14 @@ func (w *AuthenticationWriter) seal(b []byte) (*buf.Buffer, error) {
paddingSize = int32(w.padding.NextPaddingLen())
}
totalSize := encryptedSize + paddingSize
sizeBytes := w.sizeParser.SizeBytes()
totalSize := sizeBytes + encryptedSize + paddingSize
if totalSize > buf.Size {
return nil, newError("size too large: ", totalSize)
}
eb := buf.New()
w.sizeParser.Encode(uint16(encryptedSize+paddingSize), eb.Extend(w.sizeParser.SizeBytes()))
w.sizeParser.Encode(uint16(encryptedSize+paddingSize), eb.Extend(sizeBytes))
if _, err := w.auth.Seal(eb.Extend(encryptedSize)[:0], b); err != nil {
eb.Release()
return nil, err

@ -35,7 +35,7 @@ func (s *Server) Type() interface{} {
return s.dispatcher.Type()
}
// Dispatch impliments routing.Dispatcher
// Dispatch implements routing.Dispatcher
func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
if dest.Address != muxCoolAddress {
return s.dispatcher.Dispatch(ctx, dest)

@ -10,6 +10,7 @@ const (
outboundSessionKey
contentSessionKey
muxPreferedSessionKey
sockoptSessionKey
)
// ContextWithID returns a new context with the given ID.
@ -70,3 +71,16 @@ func MuxPreferedFromContext(ctx context.Context) bool {
}
return false
}
// ContextWithSockopt returns a new context with Socket configs included
func ContextWithSockopt(ctx context.Context, s *Sockopt) context.Context {
return context.WithValue(ctx, sockoptSessionKey, s)
}
// SockoptFromContext returns Socket configs in this context, or nil if not contained.
func SockoptFromContext(ctx context.Context) *Sockopt {
if sockopt, ok := ctx.Value(sockoptSessionKey).(*Sockopt); ok {
return sockopt
}
return nil
}

@ -72,6 +72,12 @@ type Content struct {
SkipRoutePick bool
}
// Sockopt is the settings for socket connection.
type Sockopt struct {
// Mark of the socket connection.
Mark int32
}
func (c *Content) SetAttribute(name string, value interface{}) {
if c.Attributes == nil {
c.Attributes = make(map[string]interface{})

@ -19,7 +19,7 @@ import (
)
var (
version = "4.26.0"
version = "4.27.0"
build = "Custom"
codename = "V2Fly, a community-driven edition of V2Ray."
intro = "A unified platform for anti-censorship."

@ -22,7 +22,7 @@ type Counter interface {
type Manager interface {
features.Feature
// RegisterCounter registers a new counter to the manager. The identifier string must not be emtpy, and unique among other counters.
// RegisterCounter registers a new counter to the manager. The identifier string must not be empty, and unique among other counters.
RegisterCounter(string) (Counter, error)
UnregisterCounter(string) error
// GetCounter returns a counter by its identifier.

@ -2,12 +2,11 @@ module v2ray.com/core
require (
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect
github.com/golang/mock v1.4.3
github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.4.2
github.com/google/go-cmp v0.5.0
github.com/google/go-cmp v0.5.1
github.com/gorilla/websocket v1.4.2
github.com/miekg/dns v1.1.29
github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57
github.com/miekg/dns v1.1.31
github.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841
github.com/stretchr/testify v1.6.1
github.com/xiaokangwang/VSign v0.0.0-20200704130305-63f4b4d7a751
@ -16,7 +15,7 @@ require (
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
google.golang.org/grpc v1.30.0
google.golang.org/grpc v1.31.0
google.golang.org/protobuf v1.25.0
h12.io/socks v1.0.1
)

@ -18,6 +18,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
github.com/golang/mock v1.4.3/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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -38,19 +40,23 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364 h1:5XxdakFhqd9dnXoAZy1Mb2R/DZ6D1e+0bGC/JhucGYI=
github.com/h12w/go-socks5 v0.0.0-20200522160539-76189e178364/go.mod h1:eDJQioIyy4Yn3MVivT7rv/39gAJTrA7lgmYr8EW950c=
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo=
github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57 h1:SL1K0QAuC1b54KoY1pjPWe6kSlsFHwK9/oC960fKrTY=
github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0=
github.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841 h1:pnfutQFsV7ySmHUeX6ANGfPsBo29RctUvDn8G3rmJVw=
github.com/seiflotfy/cuckoofilter v0.0.0-20200511222245-56093a4d3841/go.mod h1:ET5mVvNjwaGXRgZxO9UZr7X+8eAf87AfIYNwRSp9s4Y=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -126,6 +132,8 @@ google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
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=

@ -3,7 +3,7 @@ def _go_command(ctx):
if ctx.attr.os == "windows":
output = output + ".exe"
output_file = ctx.actions.declare_file(ctx.attr.os + "/" + ctx.attr.arch + "/" + output)
output_file = ctx.actions.declare_file(ctx.attr.os + "/" + ctx.attr.arch + "/" + ctx.attr.ver + "/" + output)
pkg = ctx.attr.pkg
ld_flags = "-s -w"
@ -61,6 +61,7 @@ foreign_go_binary = rule(
'output': attr.string(),
'os': attr.string(mandatory=True),
'arch': attr.string(mandatory=True),
'ver': attr.string(mandatory=True),
'mips': attr.string(),
'arm': attr.string(),
'ld': attr.string(),

@ -1,22 +1,25 @@
SUPPORTED_MATRIX = [
("windows", "amd64"),
("windows", "386"),
("windows", "arm"),
("darwin", "amd64"),
("linux", "amd64"),
("linux", "386"),
("linux", "arm64"),
("linux", "arm"),
("linux", "mips64"),
("linux", "mips"),
("linux", "mips64le"),
("linux", "mipsle"),
("linux", "ppc64"),
("linux", "ppc64le"),
("linux", "s390x"),
("freebsd", "amd64"),
("freebsd", "386"),
("openbsd", "amd64"),
("openbsd", "386"),
("dragonfly", "amd64"),
("windows", "amd64", "0"),
("windows", "386", "0"),
("windows", "arm", "7"),
("darwin", "amd64", "0"),
("linux", "amd64", "0"),
("linux", "386", "0"),
("linux", "arm64", "0"),
("linux", "arm", "7"),
("linux", "arm", "6"),
("linux", "arm", "5"),
("linux", "mips64", "0"),
("linux", "mips", "0"),
("linux", "mips64le", "0"),
("linux", "mipsle", "0"),
("linux", "ppc64", "0"),
("linux", "ppc64le", "0"),
("linux", "riscv64", "0"),
("linux", "s390x", "0"),
("freebsd", "amd64", "0"),
("freebsd", "386", "0"),
("openbsd", "amd64", "0"),
("openbsd", "386", "0"),
("dragonfly", "amd64", "0"),
]

@ -260,9 +260,19 @@ func parseDomainRule(domain string) ([]*router.Domain, error) {
}
return domains, nil
}
if strings.HasPrefix(domain, "ext:") {
kv := strings.Split(domain[4:], ":")
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(domain, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-domain:"
if strings.HasPrefix(domain, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(domain[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", domain)
}
@ -314,9 +324,19 @@ func toCidrList(ips StringList) ([]*router.GeoIP, error) {
})
continue
}
if strings.HasPrefix(ip, "ext:") {
kv := strings.Split(ip[4:], ":")
var isExtDatFile = 0
{
const prefix = "ext:"
if strings.HasPrefix(ip, prefix) {
isExtDatFile = len(prefix)
}
const prefixQualified = "ext-ip:"
if strings.HasPrefix(ip, prefixQualified) {
isExtDatFile = len(prefixQualified)
}
}
if isExtDatFile != 0 {
kv := strings.Split(ip[isExtDatFile:], ":")
if len(kv) != 2 {
return nil, newError("invalid external resource: ", ip)
}

@ -26,6 +26,8 @@ func cipherFromString(c string) shadowsocks.CipherType {
return shadowsocks.CipherType_AES_256_GCM
case "chacha20-poly1305", "aead_chacha20_poly1305", "chacha20-ietf-poly1305":
return shadowsocks.CipherType_CHACHA20_POLY1305
case "none", "plain":
return shadowsocks.CipherType_NONE
default:
return shadowsocks.CipherType_UNKNOWN
}

@ -19,6 +19,7 @@ var (
"http": func() interface{} { return new(HttpServerConfig) },
"shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) },
"socks": func() interface{} { return new(SocksServerConfig) },
"vless": func() interface{} { return new(VLessInboundConfig) },
"vmess": func() interface{} { return new(VMessInboundConfig) },
"mtproto": func() interface{} { return new(MTProtoServerConfig) },
}, "protocol", "settings")
@ -28,8 +29,9 @@ var (
"freedom": func() interface{} { return new(FreedomConfig) },
"http": func() interface{} { return new(HttpClientConfig) },
"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
"vmess": func() interface{} { return new(VMessOutboundConfig) },
"socks": func() interface{} { return new(SocksClientConfig) },
"vless": func() interface{} { return new(VLessOutboundConfig) },
"vmess": func() interface{} { return new(VMessOutboundConfig) },
"mtproto": func() interface{} { return new(MTProtoClientConfig) },
"dns": func() interface{} { return new(DnsOutboundConfig) },
}, "protocol", "settings")

@ -0,0 +1,175 @@
package conf
import (
"encoding/json"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/inbound"
"v2ray.com/core/proxy/vless/outbound"
)
type VLessInboundFallback struct {
Addr *Address `json:"addr"`
Port uint16 `json:"port"`
Unix string `json:"unix"`
Xver uint16 `json:"xver"`
}
type VLessInboundConfig struct {
Users []json.RawMessage `json:"clients"`
Decryption string `json:"decryption"`
Fallback *VLessInboundFallback `json:"fallback"`
Fallback_h2 *VLessInboundFallback `json:"fallback_h2"`
}
// Build implements Buildable
func (c *VLessInboundConfig) Build() (proto.Message, error) {
config := new(inbound.Config)
if c.Decryption != "none" {
return nil, newError(`please add/set "decryption":"none" directly to every VLESS "settings"`)
}
config.Decryption = c.Decryption
if c.Fallback != nil {
if c.Fallback.Xver > 2 {
return nil, newError(`VLESS "fallback": invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
if c.Fallback.Unix != "" {
if c.Fallback.Unix[0] == '@' {
c.Fallback.Unix = "\x00" + c.Fallback.Unix[1:]
}
} else {
if c.Fallback.Port == 0 {
return nil, newError(`please fill in a valid value for "port" in VLESS "fallback"`)
}
}
if c.Fallback.Addr == nil {
c.Fallback.Addr = &Address{
Address: net.ParseAddress("127.0.0.1"),
}
}
config.Fallback = &inbound.Fallback{
Addr: c.Fallback.Addr.Build(),
Port: uint32(c.Fallback.Port),
Unix: c.Fallback.Unix,
Xver: uint32(c.Fallback.Xver),
}
}
if c.Fallback_h2 != nil {
if config.Fallback == nil {
return nil, newError(`VLESS "fallback_h2" can't exist alone without "fallback"`)
}
if c.Fallback_h2.Xver > 2 {
return nil, newError(`VLESS "fallback_h2": invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
if c.Fallback_h2.Unix != "" {
if c.Fallback_h2.Unix[0] == '@' {
c.Fallback_h2.Unix = "\x00" + c.Fallback_h2.Unix[1:]
}
} else {
if c.Fallback_h2.Port == 0 {
return nil, newError(`please fill in a valid value for "port" in VLESS "fallback_h2"`)
}
}
if c.Fallback_h2.Addr == nil {
c.Fallback_h2.Addr = &Address{
Address: net.ParseAddress("127.0.0.1"),
}
}
config.FallbackH2 = &inbound.FallbackH2{
Addr: c.Fallback_h2.Addr.Build(),
Port: uint32(c.Fallback_h2.Port),
Unix: c.Fallback_h2.Unix,
Xver: uint32(c.Fallback_h2.Xver),
}
}
config.User = make([]*protocol.User, len(c.Users))
for idx, rawData := range c.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawData, user); err != nil {
return nil, newError("invalid VLESS user").Base(err)
}
account := new(vless.Account)
if err := json.Unmarshal(rawData, account); err != nil {
return nil, newError("invalid VLESS user").Base(err)
}
if account.Schedulers != "" {
return nil, newError(`VLESS attr "schedulers" is not available in this version`)
}
if account.Encryption != "" {
return nil, newError(`VLESS attr "encryption" should not in inbound settings`)
}
user.Account = serial.ToTypedMessage(account)
config.User[idx] = user
}
return config, nil
}
type VLessOutboundTarget struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`
}
type VLessOutboundConfig struct {
Receivers []*VLessOutboundTarget `json:"vnext"`
}
// Build implements Buildable
func (c *VLessOutboundConfig) Build() (proto.Message, error) {
config := new(outbound.Config)
if len(c.Receivers) == 0 {
return nil, newError("0 VLESS receiver configured")
}
serverSpecs := make([]*protocol.ServerEndpoint, len(c.Receivers))
for idx, rec := range c.Receivers {
if len(rec.Users) == 0 {
return nil, newError("0 user configured for VLESS outbound")
}
if rec.Address == nil {
return nil, newError("address is not set in VLESS outbound config")
}
spec := &protocol.ServerEndpoint{
Address: rec.Address.Build(),
Port: uint32(rec.Port),
}
for _, rawUser := range rec.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError("invalid VLESS user").Base(err)
}
account := new(vless.Account)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("invalid VLESS user").Base(err)
}
if account.Schedulers != "" {
return nil, newError(`VLESS attr "schedulers" is not available in this version`)
}
if account.Encryption != "none" {
return nil, newError(`please add/set "encryption":"none" for every VLESS user in "users"`)
}
user.Account = serial.ToTypedMessage(account)
spec.User = append(spec.User, user)
}
serverSpecs[idx] = spec
}
config.Receiver = serverSpecs
return config, nil
}

@ -0,0 +1,121 @@
package conf_test
import (
"testing"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
. "v2ray.com/core/infra/conf"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/inbound"
"v2ray.com/core/proxy/vless/outbound"
)
func TestVLessOutbound(t *testing.T) {
creator := func() Buildable {
return new(VLessOutboundConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"vnext": [{
"address": "example.com",
"port": 443,
"users": [
{
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
"schedulers": "",
"encryption": "none",
"level": 0
}
]
}]
}`,
Parser: loadJSON(creator),
Output: &outbound.Config{
Receiver: []*protocol.ServerEndpoint{
{
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Domain{
Domain: "example.com",
},
},
Port: 443,
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
Schedulers: "",
Encryption: "none",
}),
Level: 0,
},
},
},
},
},
},
})
}
func TestVLessInbound(t *testing.T) {
creator := func() Buildable {
return new(VLessInboundConfig)
}
runMultiTestCase(t, []TestCase{
{
Input: `{
"clients": [
{
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
"schedulers": "",
"level": 0,
"email": "love@v2fly.org"
}
],
"decryption": "none",
"fallback": {
"port": 80
},
"fallback_h2": {
"unix": "@/dev/shm/domain.socket",
"xver": 2
}
}`,
Parser: loadJSON(creator),
Output: &inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b",
Schedulers: "",
}),
Level: 0,
Email: "love@v2fly.org",
},
},
Decryption: "none",
Fallback: &inbound.Fallback{
Addr: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 80,
},
FallbackH2: &inbound.FallbackH2{
Addr: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Unix: "\x00/dev/shm/domain.socket",
Xver: 2,
},
},
},
})
}

@ -1,5 +1,3 @@
load("//infra/bazel:build.bzl", "foreign_go_binary")
load("//infra/bazel:gpg.bzl", "gpg_sign")
load("//infra/bazel:matrix.bzl", "SUPPORTED_MATRIX")
load("//infra/control/main:targets.bzl", "gen_targets")

@ -2,67 +2,21 @@ load("//infra/bazel:build.bzl", "foreign_go_binary")
load("//infra/bazel:gpg.bzl", "gpg_sign")
def gen_targets(matrix):
output = "v2ctl"
pkg = "v2ray.com/core/infra/control/main"
output = "v2ctl"
for (os, arch) in matrix:
bin_name = "v2ctl_" + os + "_" + arch
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output,
os = os,
arch = arch,
gotags = "confonly",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
if arch in ["mips", "mipsle"]:
bin_name = "v2ctl_" + os + "_" + arch + "_softfloat"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output + "_softfloat",
os = os,
arch = arch,
mips = "softfloat",
gotags = "confonly",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
for (os, arch, ver) in matrix:
if arch in ["arm"]:
bin_name = "v2ctl_" + os + "_" + arch + "_armv7"
bin_name = "v2ctl_" + os + "_" + arch + "_" + ver
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output + "_armv7",
os = os,
arch = arch,
arm = "7",
gotags = "confonly",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
bin_name = "v2ctl_" + os + "_" + arch + "_armv6"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output + "_armv6",
output = output,
os = os,
arch = arch,
arm = "6",
ver = ver,
arm = ver,
gotags = "confonly",
)
@ -71,14 +25,15 @@ def gen_targets(matrix):
base = ":" + bin_name,
)
bin_name = "v2ctl_" + os + "_" + arch + "_armv5"
else:
bin_name = "v2ctl_" + os + "_" + arch
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output,
os = os,
arch = arch,
arm = "5",
ver = ver,
gotags = "confonly",
)
@ -86,3 +41,21 @@ def gen_targets(matrix):
name = bin_name + "_sig",
base = ":" + bin_name,
)
if arch in ["mips", "mipsle"]:
bin_name = "v2ctl_" + os + "_" + arch + "_softfloat"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output + "_softfloat",
os = os,
arch = arch,
ver = ver,
mips = "softfloat",
gotags = "confonly",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)

@ -1,5 +1,3 @@
load("//infra/bazel:build.bzl", "foreign_go_binary")
load("//infra/bazel:gpg.bzl", "gpg_sign")
load("//infra/bazel:matrix.bzl", "SUPPORTED_MATRIX")
load("//main:targets.bzl", "gen_targets")

@ -31,6 +31,8 @@ import (
_ "v2ray.com/core/proxy/mtproto"
_ "v2ray.com/core/proxy/shadowsocks"
_ "v2ray.com/core/proxy/socks"
_ "v2ray.com/core/proxy/vless/inbound"
_ "v2ray.com/core/proxy/vless/outbound"
_ "v2ray.com/core/proxy/vmess/inbound"
_ "v2ray.com/core/proxy/vmess/outbound"

@ -5,125 +5,18 @@ def gen_targets(matrix):
pkg = "v2ray.com/core/main"
output = "v2ray"
for (os, arch) in matrix:
bin_name = "v2ray_" + os + "_" + arch
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output,
os = os,
arch = arch,
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
if os in ["windows"]:
bin_name = "v2ray_" + os + "_" + arch + "_nowindow"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = "w" + output,
os = os,
arch = arch,
ld = "-H windowsgui",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
bin_name = "v2ray_" + os + "_" + arch + "_armv7_nowindow"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = "w" + output + "_armv7",
os = os,
arch = arch,
arm = "7",
ld = "-H windowsgui",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
bin_name = "v2ray_" + os + "_" + arch + "_armv6_nowindow"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = "w" + output + "_armv6",
os = os,
arch = arch,
arm = "6",
ld = "-H windowsgui",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
bin_name = "v2ray_" + os + "_" + arch + "_armv5_nowindow"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = "w" + output,
os = os,
arch = arch,
arm = "5",
ld = "-H windowsgui",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
if arch in ["mips", "mipsle"]:
bin_name = "v2ray_" + os + "_" + arch + "_softfloat"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output+"_softfloat",
os = os,
arch = arch,
mips = "softfloat",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
for (os, arch, ver) in matrix:
if arch in ["arm"]:
bin_name = "v2ray_" + os + "_" + arch + "_armv7"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output + "_armv7",
os = os,
arch = arch,
arm = "7",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
bin_name = "v2ray_" + os + "_" + arch + "_armv6"
bin_name = "v2ray_" + os + "_" + arch + "_" + ver
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output + "_armv6",
output = output,
os = os,
arch = arch,
arm = "6",
ver = ver,
arm = ver,
)
gpg_sign(
@ -131,17 +24,70 @@ def gen_targets(matrix):
base = ":" + bin_name,
)
bin_name = "v2ray_" + os + "_" + arch + "_armv5"
if os in ["windows"]:
bin_name = "v2ray_" + os + "_" + arch + "_" + ver + "_nowindow"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = "w" + output,
os = os,
arch = arch,
ver = ver,
arm = ver,
ld = "-H windowsgui",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
else:
bin_name = "v2ray_" + os + "_" + arch
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output,
os = os,
arch = arch,
arm = "5",
ver = ver,
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
if os in ["windows"]:
bin_name = "v2ray_" + os + "_" + arch + "_nowindow"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = "w" + output,
os = os,
arch = arch,
ver = ver,
ld = "-H windowsgui",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)
if arch in ["mips", "mipsle"]:
bin_name = "v2ray_" + os + "_" + arch + "_softfloat"
foreign_go_binary(
name = bin_name,
pkg = pkg,
output = output + "_softfloat",
os = os,
arch = arch,
ver = ver,
mips = "softfloat",
)
gpg_sign(
name = bin_name + "_sig",
base = ":" + bin_name,
)

@ -12,6 +12,7 @@ import (
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/session"
@ -26,7 +27,7 @@ func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
d := new(DokodemoDoor)
err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
return d.Init(config.(*Config), pm)
return d.Init(config.(*Config), pm, session.SockoptFromContext(ctx))
})
return d, err
}))
@ -37,10 +38,11 @@ type DokodemoDoor struct {
config *Config
address net.Address
port net.Port
sockopt *session.Sockopt
}
// Init initializes the DokodemoDoor instance with necessary parameters.
func (d *DokodemoDoor) Init(config *Config, pm policy.Manager) error {
func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error {
if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 {
return newError("no network specified")
}
@ -48,6 +50,7 @@ func (d *DokodemoDoor) Init(config *Config, pm policy.Manager) error {
d.address = config.GetPredefinedAddress()
d.port = net.Port(config.Port)
d.policyManager = pm
d.sockopt = sockopt
return nil
}
@ -106,6 +109,14 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
}
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: conn.RemoteAddr(),
To: dest,
Status: log.AccessAccepted,
Reason: "",
})
newError("received request for ", conn.RemoteAddr()).WriteToLog(session.ExportIDToError(ctx))
plcy := d.policy()
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
@ -156,6 +167,9 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
sockopt.BindAddress = dest.Address.IP()
sockopt.BindPort = uint32(dest.Port)
}
if d.sockopt != nil {
sockopt.Mark = d.sockopt.Mark
}
tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
if err != nil {
return err

@ -71,6 +71,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return newError("target not specified.")
}
target := outbound.Target
targetAddr := target.NetAddr()
if target.Network == net.Network_UDP {
return newError("UDP is not supported by HTTP outbound")
@ -83,9 +84,8 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
server := c.serverPicker.PickServer()
dest := server.Destination()
user = server.PickUser()
targetAddr := target.NetAddr()
netConn, err := setUpHttpTunnel(ctx, dest, targetAddr, user, dialer)
netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer)
if netConn != nil {
conn = internet.Connection(netConn)
}
@ -125,27 +125,22 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return nil
}
// setUpHttpTunnel will create a socket tunnel via HTTP CONNECT method
func setUpHttpTunnel(ctx context.Context, dest net.Destination, target string, user *protocol.MemoryUser, dialer internet.Dialer) (net.Conn, error) {
req := (&http.Request{
Method: "CONNECT",
// setUpHTTPTunnel will create a socket tunnel via HTTP CONNECT method
func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, user *protocol.MemoryUser, dialer internet.Dialer) (net.Conn, error) {
req := &http.Request{
Method: http.MethodConnect,
URL: &url.URL{Host: target},
Header: make(http.Header),
Header: http.Header{"Proxy-Connection": []string{"Keep-Alive"}},
Host: target,
}).WithContext(ctx)
}
if user != nil && user.Account != nil {
account := user.Account.(*Account)
auth := account.GetUsername() + ":" + account.GetPassword()
req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
}
req.Header.Set("Proxy-Connection", "Keep-Alive")
connectHttp1 := func(rawConn net.Conn) (net.Conn, error) {
req.Proto = "HTTP/1.1"
req.ProtoMajor = 1
req.ProtoMinor = 1
connectHTTP1 := func(rawConn net.Conn) (net.Conn, error) {
err := req.Write(rawConn)
if err != nil {
rawConn.Close()
@ -165,10 +160,7 @@ func setUpHttpTunnel(ctx context.Context, dest net.Destination, target string, u
return rawConn, nil
}
connectHttp2 := func(rawConn net.Conn, h2clientConn *http2.ClientConn) (net.Conn, error) {
req.Proto = "HTTP/2.0"
req.ProtoMajor = 2
req.ProtoMinor = 0
connectHTTP2 := func(rawConn net.Conn, h2clientConn *http2.ClientConn) (net.Conn, error) {
pr, pw := io.Pipe()
req.Body = pr
@ -182,24 +174,21 @@ func setUpHttpTunnel(ctx context.Context, dest net.Destination, target string, u
rawConn.Close()
return nil, newError("Proxy responded with non 200 code: " + resp.Status)
}
return newHttp2Conn(rawConn, pw, resp.Body), nil
return newHTTP2Conn(rawConn, pw, resp.Body), nil
}
cachedH2Mutex.Lock()
defer cachedH2Mutex.Unlock()
if cachedConn, found := cachedH2Conns[dest]; found {
if cachedConn.rawConn != nil && cachedConn.h2Conn != nil {
rc := cachedConn.rawConn
cc := cachedConn.h2Conn
if cc.CanTakeNewRequest() {
proxyConn, err := connectHttp2(rc, cc)
if err != nil {
return nil, err
}
return proxyConn, nil
rc, cc := cachedConn.rawConn, cachedConn.h2Conn
if cc.CanTakeNewRequest() {
proxyConn, err := connectHTTP2(rc, cc)
if err != nil {
return nil, err
}
return proxyConn, nil
}
}
@ -208,8 +197,13 @@ func setUpHttpTunnel(ctx context.Context, dest net.Destination, target string, u
return nil, err
}
iConn := rawConn
if statConn, ok := iConn.(*internet.StatCouterConnection); ok {
iConn = statConn.Connection
}
nextProto := ""
if tlsConn, ok := rawConn.(*tls.Conn); ok {
if tlsConn, ok := iConn.(*tls.Conn); ok {
if err := tlsConn.Handshake(); err != nil {
rawConn.Close()
return nil, err
@ -218,10 +212,8 @@ func setUpHttpTunnel(ctx context.Context, dest net.Destination, target string, u
}
switch nextProto {
case "":
fallthrough
case "http/1.1":
return connectHttp1(rawConn)
case "", "http/1.1":
return connectHTTP1(rawConn)
case "h2":
t := http2.Transport{}
h2clientConn, err := t.NewClientConn(rawConn)
@ -230,7 +222,7 @@ func setUpHttpTunnel(ctx context.Context, dest net.Destination, target string, u
return nil, err
}
proxyConn, err := connectHttp2(rawConn, h2clientConn)
proxyConn, err := connectHTTP2(rawConn, h2clientConn)
if err != nil {
rawConn.Close()
return nil, err
@ -251,7 +243,7 @@ func setUpHttpTunnel(ctx context.Context, dest net.Destination, target string, u
}
}
func newHttp2Conn(c net.Conn, pipedReqBody *io.PipeWriter, respBody io.ReadCloser) net.Conn {
func newHTTP2Conn(c net.Conn, pipedReqBody *io.PipeWriter, respBody io.ReadCloser) net.Conn {
return &http2Conn{Conn: c, in: pipedReqBody, out: respBody}
}
@ -274,18 +266,6 @@ func (h *http2Conn) Close() error {
return h.out.Close()
}
func (h *http2Conn) CloseConn() error {
return h.Conn.Close()
}
func (h *http2Conn) CloseWrite() error {
return h.in.Close()
}
func (h *http2Conn) CloseRead() error {
return h.out.Close()
}
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))

@ -0,0 +1,40 @@
// +build !confonly
package vless
import (
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
)
// AsAccount implements protocol.Account.AsAccount().
func (a *Account) AsAccount() (protocol.Account, error) {
id, err := uuid.ParseString(a.Id)
if err != nil {
return nil, newError("failed to parse ID").Base(err).AtError()
}
return &MemoryAccount{
ID: protocol.NewID(id),
Schedulers: a.Schedulers, // needs parser here?
Encryption: a.Encryption, // needs parser here?
}, nil
}
// MemoryAccount is an in-memory form of VLess account.
type MemoryAccount struct {
// ID of the account.
ID *protocol.ID
// Schedulers of the account.
Schedulers string
// Encryption of the account. Used for client connections, and only accepts "none" for now.
Encryption string
}
// Equals implements protocol.Account.Equals().
func (a *MemoryAccount) Equals(account protocol.Account) bool {
vlessAccount, ok := account.(*MemoryAccount)
if !ok {
return false
}
return a.ID.Equals(vlessAccount.ID)
}

@ -0,0 +1,175 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: v2ray.com/core/proxy/vless/account.proto
package vless
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Account struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// Schedulers settings.
Schedulers string `protobuf:"bytes,2,opt,name=schedulers,proto3" json:"schedulers,omitempty"`
// Encryption settings. Only applies to client side, and only accepts "none" for now.
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
}
func (x *Account) Reset() {
*x = Account{}
if protoimpl.UnsafeEnabled {
mi := &file_v2ray_com_core_proxy_vless_account_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_v2ray_com_core_proxy_vless_account_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_v2ray_com_core_proxy_vless_account_proto_rawDescGZIP(), []int{0}
}
func (x *Account) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *Account) GetSchedulers() string {
if x != nil {
return x.Schedulers
}
return ""
}
func (x *Account) GetEncryption() string {
if x != nil {
return x.Encryption
}
return ""
}
var File_v2ray_com_core_proxy_vless_account_proto protoreflect.FileDescriptor
var file_v2ray_com_core_proxy_vless_account_proto_rawDesc = []byte{
0x0a, 0x28, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65,
0x73, 0x73, 0x22, 0x59, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a,
0x0a, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x0a,
0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x3e, 0x0a,
0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x05, 0x76,
0x6c, 0x65, 0x73, 0x73, 0xaa, 0x02, 0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,
0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_v2ray_com_core_proxy_vless_account_proto_rawDescOnce sync.Once
file_v2ray_com_core_proxy_vless_account_proto_rawDescData = file_v2ray_com_core_proxy_vless_account_proto_rawDesc
)
func file_v2ray_com_core_proxy_vless_account_proto_rawDescGZIP() []byte {
file_v2ray_com_core_proxy_vless_account_proto_rawDescOnce.Do(func() {
file_v2ray_com_core_proxy_vless_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_v2ray_com_core_proxy_vless_account_proto_rawDescData)
})
return file_v2ray_com_core_proxy_vless_account_proto_rawDescData
}
var file_v2ray_com_core_proxy_vless_account_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_v2ray_com_core_proxy_vless_account_proto_goTypes = []interface{}{
(*Account)(nil), // 0: v2ray.core.proxy.vless.Account
}
var file_v2ray_com_core_proxy_vless_account_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_v2ray_com_core_proxy_vless_account_proto_init() }
func file_v2ray_com_core_proxy_vless_account_proto_init() {
if File_v2ray_com_core_proxy_vless_account_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_v2ray_com_core_proxy_vless_account_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Account); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_v2ray_com_core_proxy_vless_account_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_v2ray_com_core_proxy_vless_account_proto_goTypes,
DependencyIndexes: file_v2ray_com_core_proxy_vless_account_proto_depIdxs,
MessageInfos: file_v2ray_com_core_proxy_vless_account_proto_msgTypes,
}.Build()
File_v2ray_com_core_proxy_vless_account_proto = out.File
file_v2ray_com_core_proxy_vless_account_proto_rawDesc = nil
file_v2ray_com_core_proxy_vless_account_proto_goTypes = nil
file_v2ray_com_core_proxy_vless_account_proto_depIdxs = nil
}

@ -0,0 +1,16 @@
syntax = "proto3";
package v2ray.core.proxy.vless;
option csharp_namespace = "V2Ray.Core.Proxy.Vless";
option go_package = "vless";
option java_package = "com.v2ray.core.proxy.vless";
option java_multiple_files = true;
message Account {
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
string id = 1;
// Schedulers settings.
string schedulers = 2;
// Encryption settings. Only applies to client side, and only accepts "none" for now.
string encryption = 3;
}

@ -0,0 +1,83 @@
// +build !confonly
package encoding
import (
"io"
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/protocol"
)
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
switch addons.Scheduler {
default:
if err := buffer.WriteByte(0); err != nil {
return newError("failed to write addons protobuf length").Base(err)
}
}
return nil
}
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
addons := new(Addons)
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return nil, newError("failed to read addons protobuf length").Base(err)
}
if length := int32(buffer.Byte(0)); length != 0 {
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, length); err != nil {
return nil, newError("failed to read addons protobuf value").Base(err)
}
if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
return nil, newError("failed to unmarshal addons protobuf value").Base(err)
}
// Verification.
switch addons.Scheduler {
default:
}
}
return addons, nil
}
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, addons *Addons) buf.Writer {
switch addons.Scheduler {
default:
return buf.NewWriter(writer)
}
}
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {
switch addons.Scheduler {
default:
return buf.NewReader(reader)
}
}

@ -0,0 +1,386 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: v2ray.com/core/proxy/vless/encoding/addons.proto
package encoding
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Addons struct {
Scheduler string `protobuf:"bytes,1,opt,name=Scheduler,proto3" json:"Scheduler,omitempty"`
SchedulerV []byte `protobuf:"bytes,2,opt,name=SchedulerV,proto3" json:"SchedulerV,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Addons) Reset() { *m = Addons{} }
func (m *Addons) String() string { return proto.CompactTextString(m) }
func (*Addons) ProtoMessage() {}
func (*Addons) Descriptor() ([]byte, []int) {
return fileDescriptor_d597c8244066ecf1, []int{0}
}
func (m *Addons) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Addons) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Addons.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *Addons) XXX_Merge(src proto.Message) {
xxx_messageInfo_Addons.Merge(m, src)
}
func (m *Addons) XXX_Size() int {
return m.Size()
}
func (m *Addons) XXX_DiscardUnknown() {
xxx_messageInfo_Addons.DiscardUnknown(m)
}
var xxx_messageInfo_Addons proto.InternalMessageInfo
func (m *Addons) GetScheduler() string {
if m != nil {
return m.Scheduler
}
return ""
}
func (m *Addons) GetSchedulerV() []byte {
if m != nil {
return m.SchedulerV
}
return nil
}
func init() {
proto.RegisterType((*Addons)(nil), "v2ray.core.proxy.vless.encoding.Addons")
}
func init() {
proto.RegisterFile("v2ray.com/core/proxy/vless/encoding/addons.proto", fileDescriptor_d597c8244066ecf1)
}
var fileDescriptor_d597c8244066ecf1 = []byte{
// 193 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x28, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x28, 0xca, 0xaf, 0xa8,
0xd4, 0x2f, 0xcb, 0x49, 0x2d, 0x2e, 0xd6, 0x4f, 0xcd, 0x4b, 0xce, 0x4f, 0xc9, 0xcc, 0x4b, 0xd7,
0x4f, 0x4c, 0x49, 0xc9, 0xcf, 0x2b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x87, 0xe9,
0x28, 0x4a, 0xd5, 0x03, 0xab, 0xd6, 0x03, 0xab, 0xd6, 0x83, 0xa9, 0x56, 0x72, 0xe3, 0x62, 0x73,
0x04, 0x6b, 0x10, 0x92, 0xe1, 0xe2, 0x0c, 0x4e, 0xce, 0x48, 0x4d, 0x29, 0xcd, 0x49, 0x2d, 0x92,
0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x42, 0x08, 0x08, 0xc9, 0x71, 0x71, 0xc1, 0x39, 0x61, 0x12,
0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x48, 0x22, 0x4e, 0xc9, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78,
0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x8c, 0xc7, 0x72, 0x0c, 0x5c, 0xca, 0xc9, 0xf9, 0xb9,
0x7a, 0x04, 0xac, 0x0f, 0x60, 0x8c, 0xe2, 0x80, 0xb1, 0x57, 0x31, 0xc9, 0x87, 0x19, 0x05, 0x25,
0x56, 0xea, 0x39, 0x83, 0x54, 0x07, 0x80, 0x55, 0x87, 0x81, 0x55, 0xbb, 0x42, 0x55, 0x24, 0xb1,
0x81, 0x3d, 0x65, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x78, 0xd4, 0xe2, 0x08, 0x01, 0x00,
0x00,
}
func (m *Addons) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Addons) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Addons) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if len(m.SchedulerV) > 0 {
i -= len(m.SchedulerV)
copy(dAtA[i:], m.SchedulerV)
i = encodeVarintAddons(dAtA, i, uint64(len(m.SchedulerV)))
i--
dAtA[i] = 0x12
}
if len(m.Scheduler) > 0 {
i -= len(m.Scheduler)
copy(dAtA[i:], m.Scheduler)
i = encodeVarintAddons(dAtA, i, uint64(len(m.Scheduler)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintAddons(dAtA []byte, offset int, v uint64) int {
offset -= sovAddons(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *Addons) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Scheduler)
if l > 0 {
n += 1 + l + sovAddons(uint64(l))
}
l = len(m.SchedulerV)
if l > 0 {
n += 1 + l + sovAddons(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovAddons(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozAddons(x uint64) (n int) {
return sovAddons(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Addons) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAddons
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Addons: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Addons: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Scheduler", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAddons
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthAddons
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthAddons
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Scheduler = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SchedulerV", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAddons
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthAddons
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthAddons
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SchedulerV = append(m.SchedulerV[:0], dAtA[iNdEx:postIndex]...)
if m.SchedulerV == nil {
m.SchedulerV = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipAddons(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthAddons
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthAddons
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipAddons(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAddons
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAddons
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowAddons
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthAddons
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupAddons
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthAddons
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthAddons = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowAddons = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupAddons = fmt.Errorf("proto: unexpected end of group")
)

@ -0,0 +1,12 @@
syntax = "proto3";
package v2ray.core.proxy.vless.encoding;
option csharp_namespace = "V2Ray.Core.Proxy.Vless.Encoding";
option go_package = "encoding";
option java_package = "com.v2ray.core.proxy.vless.encoding";
option java_multiple_files = true;
message Addons {
string Scheduler = 1;
bytes SchedulerV = 2;
}

@ -0,0 +1,173 @@
package encoding
import (
"io"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/vless"
)
//go:generate errorgen
const (
Version = byte(0)
)
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(),
)
// EncodeRequestHeader writes encoded request header into the given writer.
func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons) error {
buffer := buf.StackNew()
defer buffer.Release()
if err := buffer.WriteByte(request.Version); err != nil {
return newError("failed to write request version").Base(err)
}
if _, err := buffer.Write(request.User.Account.(*vless.MemoryAccount).ID.Bytes()); err != nil {
return newError("failed to write request user id").Base(err)
}
if err := EncodeHeaderAddons(&buffer, requestAddons); err != nil {
return newError("failed to encode request header addons").Base(err)
}
if err := buffer.WriteByte(byte(request.Command)); err != nil {
return newError("failed to write request command").Base(err)
}
if request.Command != protocol.RequestCommandMux {
if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil {
return newError("failed to write request address and port").Base(err)
}
}
if _, err := writer.Write(buffer.Bytes()); err != nil {
return newError("failed to write request header").Base(err)
}
return nil
}
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
func DecodeRequestHeader(reader io.Reader, validator *vless.Validator) (*protocol.RequestHeader, *Addons, error, *buf.Buffer) {
buffer := buf.StackNew()
defer buffer.Release()
pre := buf.New()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
pre.Write(buffer.Bytes())
return nil, nil, newError("failed to read request version").Base(err), pre
}
request := &protocol.RequestHeader{
Version: buffer.Byte(0),
}
pre.Write(buffer.Bytes())
switch request.Version {
case 0:
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil {
pre.Write(buffer.Bytes())
return nil, nil, newError("failed to read request user id").Base(err), pre
}
var id [16]byte
copy(id[:], buffer.Bytes())
if request.User = validator.Get(id); request.User == nil {
pre.Write(buffer.Bytes())
return nil, nil, newError("invalid request user id"), pre
}
requestAddons, err := DecodeHeaderAddons(&buffer, reader)
if err != nil {
return nil, nil, newError("failed to decode request header addons").Base(err), nil
}
buffer.Clear()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return nil, nil, newError("failed to read request command").Base(err), nil
}
request.Command = protocol.RequestCommand(buffer.Byte(0))
switch request.Command {
case protocol.RequestCommandMux:
request.Address = net.DomainAddress("v1.mux.cool")
request.Port = 0
case protocol.RequestCommandTCP, protocol.RequestCommandUDP:
if addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil {
request.Address = addr
request.Port = port
}
}
if request.Address == nil {
return nil, nil, newError("invalid request address"), nil
}
return request, requestAddons, nil, nil
default:
return nil, nil, newError("invalid request version"), pre
}
}
// EncodeResponseHeader writes encoded response header into the given writer.
func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *Addons) error {
buffer := buf.StackNew()
defer buffer.Release()
if err := buffer.WriteByte(request.Version); err != nil {
return newError("failed to write response version").Base(err)
}
if err := EncodeHeaderAddons(&buffer, responseAddons); err != nil {
return newError("failed to encode response header addons").Base(err)
}
if _, err := writer.Write(buffer.Bytes()); err != nil {
return newError("failed to write response header").Base(err)
}
return nil
}
// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream.
func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader, responseAddons *Addons) error {
buffer := buf.StackNew()
defer buffer.Release()
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
return newError("failed to read response version").Base(err)
}
if buffer.Byte(0) != request.Version {
return newError("unexpected response version. Expecting ", int(request.Version), " but actually ", int(buffer.Byte(0)))
}
responseAddons, err := DecodeHeaderAddons(&buffer, reader)
if err != nil {
return newError("failed to decode response header addons").Base(err)
}
return nil
}

@ -0,0 +1,126 @@
package encoding_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
"v2ray.com/core/proxy/vless"
. "v2ray.com/core/proxy/vless/encoding"
)
func toAccount(a *vless.Account) protocol.Account {
account, err := a.AsAccount()
common.Must(err)
return account
}
func TestRequestSerialization(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2fly.org",
}
id := uuid.New()
account := &vless.Account{
Id: id.String(),
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommandTCP,
Address: net.DomainAddress("www.v2fly.org"),
Port: net.Port(443),
}
expectedAddons := &Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator.Add(user)
actualRequest, actualAddons, err, _ := DecodeRequestHeader(&buffer, Validator)
common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {
t.Error(r)
}
if r := cmp.Diff(actualAddons, expectedAddons); r != "" {
t.Error(r)
}
}
func TestInvalidRequest(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2fly.org",
}
id := uuid.New()
account := &vless.Account{
Id: id.String(),
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommand(100),
Address: net.DomainAddress("www.v2fly.org"),
Port: net.Port(443),
}
expectedAddons := &Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator.Add(user)
_, _, err, _ := DecodeRequestHeader(&buffer, Validator)
if err == nil {
t.Error("nil error")
}
}
func TestMuxRequest(t *testing.T) {
user := &protocol.MemoryUser{
Level: 0,
Email: "test@v2fly.org",
}
id := uuid.New()
account := &vless.Account{
Id: id.String(),
}
user.Account = toAccount(account)
expectedRequest := &protocol.RequestHeader{
Version: Version,
User: user,
Command: protocol.RequestCommandMux,
Address: net.DomainAddress("v1.mux.cool"),
}
expectedAddons := &Addons{}
buffer := buf.StackNew()
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
Validator := new(vless.Validator)
Validator.Add(user)
actualRequest, actualAddons, err, _ := DecodeRequestHeader(&buffer, Validator)
common.Must(err)
if r := cmp.Diff(actualRequest, expectedRequest, cmp.AllowUnexported(protocol.ID{})); r != "" {
t.Error(r)
}
if r := cmp.Diff(actualAddons, expectedAddons); r != "" {
t.Error(r)
}
}

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

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

@ -0,0 +1,3 @@
// +build !confonly
package inbound

@ -0,0 +1,391 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: v2ray.com/core/proxy/vless/inbound/config.proto
package inbound
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
net "v2ray.com/core/common/net"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Fallback struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Addr *net.IPOrDomain `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
Unix string `protobuf:"bytes,3,opt,name=unix,proto3" json:"unix,omitempty"`
Xver uint32 `protobuf:"varint,4,opt,name=xver,proto3" json:"xver,omitempty"`
}
func (x *Fallback) Reset() {
*x = Fallback{}
if protoimpl.UnsafeEnabled {
mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Fallback) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Fallback) ProtoMessage() {}
func (x *Fallback) ProtoReflect() protoreflect.Message {
mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Fallback.ProtoReflect.Descriptor instead.
func (*Fallback) Descriptor() ([]byte, []int) {
return file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{0}
}
func (x *Fallback) GetAddr() *net.IPOrDomain {
if x != nil {
return x.Addr
}
return nil
}
func (x *Fallback) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
func (x *Fallback) GetUnix() string {
if x != nil {
return x.Unix
}
return ""
}
func (x *Fallback) GetXver() uint32 {
if x != nil {
return x.Xver
}
return 0
}
type FallbackH2 struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Addr *net.IPOrDomain `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
Unix string `protobuf:"bytes,3,opt,name=unix,proto3" json:"unix,omitempty"`
Xver uint32 `protobuf:"varint,4,opt,name=xver,proto3" json:"xver,omitempty"`
}
func (x *FallbackH2) Reset() {
*x = FallbackH2{}
if protoimpl.UnsafeEnabled {
mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *FallbackH2) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FallbackH2) ProtoMessage() {}
func (x *FallbackH2) ProtoReflect() protoreflect.Message {
mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FallbackH2.ProtoReflect.Descriptor instead.
func (*FallbackH2) Descriptor() ([]byte, []int) {
return file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1}
}
func (x *FallbackH2) GetAddr() *net.IPOrDomain {
if x != nil {
return x.Addr
}
return nil
}
func (x *FallbackH2) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
func (x *FallbackH2) GetUnix() string {
if x != nil {
return x.Unix
}
return ""
}
func (x *FallbackH2) GetXver() uint32 {
if x != nil {
return x.Xver
}
return 0
}
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
// Decryption settings. Only applies to server side, and only accepts "none" for now.
Decryption string `protobuf:"bytes,2,opt,name=decryption,proto3" json:"decryption,omitempty"`
Fallback *Fallback `protobuf:"bytes,3,opt,name=fallback,proto3" json:"fallback,omitempty"`
FallbackH2 *FallbackH2 `protobuf:"bytes,4,opt,name=fallback_h2,json=fallbackH2,proto3" json:"fallback_h2,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{2}
}
func (x *Config) GetUser() []*protocol.User {
if x != nil {
return x.User
}
return nil
}
func (x *Config) GetDecryption() string {
if x != nil {
return x.Decryption
}
return ""
}
func (x *Config) GetFallback() *Fallback {
if x != nil {
return x.Fallback
}
return nil
}
func (x *Config) GetFallbackH2() *FallbackH2 {
if x != nil {
return x.FallbackH2
}
return nil
}
var File_v2ray_com_core_proxy_vless_inbound_config_proto protoreflect.FileDescriptor
var file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc = []byte{
0x0a, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0x1a, 0x27, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72,
0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x29, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7d, 0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x12, 0x35, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61,
0x69, 0x6e, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x75, 0x6e, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x78,
0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04,
0x78, 0x76, 0x65, 0x72, 0x22, 0x80, 0x01, 0x0a, 0x0b, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x5f, 0x68, 0x32, 0x12, 0x35, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x70,
0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12,
0x12, 0x0a, 0x04, 0x75, 0x6e, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75,
0x6e, 0x69, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xf2, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73,
0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x63, 0x72,
0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65,
0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x66, 0x61, 0x6c, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x76, 0x32, 0x72,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c,
0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x52, 0x08, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x4c,
0x0a, 0x0b, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x68, 0x32, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x68, 0x32,
0x52, 0x0a, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x48, 0x32, 0x42, 0x50, 0x0a, 0x22,
0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75,
0x6e, 0x64, 0x50, 0x01, 0x5a, 0x07, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x1e,
0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescOnce sync.Once
file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescData = file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc
)
func file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescGZIP() []byte {
file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescOnce.Do(func() {
file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescData)
})
return file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescData
}
var file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_v2ray_com_core_proxy_vless_inbound_config_proto_goTypes = []interface{}{
(*Fallback)(nil), // 0: v2ray.core.proxy.vless.inbound.Fallback
(*FallbackH2)(nil), // 1: v2ray.core.proxy.vless.inbound.Fallback_h2
(*Config)(nil), // 2: v2ray.core.proxy.vless.inbound.Config
(*net.IPOrDomain)(nil), // 3: v2ray.core.common.net.IPOrDomain
(*protocol.User)(nil), // 4: v2ray.core.common.protocol.User
}
var file_v2ray_com_core_proxy_vless_inbound_config_proto_depIdxs = []int32{
3, // 0: v2ray.core.proxy.vless.inbound.Fallback.addr:type_name -> v2ray.core.common.net.IPOrDomain
3, // 1: v2ray.core.proxy.vless.inbound.Fallback_h2.addr:type_name -> v2ray.core.common.net.IPOrDomain
4, // 2: v2ray.core.proxy.vless.inbound.Config.user:type_name -> v2ray.core.common.protocol.User
0, // 3: v2ray.core.proxy.vless.inbound.Config.fallback:type_name -> v2ray.core.proxy.vless.inbound.Fallback
1, // 4: v2ray.core.proxy.vless.inbound.Config.fallback_h2:type_name -> v2ray.core.proxy.vless.inbound.Fallback_h2
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_v2ray_com_core_proxy_vless_inbound_config_proto_init() }
func file_v2ray_com_core_proxy_vless_inbound_config_proto_init() {
if File_v2ray_com_core_proxy_vless_inbound_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Fallback); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*FallbackH2); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_v2ray_com_core_proxy_vless_inbound_config_proto_goTypes,
DependencyIndexes: file_v2ray_com_core_proxy_vless_inbound_config_proto_depIdxs,
MessageInfos: file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes,
}.Build()
File_v2ray_com_core_proxy_vless_inbound_config_proto = out.File
file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc = nil
file_v2ray_com_core_proxy_vless_inbound_config_proto_goTypes = nil
file_v2ray_com_core_proxy_vless_inbound_config_proto_depIdxs = nil
}

@ -0,0 +1,32 @@
syntax = "proto3";
package v2ray.core.proxy.vless.inbound;
option csharp_namespace = "V2Ray.Core.Proxy.Vless.Inbound";
option go_package = "inbound";
option java_package = "com.v2ray.core.proxy.vless.inbound";
option java_multiple_files = true;
import "v2ray.com/core/common/net/address.proto";
import "v2ray.com/core/common/protocol/user.proto";
message Fallback {
v2ray.core.common.net.IPOrDomain addr = 1;
uint32 port = 2;
string unix = 3;
uint32 xver = 4;
}
message Fallback_h2 {
v2ray.core.common.net.IPOrDomain addr = 1;
uint32 port = 2;
string unix = 3;
uint32 xver = 4;
}
message Config {
repeated v2ray.core.common.protocol.User user = 1;
// Decryption settings. Only applies to server side, and only accepts "none" for now.
string decryption = 2;
Fallback fallback = 3;
Fallback_h2 fallback_h2 = 4;
}

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

@ -0,0 +1,402 @@
// +build !confonly
package inbound
//go:generate errorgen
import (
"context"
"encoding/hex"
"io"
"strconv"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/dns"
feature_inbound "v2ray.com/core/features/inbound"
"v2ray.com/core/features/policy"
"v2ray.com/core/features/routing"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/encoding"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tls"
)
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
var dc dns.Client
if err := core.RequireFeatures(ctx, func(d dns.Client) error {
dc = d
return nil
}); err != nil {
return nil, err
}
return New(ctx, config.(*Config), dc)
}))
}
// Handler is an inbound connection handler that handles messages in VLess protocol.
type Handler struct {
inboundHandlerManager feature_inbound.Manager
policyManager policy.Manager
validator *vless.Validator
dns dns.Client
fallback *Fallback // or nil
addrport string
fallback_h2 *FallbackH2 // or nil
addrport_h2 string
}
// New creates a new VLess inbound handler.
func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
v := core.MustFromContext(ctx)
handler := &Handler{
inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
validator: new(vless.Validator),
dns: dc,
}
for _, user := range config.User {
u, err := user.ToMemoryUser()
if err != nil {
return nil, newError("failed to get VLESS user").Base(err).AtError()
}
if err := handler.AddUser(ctx, u); err != nil {
return nil, newError("failed to initiate user").Base(err).AtError()
}
}
if config.Fallback != nil {
handler.fallback = config.Fallback
handler.addrport = handler.fallback.Addr.AsAddress().String() + ":" + strconv.Itoa(int(handler.fallback.Port))
}
if config.FallbackH2 != nil {
handler.fallback_h2 = config.FallbackH2
handler.addrport_h2 = handler.fallback_h2.Addr.AsAddress().String() + ":" + strconv.Itoa(int(handler.fallback_h2.Port))
}
return handler, nil
}
// Close implements common.Closable.Close().
func (h *Handler) Close() error {
return errors.Combine(common.Close(h.validator))
}
// AddUser implements proxy.UserManager.AddUser().
func (h *Handler) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
return h.validator.Add(u)
}
// RemoveUser implements proxy.UserManager.RemoveUser().
func (h *Handler) RemoveUser(ctx context.Context, e string) error {
return h.validator.Del(e)
}
// Network implements proxy.Inbound.Network().
func (*Handler) Network() []net.Network {
return []net.Network{net.Network_TCP}
}
// Process implements proxy.Inbound.Process().
func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher routing.Dispatcher) error {
sessionPolicy := h.policyManager.ForLevel(0)
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
return newError("unable to set read deadline").Base(err).AtWarning()
}
first := buf.New()
first.ReadFrom(connection)
sid := session.ExportIDToError(ctx)
newError("firstLen = ", first.Len()).AtInfo().WriteToLog(sid)
reader := &buf.BufferedReader{
Reader: buf.NewReader(connection),
Buffer: buf.MultiBuffer{first},
}
var request *protocol.RequestHeader
var requestAddons *encoding.Addons
var err error
var pre *buf.Buffer
fallback := 0
if h.fallback != nil {
fallback = 1
}
if fallback == 1 && first.Len() < 18 {
err = newError("fallback directly")
} else {
request, requestAddons, err, pre = encoding.DecodeRequestHeader(reader, h.validator)
if pre == nil {
fallback = 0
}
}
if err != nil {
if fallback == 1 {
if h.fallback_h2 != nil {
iConn := connection
if statConn, ok := iConn.(*internet.StatCouterConnection); ok {
iConn = statConn.Connection
}
if tlsConn, ok := iConn.(*tls.Conn); ok {
if tlsConn.ConnectionState().NegotiatedProtocol == "h2" {
fallback = 2
}
}
}
var addrport string
var unixpath string
var proxyver uint32
switch fallback {
case 1:
addrport = h.addrport
unixpath = h.fallback.Unix
proxyver = h.fallback.Xver
newError("fallback starts").Base(err).AtInfo().WriteToLog(sid)
case 2:
addrport = h.addrport_h2
unixpath = h.fallback_h2.Unix
proxyver = h.fallback_h2.Xver
newError("fallback_h2 starts").Base(err).AtInfo().WriteToLog(sid)
}
var conn net.Conn
if err := retry.ExponentialBackoff(5, 100).On(func() error {
var dialer net.Dialer
var err error
if unixpath != "" {
conn, err = dialer.DialContext(ctx, "unix", unixpath)
} else {
conn, err = dialer.DialContext(ctx, "tcp", addrport)
}
if err != nil {
return err
}
return nil
}); err != nil {
return newError("failed to fallback connection").Base(err).AtWarning()
}
defer conn.Close() // nolint: errcheck
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
writer := buf.NewWriter(connection)
serverReader := buf.NewReader(conn)
serverWriter := buf.NewWriter(conn)
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
if proxyver > 0 {
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
}
ipv4 := true
for i := 0; i < len(remoteAddr); i++ {
if remoteAddr[i] == ':' {
ipv4 = false
break
}
}
pro := buf.New()
switch proxyver {
case 1:
if ipv4 {
pro.Write([]byte("PROXY TCP4 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))
} else {
pro.Write([]byte("PROXY TCP6 " + remoteAddr + " " + localAddr + " " + remotePort + " " + localPort + "\r\n"))
}
case 2:
pro.Write([]byte("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x21")) // signature + v2 + PROXY
if ipv4 {
pro.Write([]byte("\x11\x00\x0C")) // AF_INET + STREAM + 12 bytes
pro.Write(net.ParseIP(remoteAddr).To4())
pro.Write(net.ParseIP(localAddr).To4())
} else {
pro.Write([]byte("\x21\x00\x24")) // AF_INET6 + STREAM + 36 bytes
pro.Write(net.ParseIP(remoteAddr).To16())
pro.Write(net.ParseIP(localAddr).To16())
}
p1, _ := strconv.ParseInt(remotePort, 10, 64)
b1, _ := hex.DecodeString(strconv.FormatInt(p1, 16))
p2, _ := strconv.ParseInt(localPort, 10, 64)
b2, _ := hex.DecodeString(strconv.FormatInt(p2, 16))
if len(b1) == 1 {
pro.WriteByte(0)
}
pro.Write(b1)
if len(b2) == 1 {
pro.WriteByte(0)
}
pro.Write(b2)
}
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
return newError("failed to set PROXY protocol v", proxyver).Base(err).AtWarning()
}
}
if pre != nil && pre.Len() > 0 {
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pre}); err != nil {
return newError("failed to fallback request pre").Base(err).AtWarning()
}
}
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return err // ...
}
return nil
}
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
return err // ...
}
return nil
}
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
common.Interrupt(serverReader)
common.Interrupt(serverWriter)
return newError("fallback ends").Base(err).AtInfo()
}
return nil
}
if errors.Cause(err) != io.EOF {
log.Record(&log.AccessMessage{
From: connection.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
err = newError("invalid request from ", connection.RemoteAddr()).Base(err).AtWarning()
}
return err
}
if request.Command != protocol.RequestCommandMux {
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: connection.RemoteAddr(),
To: request.Destination(),
Status: log.AccessAccepted,
Reason: "",
Email: request.User.Email,
})
}
newError("received request for ", request.Destination()).AtInfo().WriteToLog(sid)
if err := connection.SetReadDeadline(time.Time{}); err != nil {
newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid)
}
inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.User = request.User
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
link, err := dispatcher.Dispatch(ctx, request.Destination())
if err != nil {
return newError("failed to dispatch request to ", request.Destination()).Base(err).AtWarning()
}
serverReader := link.Reader
serverWriter := link.Writer
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
// default: clientReader := reader
clientReader := encoding.DecodeBodyAddons(reader, request, requestAddons)
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
if err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request payload").Base(err).AtInfo()
}
return nil
}
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
responseAddons := &encoding.Addons{
Scheduler: requestAddons.Scheduler,
}
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
return newError("failed to encode response header").Base(err).AtWarning()
}
// default: clientWriter := bufferWriter
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons)
{
multiBuffer, err := serverReader.ReadMultiBuffer()
if err != nil {
return err // ...
}
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
return err // ...
}
}
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
if err := bufferWriter.SetBuffered(false); err != nil {
return newError("failed to write A response payload").Base(err).AtWarning()
}
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
if err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer response payload").Base(err).AtInfo()
}
// Indicates the end of response payload.
switch responseAddons.Scheduler {
default:
}
return nil
}
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), getResponse); err != nil {
common.Interrupt(serverReader)
common.Interrupt(serverWriter)
return newError("connection ends").Base(err).AtInfo()
}
return nil
}

@ -0,0 +1,3 @@
// +build !confonly
package outbound

@ -0,0 +1,164 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: v2ray.com/core/proxy/vless/outbound/config.proto
package outbound
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protocol "v2ray.com/core/common/protocol"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Receiver []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=receiver,proto3" json:"receiver,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_v2ray_com_core_proxy_vless_outbound_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_v2ray_com_core_proxy_vless_outbound_config_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetReceiver() []*protocol.ServerEndpoint {
if x != nil {
return x.Receiver
}
return nil
}
var File_v2ray_com_core_proxy_vless_outbound_config_proto protoreflect.FileDescriptor
var file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDesc = []byte{
0x0a, 0x30, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x6f, 0x75, 0x74,
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x1f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62, 0x6f,
0x75, 0x6e, 0x64, 0x1a, 0x30, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x50, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x46, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x72,
0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x42, 0x53, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x76,
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01,
0x5a, 0x08, 0x6f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x1f, 0x56, 0x32, 0x52,
0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c,
0x65, 0x73, 0x73, 0x2e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescOnce sync.Once
file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescData = file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDesc
)
func file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescGZIP() []byte {
file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescOnce.Do(func() {
file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescData)
})
return file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDescData
}
var file_v2ray_com_core_proxy_vless_outbound_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_v2ray_com_core_proxy_vless_outbound_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v2ray.core.proxy.vless.outbound.Config
(*protocol.ServerEndpoint)(nil), // 1: v2ray.core.common.protocol.ServerEndpoint
}
var file_v2ray_com_core_proxy_vless_outbound_config_proto_depIdxs = []int32{
1, // 0: v2ray.core.proxy.vless.outbound.Config.receiver:type_name -> v2ray.core.common.protocol.ServerEndpoint
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_v2ray_com_core_proxy_vless_outbound_config_proto_init() }
func file_v2ray_com_core_proxy_vless_outbound_config_proto_init() {
if File_v2ray_com_core_proxy_vless_outbound_config_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_v2ray_com_core_proxy_vless_outbound_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_v2ray_com_core_proxy_vless_outbound_config_proto_goTypes,
DependencyIndexes: file_v2ray_com_core_proxy_vless_outbound_config_proto_depIdxs,
MessageInfos: file_v2ray_com_core_proxy_vless_outbound_config_proto_msgTypes,
}.Build()
File_v2ray_com_core_proxy_vless_outbound_config_proto = out.File
file_v2ray_com_core_proxy_vless_outbound_config_proto_rawDesc = nil
file_v2ray_com_core_proxy_vless_outbound_config_proto_goTypes = nil
file_v2ray_com_core_proxy_vless_outbound_config_proto_depIdxs = nil
}

@ -0,0 +1,13 @@
syntax = "proto3";
package v2ray.core.proxy.vless.outbound;
option csharp_namespace = "V2Ray.Core.Proxy.Vless.Outbound";
option go_package = "outbound";
option java_package = "com.v2ray.core.proxy.vless.outbound";
option java_multiple_files = true;
import "v2ray.com/core/common/protocol/server_spec.proto";
message Config {
repeated v2ray.core.common.protocol.ServerEndpoint receiver = 1;
}

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

@ -0,0 +1,177 @@
// +build !confonly
package outbound
//go:generate errorgen
import (
"context"
"time"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry"
"v2ray.com/core/common/session"
"v2ray.com/core/common/signal"
"v2ray.com/core/common/task"
"v2ray.com/core/features/policy"
"v2ray.com/core/proxy/vless"
"v2ray.com/core/proxy/vless/encoding"
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}
// Handler is an outbound connection handler for VLess protocol.
type Handler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
policyManager policy.Manager
}
// New creates a new VLess outbound handler.
func New(ctx context.Context, config *Config) (*Handler, error) {
serverList := protocol.NewServerList()
for _, rec := range config.Receiver {
s, err := protocol.NewServerSpecFromPB(*rec)
if err != nil {
return nil, newError("failed to parse server spec").Base(err).AtError()
}
serverList.AddServer(s)
}
v := core.MustFromContext(ctx)
handler := &Handler{
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}
return handler, nil
}
// Process implements proxy.Outbound.Process().
func (v *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
var rec *protocol.ServerSpec
var conn internet.Connection
if err := retry.ExponentialBackoff(5, 200).On(func() error {
rec = v.serverPicker.PickServer()
var err error
conn, err = dialer.Dial(ctx, rec.Destination())
if err != nil {
return err
}
return nil
}); err != nil {
return newError("failed to find an available destination").Base(err).AtWarning()
}
defer conn.Close() // nolint: errcheck
outbound := session.OutboundFromContext(ctx)
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified").AtError()
}
target := outbound.Target
newError("tunneling request to ", target, " via ", rec.Destination()).AtInfo().WriteToLog(session.ExportIDToError(ctx))
command := protocol.RequestCommandTCP
if target.Network == net.Network_UDP {
command = protocol.RequestCommandUDP
}
if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
command = protocol.RequestCommandMux
}
request := &protocol.RequestHeader{
Version: encoding.Version,
User: rec.PickUser(),
Command: command,
Address: target.Address,
Port: target.Port,
}
account := request.User.Account.(*vless.MemoryAccount)
requestAddons := &encoding.Addons{
Scheduler: account.Schedulers,
}
sessionPolicy := v.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
clientReader := link.Reader
clientWriter := link.Writer
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
return newError("failed to encode request header").Base(err).AtWarning()
}
// default: serverWriter := bufferWriter
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons)
if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return err // ...
}
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
if err := bufferWriter.SetBuffered(false); err != nil {
return newError("failed to write A request payload").Base(err).AtWarning()
}
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
if err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request payload").Base(err).AtInfo()
}
// Indicates the end of request payload.
switch requestAddons.Scheduler {
default:
}
return nil
}
getResponse := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
responseAddons := new(encoding.Addons)
if err := encoding.DecodeResponseHeader(conn, request, responseAddons); err != nil {
return newError("failed to decode response header").Base(err).AtWarning()
}
// default: serverReader := buf.NewReader(conn)
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
if err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer response payload").Base(err).AtInfo()
}
return nil
}
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
return newError("connection ends").Base(err).AtInfo()
}
return nil
}

@ -0,0 +1,50 @@
// +build !confonly
package vless
import (
"strings"
"sync"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
)
type Validator struct {
// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.
email sync.Map
users sync.Map
}
func (v *Validator) Add(u *protocol.MemoryUser) error {
if u.Email != "" {
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
if loaded {
return newError("User ", u.Email, " already exists.")
}
}
v.users.Store(u.Account.(*MemoryAccount).ID.UUID(), u)
return nil
}
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.")
}
v.email.Delete(le)
v.users.Delete(u.(*protocol.MemoryUser).Account.(*MemoryAccount).ID.UUID())
return nil
}
func (v *Validator) Get(id uuid.UUID) *protocol.MemoryUser {
u, _ := v.users.Load(id)
if u != nil {
return u.(*protocol.MemoryUser)
}
return nil
}

@ -0,0 +1,8 @@
// Package vless contains the implementation of VLess protocol and transportation.
//
// VLess contains both inbound and outbound connections. VLess inbound is usually used on servers
// together with 'freedom' to talk to final destination, while VLess outbound is usually used on
// clients with 'socks' for proxying.
package vless
//go:generate errorgen

@ -44,8 +44,8 @@ pkg_zip(
"//main:v2ray_darwin_amd64",
"//main:v2ray_darwin_amd64_sig",
],
out = "v2ray-macos.zip",
mappings = gen_mappings("darwin", "amd64"),
out = "v2ray-macos-64.zip",
mappings = gen_mappings("darwin", "amd64", "0"),
)
pkg_zip(
@ -57,12 +57,12 @@ pkg_zip(
"//infra/control/main:v2ctl_windows_amd64",
"//infra/control/main:v2ctl_windows_amd64_sig",
"//main:v2ray_windows_amd64",
"//main:v2ray_windows_amd64_sig",
"//main:v2ray_windows_amd64_nowindow",
"//main:v2ray_windows_amd64_nowindow_sig",
"//main:v2ray_windows_amd64_sig",
],
out = "v2ray-windows-64.zip",
mappings = gen_mappings("windows", "amd64"),
mappings = gen_mappings("windows", "amd64", "0"),
)
pkg_zip(
@ -74,41 +74,29 @@ pkg_zip(
"//infra/control/main:v2ctl_windows_386",
"//infra/control/main:v2ctl_windows_386_sig",
"//main:v2ray_windows_386",
"//main:v2ray_windows_386_sig",
"//main:v2ray_windows_386_nowindow",
"//main:v2ray_windows_386_nowindow_sig",
"//main:v2ray_windows_386_sig",
],
out = "v2ray-windows-32.zip",
mappings = gen_mappings("windows", "386"),
mappings = gen_mappings("windows", "386", "0"),
)
pkg_zip(
name = "v2ray_windows_arm_package",
name = "v2ray_windows_armv7_package",
srcs = [
":config_json",
":doc",
":geodata",
"//infra/control/main:v2ctl_windows_arm_armv5",
"//infra/control/main:v2ctl_windows_arm_armv5_sig",
"//infra/control/main:v2ctl_windows_arm_armv6",
"//infra/control/main:v2ctl_windows_arm_armv6_sig",
"//infra/control/main:v2ctl_windows_arm_armv7",
"//infra/control/main:v2ctl_windows_arm_armv7_sig",
"//main:v2ray_windows_arm_armv5",
"//main:v2ray_windows_arm_armv5_sig",
"//main:v2ray_windows_arm_armv5_nowindow",
"//main:v2ray_windows_arm_armv5_nowindow_sig",
"//main:v2ray_windows_arm_armv6",
"//main:v2ray_windows_arm_armv6_sig",
"//main:v2ray_windows_arm_armv6_nowindow",
"//main:v2ray_windows_arm_armv6_nowindow_sig",
"//main:v2ray_windows_arm_armv7",
"//main:v2ray_windows_arm_armv7_sig",
"//main:v2ray_windows_arm_armv7_nowindow",
"//main:v2ray_windows_arm_armv7_nowindow_sig",
"//infra/control/main:v2ctl_windows_arm_7",
"//infra/control/main:v2ctl_windows_arm_7_sig",
"//main:v2ray_windows_arm_7",
"//main:v2ray_windows_arm_7_sig",
"//main:v2ray_windows_arm_7_nowindow",
"//main:v2ray_windows_arm_7_nowindow_sig",
],
out = "v2ray-windows-arm.zip",
mappings = gen_mappings("windows", "arm"),
out = "v2ray-windows-arm32-v7a.zip",
mappings = gen_mappings("windows", "arm", "7"),
)
pkg_zip(
@ -123,7 +111,7 @@ pkg_zip(
"//main:v2ray_freebsd_amd64_sig",
],
out = "v2ray-freebsd-64.zip",
mappings = gen_mappings("freebsd", "amd64"),
mappings = gen_mappings("freebsd", "amd64", "0"),
)
pkg_zip(
@ -138,7 +126,7 @@ pkg_zip(
"//main:v2ray_freebsd_386_sig",
],
out = "v2ray-freebsd-32.zip",
mappings = gen_mappings("freebsd", "386"),
mappings = gen_mappings("freebsd", "386", "0"),
)
pkg_zip(
@ -153,7 +141,7 @@ pkg_zip(
"//main:v2ray_openbsd_amd64_sig",
],
out = "v2ray-openbsd-64.zip",
mappings = gen_mappings("openbsd", "amd64"),
mappings = gen_mappings("openbsd", "amd64", "0"),
)
pkg_zip(
@ -168,7 +156,7 @@ pkg_zip(
"//main:v2ray_openbsd_386_sig",
],
out = "v2ray-openbsd-32.zip",
mappings = gen_mappings("openbsd", "386"),
mappings = gen_mappings("openbsd", "386", "0"),
)
pkg_zip(
@ -183,7 +171,7 @@ pkg_zip(
"//main:v2ray_dragonfly_amd64_sig",
],
out = "v2ray-dragonfly-64.zip",
mappings = gen_mappings("dragonfly", "amd64"),
mappings = gen_mappings("dragonfly", "amd64", "0"),
)
pkg_zip(
@ -199,7 +187,7 @@ pkg_zip(
"//main:v2ray_linux_amd64_sig",
],
out = "v2ray-linux-64.zip",
mappings = gen_mappings("linux", "amd64"),
mappings = gen_mappings("linux", "amd64", "0"),
)
pkg_zip(
@ -215,51 +203,75 @@ pkg_zip(
"//main:v2ray_linux_386_sig",
],
out = "v2ray-linux-32.zip",
mappings = gen_mappings("linux", "386"),
mappings = gen_mappings("linux", "386", "0"),
)
pkg_zip(
name = "v2ray_linux_arm_package",
name = "v2ray_linux_arm64_package",
srcs = [
":config_json",
":doc",
":geodata",
":systemd",
"//infra/control/main:v2ctl_linux_arm_armv5",
"//infra/control/main:v2ctl_linux_arm_armv5_sig",
"//infra/control/main:v2ctl_linux_arm_armv6",
"//infra/control/main:v2ctl_linux_arm_armv6_sig",
"//infra/control/main:v2ctl_linux_arm_armv7",
"//infra/control/main:v2ctl_linux_arm_armv7_sig",
"//main:v2ray_linux_arm_armv5",
"//main:v2ray_linux_arm_armv5_sig",
"//main:v2ray_linux_arm_armv6",
"//main:v2ray_linux_arm_armv6_sig",
"//main:v2ray_linux_arm_armv7",
"//main:v2ray_linux_arm_armv7_sig",
"//infra/control/main:v2ctl_linux_arm64",
"//infra/control/main:v2ctl_linux_arm64_sig",
"//main:v2ray_linux_arm64",
"//main:v2ray_linux_arm64_sig",
],
out = "v2ray-linux-arm.zip",
mappings = gen_mappings("linux", "arm"),
out = "v2ray-linux-arm64-v8a.zip",
mappings = gen_mappings("linux", "arm64", "0"),
)
pkg_zip(
name = "v2ray_linux_arm64_package",
name = "v2ray_linux_armv7_package",
srcs = [
":config_json",
":doc",
":geodata",
":systemd",
"//infra/control/main:v2ctl_linux_arm64",
"//infra/control/main:v2ctl_linux_arm64_sig",
"//main:v2ray_linux_arm64",
"//main:v2ray_linux_arm64_sig",
"//infra/control/main:v2ctl_linux_arm_7",
"//infra/control/main:v2ctl_linux_arm_7_sig",
"//main:v2ray_linux_arm_7",
"//main:v2ray_linux_arm_7_sig",
],
out = "v2ray-linux-arm64.zip",
mappings = gen_mappings("linux", "arm64"),
out = "v2ray-linux-arm32-v7a.zip",
mappings = gen_mappings("linux", "arm", "7"),
)
pkg_zip(
name = "v2ray_linux_mips_package",
name = "v2ray_linux_armv6_package",
srcs = [
":config_json",
":doc",
":geodata",
":systemd",
"//infra/control/main:v2ctl_linux_arm_6",
"//infra/control/main:v2ctl_linux_arm_6_sig",
"//main:v2ray_linux_arm_6",
"//main:v2ray_linux_arm_6_sig",
],
out = "v2ray-linux-arm32-v6.zip",
mappings = gen_mappings("linux", "arm", "6"),
)
pkg_zip(
name = "v2ray_linux_armv5_package",
srcs = [
":config_json",
":doc",
":geodata",
":systemd",
"//infra/control/main:v2ctl_linux_arm_5",
"//infra/control/main:v2ctl_linux_arm_5_sig",
"//main:v2ray_linux_arm_5",
"//main:v2ray_linux_arm_5_sig",
],
out = "v2ray-linux-arm32-v5.zip",
mappings = gen_mappings("linux", "arm", "5"),
)
pkg_zip(
name = "v2ray_linux_mips32_package",
srcs = [
":config_json",
":doc",
@ -274,12 +286,12 @@ pkg_zip(
"//main:v2ray_linux_mips_softfloat",
"//main:v2ray_linux_mips_softfloat_sig",
],
out = "v2ray-linux-mips.zip",
mappings = gen_mappings("linux", "mips"),
out = "v2ray-linux-mips32.zip",
mappings = gen_mappings("linux", "mips", "0"),
)
pkg_zip(
name = "v2ray_linux_mipsle_package",
name = "v2ray_linux_mips32le_package",
srcs = [
":config_json",
":doc",
@ -294,8 +306,8 @@ pkg_zip(
"//main:v2ray_linux_mipsle_softfloat",
"//main:v2ray_linux_mipsle_softfloat_sig",
],
out = "v2ray-linux-mipsle.zip",
mappings = gen_mappings("linux", "mipsle"),
out = "v2ray-linux-mips32le.zip",
mappings = gen_mappings("linux", "mipsle", "0"),
)
pkg_zip(
@ -311,7 +323,7 @@ pkg_zip(
"//main:v2ray_linux_mips64_sig",
],
out = "v2ray-linux-mips64.zip",
mappings = gen_mappings("linux", "mips64"),
mappings = gen_mappings("linux", "mips64", "0"),
)
pkg_zip(
@ -327,7 +339,23 @@ pkg_zip(
"//main:v2ray_linux_mips64le_sig",
],
out = "v2ray-linux-mips64le.zip",
mappings = gen_mappings("linux", "mips64le"),
mappings = gen_mappings("linux", "mips64le", "0"),
)
pkg_zip(
name = "v2ray_linux_riscv64_package",
srcs = [
":config_json",
":doc",
":geodata",
":systemd",
"//infra/control/main:v2ctl_linux_riscv64",
"//infra/control/main:v2ctl_linux_riscv64_sig",
"//main:v2ray_linux_riscv64",
"//main:v2ray_linux_riscv64_sig",
],
out = "v2ray-linux-riscv64.zip",
mappings = gen_mappings("linux", "riscv64", "0"),
)
pkg_zip(
@ -343,7 +371,7 @@ pkg_zip(
"//main:v2ray_linux_s390x_sig",
],
out = "v2ray-linux-s390x.zip",
mappings = gen_mappings("linux", "s390x"),
mappings = gen_mappings("linux", "s390x", "0"),
)
pkg_zip(
@ -359,7 +387,7 @@ pkg_zip(
"//main:v2ray_linux_ppc64_sig",
],
out = "v2ray-linux-ppc64.zip",
mappings = gen_mappings("linux", "ppc64"),
mappings = gen_mappings("linux", "ppc64", "0"),
)
pkg_zip(
@ -375,5 +403,5 @@ pkg_zip(
"//main:v2ray_linux_ppc64le_sig",
],
out = "v2ray-linux-ppc64le.zip",
mappings = gen_mappings("linux", "ppc64le"),
mappings = gen_mappings("linux", "ppc64le", "0"),
)

@ -34,20 +34,23 @@ pushd ${ART_ROOT}
{
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen version ${RELEASE_TAG}
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen project "v2flyunstable"
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-macos.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-macos-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-32.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-arm.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-arm32-v7a.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-32.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm64-v8a.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v7a.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v6.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v5.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64le.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mipsle.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32le.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64le.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-riscv64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-s390x.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-32.zip
@ -65,20 +68,23 @@ pushd ${ART_ROOT}
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil post commit "${RELEASE_SHA}" < buildcomment
popd
upload ${ART_ROOT}/v2ray-macos.zip
upload ${ART_ROOT}/v2ray-macos-64.zip
upload ${ART_ROOT}/v2ray-windows-64.zip
upload ${ART_ROOT}/v2ray-windows-32.zip
upload ${ART_ROOT}/v2ray-windows-arm.zip
upload ${ART_ROOT}/v2ray-windows-arm32-v7a.zip
upload ${ART_ROOT}/v2ray-linux-64.zip
upload ${ART_ROOT}/v2ray-linux-32.zip
upload ${ART_ROOT}/v2ray-linux-arm.zip
upload ${ART_ROOT}/v2ray-linux-arm64.zip
upload ${ART_ROOT}/v2ray-linux-arm64-v8a.zip
upload ${ART_ROOT}/v2ray-linux-arm32-v7a.zip
upload ${ART_ROOT}/v2ray-linux-arm32-v6.zip
upload ${ART_ROOT}/v2ray-linux-arm32-v5.zip
upload ${ART_ROOT}/v2ray-linux-mips64.zip
upload ${ART_ROOT}/v2ray-linux-mips64le.zip
upload ${ART_ROOT}/v2ray-linux-mips.zip
upload ${ART_ROOT}/v2ray-linux-mipsle.zip
upload ${ART_ROOT}/v2ray-linux-mips32.zip
upload ${ART_ROOT}/v2ray-linux-mips32le.zip
upload ${ART_ROOT}/v2ray-linux-ppc64.zip
upload ${ART_ROOT}/v2ray-linux-ppc64le.zip
upload ${ART_ROOT}/v2ray-linux-riscv64.zip
upload ${ART_ROOT}/v2ray-linux-s390x.zip
upload ${ART_ROOT}/v2ray-freebsd-64.zip
upload ${ART_ROOT}/v2ray-freebsd-32.zip

@ -1,7 +1,7 @@
def gen_mappings(os, arch):
def gen_mappings(os, arch, ver):
return {
"v2ray_core/release/doc": "doc",
"v2ray_core/release/config": "",
"v2ray_core/main/" + os + "/" + arch: "",
"v2ray_core/infra/control/main/" + os + "/" + arch: "",
"v2ray_core/main/" + os + "/" + arch + "/" + ver: "",
"v2ray_core/infra/control/main/" + os + "/" + arch + "/" + ver : "",
}

@ -59,20 +59,23 @@ pushd ${ART_ROOT}
{
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen version "${GITHUB_RELEASE_TAG}"
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen project "v2fly"
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-macos.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-macos-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-32.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-arm.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-windows-arm32-v7a.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-32.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm64-v8a.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v7a.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v6.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-arm32-v5.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips64le.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mipsle.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-mips32le.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-ppc64le.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-riscv64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-linux-s390x.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-64.zip
go run github.com/xiaokangwang/V2BuildAssist/v2buildutil gen file v2ray-freebsd-32.zip
@ -84,20 +87,23 @@ pushd ${ART_ROOT}
popd
upload ${ART_ROOT}/v2ray-macos.zip
upload ${ART_ROOT}/v2ray-macos-64.zip
upload ${ART_ROOT}/v2ray-windows-64.zip
upload ${ART_ROOT}/v2ray-windows-32.zip
upload ${ART_ROOT}/v2ray-windows-arm.zip
upload ${ART_ROOT}/v2ray-windows-arm32-v7a.zip
upload ${ART_ROOT}/v2ray-linux-64.zip
upload ${ART_ROOT}/v2ray-linux-32.zip
upload ${ART_ROOT}/v2ray-linux-arm.zip
upload ${ART_ROOT}/v2ray-linux-arm64.zip
upload ${ART_ROOT}/v2ray-linux-arm64-v8a.zip
upload ${ART_ROOT}/v2ray-linux-arm32-v7a.zip
upload ${ART_ROOT}/v2ray-linux-arm32-v6.zip
upload ${ART_ROOT}/v2ray-linux-arm32-v5.zip
upload ${ART_ROOT}/v2ray-linux-mips64.zip
upload ${ART_ROOT}/v2ray-linux-mips64le.zip
upload ${ART_ROOT}/v2ray-linux-mips.zip
upload ${ART_ROOT}/v2ray-linux-mipsle.zip
upload ${ART_ROOT}/v2ray-linux-mips32.zip
upload ${ART_ROOT}/v2ray-linux-mips32le.zip
upload ${ART_ROOT}/v2ray-linux-ppc64.zip
upload ${ART_ROOT}/v2ray-linux-ppc64le.zip
upload ${ART_ROOT}/v2ray-linux-riscv64.zip
upload ${ART_ROOT}/v2ray-linux-s390x.zip
upload ${ART_ROOT}/v2ray-freebsd-64.zip
upload ${ART_ROOT}/v2ray-freebsd-32.zip

@ -50,3 +50,11 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
func bindAddr(fd uintptr, address []byte, port uint32) error {
return nil
}
func setReuseAddr(fd uintptr) error {
return nil
}
func setReusePort(fd uintptr) error {
return nil
}

@ -188,15 +188,8 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
}
func bindAddr(fd uintptr, ip []byte, port uint32) error {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
return newError("failed to set resuse_addr").Base(err).AtWarning()
}
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePortLB, 1); err != nil {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePort, 1); err != nil {
return newError("failed to set resuse_port").Base(err).AtWarning()
}
}
setReuseAddr(fd)
setReusePort(fd)
var sockaddr syscall.Sockaddr
@ -219,3 +212,19 @@ func bindAddr(fd uintptr, ip []byte, port uint32) error {
return syscall.Bind(int(fd), sockaddr)
}
func setReuseAddr(fd uintptr) error {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
return newError("failed to set SO_REUSEADDR").Base(err).AtWarning()
}
return nil
}
func setReusePort(fd uintptr) error {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePortLB, 1); err != nil {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, soReUsePort, 1); err != nil {
return newError("failed to set SO_REUSEPORT").Base(err).AtWarning()
}
}
return nil
}

@ -15,13 +15,8 @@ const (
)
func bindAddr(fd uintptr, ip []byte, port uint32) error {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
return newError("failed to set resuse_addr").Base(err).AtWarning()
}
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
return newError("failed to set resuse_port").Base(err).AtWarning()
}
setReuseAddr(fd)
setReusePort(fd)
var sockaddr syscall.Sockaddr
@ -107,9 +102,19 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
}
}
return nil
}
func setReuseAddr(fd uintptr) error {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
return newError("failed to set SO_REUSEADDR").Base(err).AtWarning()
}
return nil
}
func setReusePort(fd uintptr) error {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
return newError("failed to set SO_REUSEPORT").Base(err).AtWarning()
}
return nil
}

@ -13,3 +13,11 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
func bindAddr(fd uintptr, ip []byte, port uint32) error {
return nil
}
func setReuseAddr(fd uintptr) error {
return nil
}
func setReusePort(fd uintptr) error {
return nil
}

@ -46,3 +46,11 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
func bindAddr(fd uintptr, ip []byte, port uint32) error {
return nil
}
func setReuseAddr(fd uintptr) error {
return nil
}
func setReusePort(fd uintptr) error {
return nil
}

@ -27,6 +27,8 @@ func getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []co
}
}
setReusePort(fd)
for _, controller := range controllers {
if err := controller(network, address, fd); err != nil {
newError("failed to apply external controller").Base(err).WriteToLog(session.ExportIDToError(ctx))
@ -39,9 +41,7 @@ func getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []co
func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.Listener, error) {
var lc net.ListenConfig
if sockopt != nil || len(dl.controllers) > 0 {
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
}
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
return lc.Listen(ctx, addr.Network(), addr.String())
}
@ -49,9 +49,7 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
func (dl *DefaultListener) ListenPacket(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.PacketConn, error) {
var lc net.ListenConfig
if sockopt != nil || len(dl.controllers) > 0 {
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
}
lc.Control = getControlFunc(ctx, sockopt, dl.controllers)
return lc.ListenPacket(ctx, addr.Network(), addr.String())
}

@ -22,11 +22,14 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
if config.IsExperiment8357() {
conn = tls.UClient(conn, tlsConfig)
} else {
conn = tls.Client(conn, tlsConfig)
}
/*
if config.IsExperiment8357() {
conn = tls.UClient(conn, tlsConfig)
} else {
conn = tls.Client(conn, tlsConfig)
}
*/
conn = tls.Client(conn, tlsConfig)
}
tcpSettings := streamSettings.ProtocolSettings.(*Config)

@ -7,8 +7,6 @@ import (
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
utls "github.com/refraction-networking/utls"
)
//go:generate errorgen
@ -45,6 +43,7 @@ func Client(c net.Conn, config *tls.Config) net.Conn {
return &Conn{Conn: tlsConn}
}
/*
func copyConfig(c *tls.Config) *utls.Config {
return &utls.Config{
NextProtos: c.NextProtos,
@ -59,6 +58,7 @@ func UClient(c net.Conn, config *tls.Config) net.Conn {
uConfig := copyConfig(config)
return utls.Client(c, uConfig)
}
*/
// Server initiates a TLS server handshake on the given connection.
func Server(c net.Conn, config *tls.Config) net.Conn {

Loading…
Cancel
Save