Browse Source

VLESS PREVIEW 1.2

RPRX 5 years ago
parent
commit
1cfc02e720

+ 38 - 3
infra/conf/vless.go

@@ -17,12 +17,14 @@ type VLessInboundFallback struct {
 	Addr *Address `json:"addr"`
 	Addr *Address `json:"addr"`
 	Port uint16   `json:"port"`
 	Port uint16   `json:"port"`
 	Unix string   `json:"unix"`
 	Unix string   `json:"unix"`
+	Xver uint16   `json:"xver"`
 }
 }
 
 
 type VLessInboundConfig struct {
 type VLessInboundConfig struct {
-	Users      []json.RawMessage     `json:"clients"`
-	Decryption string                `json:"decryption"`
-	Fallback   *VLessInboundFallback `json:"fallback"`
+	Users       []json.RawMessage     `json:"clients"`
+	Decryption  string                `json:"decryption"`
+	Fallback    *VLessInboundFallback `json:"fallback"`
+	Fallback_h2 *VLessInboundFallback `json:"fallback_h2"`
 }
 }
 
 
 // Build implements Buildable
 // Build implements Buildable
@@ -36,6 +38,9 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
 	config.Decryption = c.Decryption
 	config.Decryption = c.Decryption
 
 
 	if c.Fallback != nil {
 	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 != "" {
 			if c.Fallback.Unix[0] == '@' {
 			if c.Fallback.Unix[0] == '@' {
 				c.Fallback.Unix = "\x00" + c.Fallback.Unix[1:]
 				c.Fallback.Unix = "\x00" + c.Fallback.Unix[1:]
@@ -54,6 +59,36 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
 			Addr: c.Fallback.Addr.Build(),
 			Addr: c.Fallback.Addr.Build(),
 			Port: uint32(c.Fallback.Port),
 			Port: uint32(c.Fallback.Port),
 			Unix: c.Fallback.Unix,
 			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),
 		}
 		}
 	}
 	}
 
 

+ 12 - 1
infra/conf/vless_test.go

@@ -79,7 +79,10 @@ func TestVLessInbound(t *testing.T) {
 				"decryption": "none",
 				"decryption": "none",
 				"fallback": {
 				"fallback": {
 					"port": 80,
 					"port": 80,
-					"unix": "@/dev/shm/domain.socket"
+				},
+				"fallback_h2": {
+					"unix": "@/dev/shm/domain.socket",
+					"xver": 2
 				}
 				}
 			}`,
 			}`,
 			Parser: loadJSON(creator),
 			Parser: loadJSON(creator),
@@ -102,7 +105,15 @@ func TestVLessInbound(t *testing.T) {
 						},
 						},
 					},
 					},
 					Port: 80,
 					Port: 80,
+				},
+				FallbackH2: &inbound.FallbackH2{
+					Addr: &net.IPOrDomain{
+						Address: &net.IPOrDomain_Ip{
+							Ip: []byte{127, 0, 0, 1},
+						},
+					},
 					Unix: "\x00/dev/shm/domain.socket",
 					Unix: "\x00/dev/shm/domain.socket",
+					Xver: 2,
 				},
 				},
 			},
 			},
 		},
 		},

+ 4 - 4
proxy/vless/encoding/addons.go

@@ -17,7 +17,7 @@ func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
 	default:
 	default:
 
 
 		if err := buffer.WriteByte(0); err != nil {
 		if err := buffer.WriteByte(0); err != nil {
-			return newError("failed to write addons protobuf length").Base(err).AtWarning()
+			return newError("failed to write addons protobuf length").Base(err)
 		}
 		}
 
 
 	}
 	}
@@ -32,18 +32,18 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
 
 
 	buffer.Clear()
 	buffer.Clear()
 	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
 	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
-		return nil, newError("failed to read addons protobuf length").Base(err).AtWarning()
+		return nil, newError("failed to read addons protobuf length").Base(err)
 	}
 	}
 
 
 	if length := int32(buffer.Byte(0)); length != 0 {
 	if length := int32(buffer.Byte(0)); length != 0 {
 
 
 		buffer.Clear()
 		buffer.Clear()
 		if _, err := buffer.ReadFullFrom(reader, length); err != nil {
 		if _, err := buffer.ReadFullFrom(reader, length); err != nil {
-			return nil, newError("failed to read addons protobuf value").Base(err).AtWarning()
+			return nil, newError("failed to read addons protobuf value").Base(err)
 		}
 		}
 
 
 		if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
 		if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
-			return nil, newError("failed to unmarshal addons protobuf value").Base(err).AtWarning()
+			return nil, newError("failed to unmarshal addons protobuf value").Base(err)
 		}
 		}
 
 
 		// Verification.
 		// Verification.

