1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 09:36:34 -05:00

Add socks4/4a support

This commit is contained in:
世界 2021-09-16 14:42:12 +08:00 committed by Shelikhoo
parent 41ae53e60d
commit 9ee66f7efe
No known key found for this signature in database
GPG Key ID: C4D5E79D22B25316
4 changed files with 166 additions and 35 deletions

View File

@ -2,6 +2,7 @@ package v4
import ( import (
"encoding/json" "encoding/json"
"strings"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
@ -74,11 +75,22 @@ type SocksRemoteConfig struct {
type SocksClientConfig struct { type SocksClientConfig struct {
Servers []*SocksRemoteConfig `json:"servers"` Servers []*SocksRemoteConfig `json:"servers"`
Version string `json:"version"`
} }
func (v *SocksClientConfig) Build() (proto.Message, error) { func (v *SocksClientConfig) Build() (proto.Message, error) {
config := new(socks.ClientConfig) config := new(socks.ClientConfig)
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
switch strings.ToLower(v.Version) {
case "4":
config.Version = socks.Version_SOCKS4
case "4a":
config.Version = socks.Version_SOCKS4A
case "", "5":
config.Version = socks.Version_SOCKS5
default:
return nil, newError("failed to parse socks server version: ", v.Version).AtError()
}
for idx, serverConfig := range v.Servers { for idx, serverConfig := range v.Servers {
server := &protocol.ServerEndpoint{ server := &protocol.ServerEndpoint{
Address: serverConfig.Address.Build(), Address: serverConfig.Address.Build(),
@ -93,6 +105,9 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
if err := json.Unmarshal(rawUser, account); err != nil { if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("failed to parse socks account").Base(err).AtError() return nil, newError("failed to parse socks account").Base(err).AtError()
} }
if config.Version != socks.Version_SOCKS5 && account.Password != "" {
return nil, newError("password is only supported in socks5").AtError()
}
user.Account = serial.ToTypedMessage(account.Build()) user.Account = serial.ToTypedMessage(account.Build())
server.User = append(server.User, user) server.User = append(server.User, user)
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/v2fly/v2ray-core/v4/common/session" "github.com/v2fly/v2ray-core/v4/common/session"
"github.com/v2fly/v2ray-core/v4/common/signal" "github.com/v2fly/v2ray-core/v4/common/signal"
"github.com/v2fly/v2ray-core/v4/common/task" "github.com/v2fly/v2ray-core/v4/common/task"
"github.com/v2fly/v2ray-core/v4/features/dns"
"github.com/v2fly/v2ray-core/v4/features/policy" "github.com/v2fly/v2ray-core/v4/features/policy"
"github.com/v2fly/v2ray-core/v4/transport" "github.com/v2fly/v2ray-core/v4/transport"
"github.com/v2fly/v2ray-core/v4/transport/internet" "github.com/v2fly/v2ray-core/v4/transport/internet"
@ -22,6 +23,8 @@ import (
type Client struct { type Client struct {
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
policyManager policy.Manager policyManager policy.Manager
version Version
dns dns.Client
} }
// NewClient create a new Socks5 client based on the given config. // NewClient create a new Socks5 client based on the given config.
@ -39,10 +42,16 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
} }
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
return &Client{ c := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
}, nil version: config.Version,
}
if config.Version == Version_SOCKS4 {
c.dns = v.GetFeature(dns.ClientType()).(dns.Client)
}
return c, nil
} }
// Process implements proxy.Outbound.Process. // Process implements proxy.Outbound.Process.
@ -89,6 +98,39 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
Address: destination.Address, Address: destination.Address,
Port: destination.Port, Port: destination.Port,
} }
switch c.version {
case Version_SOCKS4:
if request.Address.Family().IsDomain() {
if d, ok := c.dns.(dns.ClientWithIPOption); ok {
d.SetFakeDNSOption(false) // Skip FakeDNS
} else {
newError("DNS client doesn't implement ClientWithIPOption")
}
lookupFunc := c.dns.LookupIP
if lookupIPv4, ok := c.dns.(dns.IPv4Lookup); ok {
lookupFunc = lookupIPv4.LookupIPv4
}
ips, err := lookupFunc(request.Address.Domain())
if err != nil {
return err
} else if len(ips) == 0 {
return dns.ErrEmptyResponse
}
request.Address = net.IPAddress(ips[0])
}
fallthrough
case Version_SOCKS4A:
request.Version = socks4Version
if destination.Network == net.Network_UDP {
return newError("udp is not supported in socks4")
} else if destination.Address.Family().IsIPv6() {
return newError("ipv6 is not supported in socks4")
}
}
if destination.Network == net.Network_UDP { if destination.Network == net.Network_UDP {
request.Command = protocol.RequestCommandUDP request.Command = protocol.RequestCommandUDP
} }

View File

@ -71,6 +71,56 @@ func (AuthType) EnumDescriptor() ([]byte, []int) {
return file_proxy_socks_config_proto_rawDescGZIP(), []int{0} return file_proxy_socks_config_proto_rawDescGZIP(), []int{0}
} }
// AuthType is the outbound server version of Socks proxy.
type Version int32
const (
Version_SOCKS5 Version = 0
Version_SOCKS4 Version = 1
Version_SOCKS4A Version = 2
)
// Enum value maps for Version.
var (
Version_name = map[int32]string{
0: "SOCKS5",
1: "SOCKS4",
2: "SOCKS4A",
}
Version_value = map[string]int32{
"SOCKS5": 0,
"SOCKS4": 1,
"SOCKS4A": 2,
}
)
func (x Version) Enum() *Version {
p := new(Version)
*p = x
return p
}
func (x Version) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Version) Descriptor() protoreflect.EnumDescriptor {
return file_proxy_socks_config_proto_enumTypes[1].Descriptor()
}
func (Version) Type() protoreflect.EnumType {
return &file_proxy_socks_config_proto_enumTypes[1]
}
func (x Version) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Version.Descriptor instead.
func (Version) EnumDescriptor() ([]byte, []int) {
return file_proxy_socks_config_proto_rawDescGZIP(), []int{1}
}
// Account represents a Socks account. // Account represents a Socks account.
type Account struct { type Account struct {
state protoimpl.MessageState state protoimpl.MessageState
@ -224,7 +274,8 @@ type ClientConfig struct {
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
// Sever is a list of Socks server addresses. // Sever is a list of Socks server addresses.
Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"` Server []*protocol.ServerEndpoint `protobuf:"bytes,1,rep,name=server,proto3" json:"server,omitempty"`
Version Version `protobuf:"varint,2,opt,name=version,proto3,enum=v2ray.core.proxy.socks.Version" json:"version,omitempty"`
} }
func (x *ClientConfig) Reset() { func (x *ClientConfig) Reset() {
@ -266,6 +317,13 @@ func (x *ClientConfig) GetServer() []*protocol.ServerEndpoint {
return nil return nil
} }
func (x *ClientConfig) GetVersion() Version {
if x != nil {
return x.Version
}
return Version_SOCKS5
}
var File_proxy_socks_config_proto protoreflect.FileDescriptor var File_proxy_socks_config_proto protoreflect.FileDescriptor
var file_proxy_socks_config_proto_rawDesc = []byte{ var file_proxy_socks_config_proto_rawDesc = []byte{
@ -303,22 +361,28 @@ var file_proxy_socks_config_proto_rawDesc = []byte{
0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x52, 0x0a, 0x0c, 0x43, 0x6c, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8d, 0x01, 0x0a, 0x0c, 0x43,
0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x65, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x42, 0x0a, 0x06, 0x73,
0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2a, 0x25, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12,
0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x39, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e,
0x5f, 0x41, 0x55, 0x54, 0x48, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x57, 0x32, 0x1f, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72,
0x4f, 0x52, 0x44, 0x10, 0x01, 0x42, 0x63, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2a, 0x25, 0x0a, 0x08, 0x41, 0x75,
0x63, 0x6b, 0x73, 0x50, 0x01, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x5f, 0x41, 0x55, 0x54,
0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x48, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10,
0x72, 0x65, 0x2f, 0x76, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x6f, 0x63, 0x6b, 0x01, 0x2a, 0x2e, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06,
0x73, 0xaa, 0x02, 0x16, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x53, 0x4f, 0x43, 0x4b, 0x53, 0x35, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x4f, 0x43, 0x4b,
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x53, 0x34, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x4f, 0x43, 0x4b, 0x53, 0x34, 0x41, 0x10,
0x6f, 0x33, 0x02, 0x42, 0x63, 0x0a, 0x1a, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x50,
0x01, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32,
0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76,
0x34, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0xaa, 0x02, 0x16,
0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,
0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -333,27 +397,29 @@ func file_proxy_socks_config_proto_rawDescGZIP() []byte {
return file_proxy_socks_config_proto_rawDescData return file_proxy_socks_config_proto_rawDescData
} }
var file_proxy_socks_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_proxy_socks_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_proxy_socks_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_proxy_socks_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_proxy_socks_config_proto_goTypes = []interface{}{ var file_proxy_socks_config_proto_goTypes = []interface{}{
(AuthType)(0), // 0: v2ray.core.proxy.socks.AuthType (AuthType)(0), // 0: v2ray.core.proxy.socks.AuthType
(*Account)(nil), // 1: v2ray.core.proxy.socks.Account (Version)(0), // 1: v2ray.core.proxy.socks.Version
(*ServerConfig)(nil), // 2: v2ray.core.proxy.socks.ServerConfig (*Account)(nil), // 2: v2ray.core.proxy.socks.Account
(*ClientConfig)(nil), // 3: v2ray.core.proxy.socks.ClientConfig (*ServerConfig)(nil), // 3: v2ray.core.proxy.socks.ServerConfig
nil, // 4: v2ray.core.proxy.socks.ServerConfig.AccountsEntry (*ClientConfig)(nil), // 4: v2ray.core.proxy.socks.ClientConfig
(*net.IPOrDomain)(nil), // 5: v2ray.core.common.net.IPOrDomain nil, // 5: v2ray.core.proxy.socks.ServerConfig.AccountsEntry
(*protocol.ServerEndpoint)(nil), // 6: v2ray.core.common.protocol.ServerEndpoint (*net.IPOrDomain)(nil), // 6: v2ray.core.common.net.IPOrDomain
(*protocol.ServerEndpoint)(nil), // 7: v2ray.core.common.protocol.ServerEndpoint
} }
var file_proxy_socks_config_proto_depIdxs = []int32{ var file_proxy_socks_config_proto_depIdxs = []int32{
0, // 0: v2ray.core.proxy.socks.ServerConfig.auth_type:type_name -> v2ray.core.proxy.socks.AuthType 0, // 0: v2ray.core.proxy.socks.ServerConfig.auth_type:type_name -> v2ray.core.proxy.socks.AuthType
4, // 1: v2ray.core.proxy.socks.ServerConfig.accounts:type_name -> v2ray.core.proxy.socks.ServerConfig.AccountsEntry 5, // 1: v2ray.core.proxy.socks.ServerConfig.accounts:type_name -> v2ray.core.proxy.socks.ServerConfig.AccountsEntry
5, // 2: v2ray.core.proxy.socks.ServerConfig.address:type_name -> v2ray.core.common.net.IPOrDomain 6, // 2: v2ray.core.proxy.socks.ServerConfig.address:type_name -> v2ray.core.common.net.IPOrDomain
6, // 3: v2ray.core.proxy.socks.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint 7, // 3: v2ray.core.proxy.socks.ClientConfig.server:type_name -> v2ray.core.common.protocol.ServerEndpoint
4, // [4:4] is the sub-list for method output_type 1, // 4: v2ray.core.proxy.socks.ClientConfig.version:type_name -> v2ray.core.proxy.socks.Version
4, // [4:4] is the sub-list for method input_type 5, // [5:5] is the sub-list for method output_type
4, // [4:4] is the sub-list for extension type_name 5, // [5:5] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension extendee 5, // [5:5] is the sub-list for extension type_name
0, // [0:4] is the sub-list for field 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_proxy_socks_config_proto_init() } func init() { file_proxy_socks_config_proto_init() }
@ -404,7 +470,7 @@ func file_proxy_socks_config_proto_init() {
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proxy_socks_config_proto_rawDesc, RawDescriptor: file_proxy_socks_config_proto_rawDesc,
NumEnums: 1, NumEnums: 2,
NumMessages: 4, NumMessages: 4,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,

View File

@ -23,6 +23,13 @@ enum AuthType {
PASSWORD = 1; PASSWORD = 1;
} }
enum Version {
SOCKS5 = 0;
SOCKS4 = 1;
SOCKS4A = 2;
}
// ServerConfig is the protobuf config for Socks server. // ServerConfig is the protobuf config for Socks server.
message ServerConfig { message ServerConfig {
AuthType auth_type = 1; AuthType auth_type = 1;
@ -37,4 +44,5 @@ message ServerConfig {
message ClientConfig { message ClientConfig {
// Sever is a list of Socks server addresses. // Sever is a list of Socks server addresses.
repeated v2ray.core.common.protocol.ServerEndpoint server = 1; repeated v2ray.core.common.protocol.ServerEndpoint server = 1;
Version version = 2;
} }