+ 19 - 19
proxy/vless/encoding/encoding.go

@@ -29,29 +29,29 @@ func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requ
 	defer buffer.Release()
 	defer buffer.Release()
 
 
 	if err := buffer.WriteByte(request.Version); err != nil {
 	if err := buffer.WriteByte(request.Version); err != nil {
-		return newError("failed to write request version").Base(err).AtWarning()
+		return newError("failed to write request version").Base(err)
 	}
 	}
 
 
 	if _, err := buffer.Write(request.User.Account.(*vless.MemoryAccount).ID.Bytes()); err != nil {
 	if _, err := buffer.Write(request.User.Account.(*vless.MemoryAccount).ID.Bytes()); err != nil {
-		return newError("failed to write request user id").Base(err).AtWarning()
+		return newError("failed to write request user id").Base(err)
 	}
 	}
 
 
 	if err := EncodeHeaderAddons(&buffer, requestAddons); err != nil {
 	if err := EncodeHeaderAddons(&buffer, requestAddons); err != nil {
-		return newError("failed to encode request header addons").Base(err).AtWarning()
+		return newError("failed to encode request header addons").Base(err)
 	}
 	}
 
 
 	if err := buffer.WriteByte(byte(request.Command)); err != nil {
 	if err := buffer.WriteByte(byte(request.Command)); err != nil {
-		return newError("failed to write request command").Base(err).AtWarning()
+		return newError("failed to write request command").Base(err)
 	}
 	}
 
 
 	if request.Command != protocol.RequestCommandMux {
 	if request.Command != protocol.RequestCommandMux {
 		if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil {
 		if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil {
-			return newError("failed to write request address and port").Base(err).AtWarning()
+			return newError("failed to write request address and port").Base(err)
 		}
 		}
 	}
 	}
 
 
 	if _, err := writer.Write(buffer.Bytes()); err != nil {
 	if _, err := writer.Write(buffer.Bytes()); err != nil {
-		return newError("failed to write request header").Base(err).AtWarning()
+		return newError("failed to write request header").Base(err)
 	}
 	}
 
 
 	return nil
 	return nil
@@ -67,7 +67,7 @@ func DecodeRequestHeader(reader io.Reader, validator *vless.Validator) (*protoco
 
 
 	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
 	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
 		pre.Write(buffer.Bytes())
 		pre.Write(buffer.Bytes())
-		return nil, nil, newError("failed to read request version").Base(err).AtWarning(), pre
+		return nil, nil, newError("failed to read request version").Base(err), pre
 	}
 	}
 
 
 	request := &protocol.RequestHeader{
 	request := &protocol.RequestHeader{
@@ -82,7 +82,7 @@ func DecodeRequestHeader(reader io.Reader, validator *vless.Validator) (*protoco
 		buffer.Clear()
 		buffer.Clear()
 		if _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil {
 		if _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil {
 			pre.Write(buffer.Bytes())
 			pre.Write(buffer.Bytes())
-			return nil, nil, newError("failed to read request user id").Base(err).AtWarning(), pre
+			return nil, nil, newError("failed to read request user id").Base(err), pre
 		}
 		}
 
 
 		var id [16]byte
 		var id [16]byte
@@ -90,17 +90,17 @@ func DecodeRequestHeader(reader io.Reader, validator *vless.Validator) (*protoco
 
 
 		if request.User = validator.Get(id); request.User == nil {
 		if request.User = validator.Get(id); request.User == nil {
 			pre.Write(buffer.Bytes())
 			pre.Write(buffer.Bytes())
-			return nil, nil, newError("invalid request user id").AtWarning(), pre
+			return nil, nil, newError("invalid request user id"), pre
 		}
 		}
 
 
 		requestAddons, err := DecodeHeaderAddons(&buffer, reader)
 		requestAddons, err := DecodeHeaderAddons(&buffer, reader)
 		if err != nil {
 		if err != nil {
-			return nil, nil, newError("failed to decode request header addons").Base(err).AtWarning(), nil
+			return nil, nil, newError("failed to decode request header addons").Base(err), nil
 		}
 		}
 
 
 		buffer.Clear()
 		buffer.Clear()
 		if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
 		if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
-			return nil, nil, newError("failed to read request command").Base(err).AtWarning(), nil
+			return nil, nil, newError("failed to read request command").Base(err), nil
 		}
 		}
 
 
 		request.Command = protocol.RequestCommand(buffer.Byte(0))
 		request.Command = protocol.RequestCommand(buffer.Byte(0))
@@ -116,14 +116,14 @@ func DecodeRequestHeader(reader io.Reader, validator *vless.Validator) (*protoco
 		}
 		}
 
 
 		if request.Address == nil {
 		if request.Address == nil {
-			return nil, nil, newError("invalid request address").AtWarning(), nil
+			return nil, nil, newError("invalid request address"), nil
 		}
 		}
 
 
 		return request, requestAddons, nil, nil
 		return request, requestAddons, nil, nil
 
 
 	default:
 	default:
 
 
-		return nil, nil, newError("unexpected request version").AtWarning(), pre
+		return nil, nil, newError("unexpected request version"), pre
 
 
 	}
 	}
 
 
@@ -136,15 +136,15 @@ func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, res
 	defer buffer.Release()
 	defer buffer.Release()
 
 
 	if err := buffer.WriteByte(request.Version); err != nil {
 	if err := buffer.WriteByte(request.Version); err != nil {
-		return newError("failed to write response version").Base(err).AtWarning()
+		return newError("failed to write response version").Base(err)
 	}
 	}
 
 
 	if err := EncodeHeaderAddons(&buffer, responseAddons); err != nil {
 	if err := EncodeHeaderAddons(&buffer, responseAddons); err != nil {
-		return newError("failed to encode response header addons").Base(err).AtWarning()
+		return newError("failed to encode response header addons").Base(err)
 	}
 	}
 
 
 	if _, err := writer.Write(buffer.Bytes()); err != nil {
 	if _, err := writer.Write(buffer.Bytes()); err != nil {
-		return newError("failed to write response header").Base(err).AtWarning()
+		return newError("failed to write response header").Base(err)
 	}
 	}
 
 
 	return nil
 	return nil
@@ -157,16 +157,16 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader, res
 	defer buffer.Release()
 	defer buffer.Release()
 
 
 	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
 	if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
-		return newError("failed to read response version").Base(err).AtWarning()
+		return newError("failed to read response version").Base(err)
 	}
 	}
 
 
 	if buffer.Byte(0) != request.Version {
 	if buffer.Byte(0) != request.Version {
-		return newError("unexpected response version. Expecting ", int(request.Version), " but actually ", int(buffer.Byte(0))).AtWarning()
+		return newError("unexpected response version. Expecting ", int(request.Version), " but actually ", int(buffer.Byte(0)))
 	}
 	}
 
 
 	responseAddons, err := DecodeHeaderAddons(&buffer, reader)
 	responseAddons, err := DecodeHeaderAddons(&buffer, reader)
 	if err != nil {
 	if err != nil {
-		return newError("failed to decode response header addons").Base(err).AtWarning()
+		return newError("failed to decode response header addons").Base(err)
 	}
 	}
 
 
 	return nil
 	return nil

+ 151 - 35
proxy/vless/inbound/config.pb.go

@@ -35,6 +35,7 @@ type Fallback struct {
 	Addr *net.IPOrDomain `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
 	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"`
 	Port uint32          `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
 	Unix string          `protobuf:"bytes,3,opt,name=unix,proto3" json:"unix,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() {
 func (x *Fallback) Reset() {
@@ -90,6 +91,84 @@ func (x *Fallback) GetUnix() string {
 	return ""
 	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 {
 type Config struct {
 	state         protoimpl.MessageState
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	sizeCache     protoimpl.SizeCache
@@ -97,14 +176,15 @@ type Config struct {
 
 
 	User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"`
 	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 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"`
+	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() {
 func (x *Config) Reset() {
 	*x = Config{}
 	*x = Config{}
 	if protoimpl.UnsafeEnabled {
 	if protoimpl.UnsafeEnabled {
-		mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[1]
+		mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[2]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 		ms.StoreMessageInfo(mi)
 	}
 	}
@@ -117,7 +197,7 @@ func (x *Config) String() string {
 func (*Config) ProtoMessage() {}
 func (*Config) ProtoMessage() {}
 
 
 func (x *Config) ProtoReflect() protoreflect.Message {
 func (x *Config) ProtoReflect() protoreflect.Message {
-	mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[1]
+	mi := &file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[2]
 	if protoimpl.UnsafeEnabled && x != nil {
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
 		if ms.LoadMessageInfo() == nil {
@@ -130,7 +210,7 @@ func (x *Config) ProtoReflect() protoreflect.Message {
 
 
 // Deprecated: Use Config.ProtoReflect.Descriptor instead.
 // Deprecated: Use Config.ProtoReflect.Descriptor instead.
 func (*Config) Descriptor() ([]byte, []int) {
 func (*Config) Descriptor() ([]byte, []int) {
-	return file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1}
+	return file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{2}
 }
 }
 
 
 func (x *Config) GetUser() []*protocol.User {
 func (x *Config) GetUser() []*protocol.User {
@@ -154,6 +234,13 @@ func (x *Config) GetFallback() *Fallback {
 	return nil
 	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 protoreflect.FileDescriptor
 
 
 var file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc = []byte{
 var file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc = []byte{
@@ -167,30 +254,44 @@ var file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc = []byte{
 	0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x29, 0x76, 0x32, 0x72, 0x61,
 	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,
 	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,
 	0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x69, 0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
+	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,
 	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,
 	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,
 	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,
 	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,
 	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,
 	0x75, 0x6e, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x6e, 0x69, 0x78,
-	0x22, 0xa4, 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,
+	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,
 	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, 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,
+	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 (
 var (
@@ -205,22 +306,25 @@ func file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDescGZIP() []byte {
 	return 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, 2)
+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{}{
 var file_v2ray_com_core_proxy_vless_inbound_config_proto_goTypes = []interface{}{
 	(*Fallback)(nil),       // 0: v2ray.core.proxy.vless.inbound.Fallback
 	(*Fallback)(nil),       // 0: v2ray.core.proxy.vless.inbound.Fallback
-	(*Config)(nil),         // 1: v2ray.core.proxy.vless.inbound.Config
-	(*net.IPOrDomain)(nil), // 2: v2ray.core.common.net.IPOrDomain
-	(*protocol.User)(nil),  // 3: v2ray.core.common.protocol.User
+	(*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{
 var file_v2ray_com_core_proxy_vless_inbound_config_proto_depIdxs = []int32{
-	2, // 0: v2ray.core.proxy.vless.inbound.Fallback.addr:type_name -> v2ray.core.common.net.IPOrDomain
-	3, // 1: v2ray.core.proxy.vless.inbound.Config.user:type_name -> v2ray.core.common.protocol.User
-	0, // 2: v2ray.core.proxy.vless.inbound.Config.fallback:type_name -> v2ray.core.proxy.vless.inbound.Fallback
-	3, // [3:3] is the sub-list for method output_type
-	3, // [3:3] is the sub-list for method input_type
-	3, // [3:3] is the sub-list for extension type_name
-	3, // [3:3] is the sub-list for extension extendee
-	0, // [0:3] is the sub-list for field type_name
+	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 init() { file_v2ray_com_core_proxy_vless_inbound_config_proto_init() }
@@ -242,6 +346,18 @@ func file_v2ray_com_core_proxy_vless_inbound_config_proto_init() {
 			}
 			}
 		}
 		}
 		file_v2ray_com_core_proxy_vless_inbound_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
 		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 {
 			switch v := v.(*Config); i {
 			case 0:
 			case 0:
 				return &v.state
 				return &v.state
@@ -260,7 +376,7 @@ func file_v2ray_com_core_proxy_vless_inbound_config_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc,
 			RawDescriptor: file_v2ray_com_core_proxy_vless_inbound_config_proto_rawDesc,
 			NumEnums:      0,
 			NumEnums:      0,
-			NumMessages:   2,
+			NumMessages:   3,
 			NumExtensions: 0,
 			NumExtensions: 0,
 			NumServices:   0,
 			NumServices:   0,
 		},
 		},

+ 9 - 0
proxy/vless/inbound/config.proto

@@ -13,6 +13,14 @@ message Fallback {
   v2ray.core.common.net.IPOrDomain addr = 1;
   v2ray.core.common.net.IPOrDomain addr = 1;
   uint32 port = 2;
   uint32 port = 2;
   string unix = 3;
   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 {
 message Config {
@@ -20,4 +28,5 @@ message Config {
   // Decryption settings. Only applies to server side, and only accepts "none" for now.
   // Decryption settings. Only applies to server side, and only accepts "none" for now.
   string decryption = 2;
   string decryption = 2;
   Fallback fallback = 3;
   Fallback fallback = 3;
+  Fallback_h2 fallback_h2 = 4;
 }
 }

+ 102 - 8
proxy/vless/inbound/inbound.go

@@ -6,6 +6,7 @@ package inbound
 
 
 import (
 import (
 	"context"
 	"context"
+	"encoding/hex"
 	"io"
 	"io"
 	"strconv"
 	"strconv"
 	"time"
 	"time"
@@ -28,6 +29,7 @@ import (
 	"v2ray.com/core/proxy/vless"
 	"v2ray.com/core/proxy/vless"
 	"v2ray.com/core/proxy/vless/encoding"
 	"v2ray.com/core/proxy/vless/encoding"
 	"v2ray.com/core/transport/internet"
 	"v2ray.com/core/transport/internet"
+	"v2ray.com/core/transport/internet/tls"
 )
 )
 
 
 func init() {
 func init() {
@@ -51,6 +53,8 @@ type Handler struct {
 	dns                   dns.Client
 	dns                   dns.Client
 	fallback              *Fallback // or nil
 	fallback              *Fallback // or nil
 	addrport              string
 	addrport              string
+	fallback_h2           *FallbackH2 // or nil
+	addrport_h2           string
 }
 }
 
 
 // New creates a new VLess inbound handler.
 // New creates a new VLess inbound handler.
@@ -78,6 +82,10 @@ func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
 		handler.fallback = config.Fallback
 		handler.fallback = config.Fallback
 		handler.addrport = handler.fallback.Addr.AsAddress().String() + ":" + strconv.Itoa(int(handler.fallback.Port))
 		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
 	return handler, nil
 }
 }
@@ -113,6 +121,33 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
 	first := buf.New()
 	first := buf.New()
 	first.ReadFrom(connection)
 	first.ReadFrom(connection)
 
 
+	var fallback uint32
+	var addrport string
+	var unixpath string
+	var proxyver uint32
+
+	if h.fallback != nil {
+		fallback = 1
+		addrport = h.addrport
+		unixpath = h.fallback.Unix
+		proxyver = h.fallback.Xver
+	}
+
+	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
+				addrport = h.addrport_h2
+				unixpath = h.fallback_h2.Unix
+				proxyver = h.fallback_h2.Xver
+			}
+		}
+	}
+
 	sid := session.ExportIDToError(ctx)
 	sid := session.ExportIDToError(ctx)
 	newError("firstLen = ", first.Len()).AtInfo().WriteToLog(sid)
 	newError("firstLen = ", first.Len()).AtInfo().WriteToLog(sid)
 
 
@@ -126,26 +161,33 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
 	var err error
 	var err error
 	var pre *buf.Buffer
 	var pre *buf.Buffer
 
 
-	if h.fallback != nil && first.Len() < 18 {
+	if fallback > 0 && first.Len() < 18 {
 		err = newError("fallback directly")
 		err = newError("fallback directly")
-		pre = buf.New()
 	} else {
 	} else {
 		request, requestAddons, err, pre = encoding.DecodeRequestHeader(reader, h.validator)
 		request, requestAddons, err, pre = encoding.DecodeRequestHeader(reader, h.validator)
+		if pre == nil {
+			fallback = 0
+		}
 	}
 	}
 
 
 	if err != nil {
 	if err != nil {
 
 
-		if h.fallback != nil && pre != nil {
-			newError("fallback starts").AtInfo().WriteToLog(sid)
+		if fallback > 0 {
+			switch fallback {
+			case 1:
+				newError("fallback starts").Base(err).AtInfo().WriteToLog(sid)
+			case 2:
+				newError("fallback_h2 starts").Base(err).AtInfo().WriteToLog(sid)
+			}
 
 
 			var conn net.Conn
 			var conn net.Conn
 			if err := retry.ExponentialBackoff(5, 100).On(func() error {
 			if err := retry.ExponentialBackoff(5, 100).On(func() error {
 				var dialer net.Dialer
 				var dialer net.Dialer
 				var err error
 				var err error
-				if h.fallback.Unix != "" {
-					conn, err = dialer.DialContext(ctx, "unix", h.fallback.Unix)
+				if unixpath != "" {
+					conn, err = dialer.DialContext(ctx, "unix", unixpath)
 				} else {
 				} else {
-					conn, err = dialer.DialContext(ctx, "tcp", h.addrport)
+					conn, err = dialer.DialContext(ctx, "tcp", addrport)
 				}
 				}
 				if err != nil {
 				if err != nil {
 					return err
 					return err
@@ -166,7 +208,59 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
 
 
 			postRequest := func() error {
 			postRequest := func() error {
 				defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
 				defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
-				if pre.Len() > 0 {
+				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 {
 					if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pre}); err != nil {
 						return newError("failed to fallback request pre").Base(err).AtWarning()
 						return newError("failed to fallback request pre").Base(err).AtWarning()
 					}
 					}