1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-09-27 14:26:11 -04:00

support client subnet

This commit is contained in:
Darien Raymond 2018-06-26 17:14:51 +02:00
parent ff0ae91b9b
commit e9e9de55ac
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
4 changed files with 163 additions and 48 deletions

View File

@ -19,19 +19,21 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config struct {
// Nameservers used by this DNS. Only traditional UDP servers are support at the moment.
// A special value 'localhost' as a domain address can be set to use DNS on local system.
NameServers []*net.Endpoint `protobuf:"bytes,1,rep,name=NameServers" json:"NameServers,omitempty"`
NameServers []*net.Endpoint `protobuf:"bytes,1,rep,name=NameServers,proto3" json:"NameServers,omitempty"`
// Static hosts. Domain to IP.
Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Hosts map[string]*net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts,proto3" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// Client IP for EDNS client subnet.
ClientIp *Config_ClientIP `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) {
return fileDescriptor_config_862435acfeec6b70, []int{0}
return fileDescriptor_config_209d2630698ab6f5, []int{0}
}
func (m *Config) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Config.Unmarshal(m, b)
@ -65,33 +67,93 @@ func (m *Config) GetHosts() map[string]*net.IPOrDomain {
return nil
}
func (m *Config) GetClientIp() *Config_ClientIP {
if m != nil {
return m.ClientIp
}
return nil
}
type Config_ClientIP struct {
// IPv4 address of the client. Must be 4 bytes.
V4 []byte `protobuf:"bytes,1,opt,name=v4,proto3" json:"v4,omitempty"`
// IPv6 address of the client. Must be 4 bytes.
V6 []byte `protobuf:"bytes,2,opt,name=v6,proto3" json:"v6,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Config_ClientIP) Reset() { *m = Config_ClientIP{} }
func (m *Config_ClientIP) String() string { return proto.CompactTextString(m) }
func (*Config_ClientIP) ProtoMessage() {}
func (*Config_ClientIP) Descriptor() ([]byte, []int) {
return fileDescriptor_config_209d2630698ab6f5, []int{0, 1}
}
func (m *Config_ClientIP) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Config_ClientIP.Unmarshal(m, b)
}
func (m *Config_ClientIP) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Config_ClientIP.Marshal(b, m, deterministic)
}
func (dst *Config_ClientIP) XXX_Merge(src proto.Message) {
xxx_messageInfo_Config_ClientIP.Merge(dst, src)
}
func (m *Config_ClientIP) XXX_Size() int {
return xxx_messageInfo_Config_ClientIP.Size(m)
}
func (m *Config_ClientIP) XXX_DiscardUnknown() {
xxx_messageInfo_Config_ClientIP.DiscardUnknown(m)
}
var xxx_messageInfo_Config_ClientIP proto.InternalMessageInfo
func (m *Config_ClientIP) GetV4() []byte {
if m != nil {
return m.V4
}
return nil
}
func (m *Config_ClientIP) GetV6() []byte {
if m != nil {
return m.V6
}
return nil
}
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.app.dns.Config")
proto.RegisterMapType((map[string]*net.IPOrDomain)(nil), "v2ray.core.app.dns.Config.HostsEntry")
proto.RegisterType((*Config_ClientIP)(nil), "v2ray.core.app.dns.Config.ClientIP")
}
func init() {
proto.RegisterFile("v2ray.com/core/app/dns/config.proto", fileDescriptor_config_862435acfeec6b70)
proto.RegisterFile("v2ray.com/core/app/dns/config.proto", fileDescriptor_config_209d2630698ab6f5)
}
var fileDescriptor_config_862435acfeec6b70 = []byte{
// 286 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0x41, 0x4b, 0x33, 0x31,
0x10, 0x86, 0xc9, 0x96, 0x16, 0xbe, 0xf4, 0xf2, 0x91, 0x83, 0x2c, 0xbd, 0x58, 0x15, 0xb1, 0x20,
0x4c, 0x60, 0x15, 0x14, 0x3d, 0xd5, 0xb6, 0xa0, 0x17, 0x2d, 0x2b, 0x78, 0xd0, 0x53, 0xdc, 0x44,
0x59, 0x34, 0x33, 0x21, 0x89, 0x0b, 0xfb, 0x97, 0xfc, 0x5f, 0xfe, 0x0f, 0xe9, 0x06, 0xb1, 0xa8,
0xbd, 0x85, 0xe4, 0x79, 0xf2, 0xbe, 0x33, 0x7c, 0xaf, 0x29, 0xbc, 0x6a, 0xa1, 0x22, 0x2b, 0x2b,
0xf2, 0x46, 0x2a, 0xe7, 0xa4, 0xc6, 0x20, 0x2b, 0xc2, 0xa7, 0xfa, 0x19, 0x9c, 0xa7, 0x48, 0x42,
0x7c, 0x41, 0xde, 0x80, 0x72, 0x0e, 0x34, 0x86, 0xd1, 0xc1, 0x0f, 0xb1, 0x22, 0x6b, 0x09, 0x25,
0x9a, 0x28, 0x95, 0xd6, 0xde, 0x84, 0x90, 0xe4, 0xd1, 0xe1, 0x66, 0x50, 0x9b, 0x10, 0x6b, 0x54,
0xb1, 0x26, 0x4c, 0xf0, 0xee, 0x07, 0xe3, 0x83, 0x59, 0x17, 0x2d, 0xa6, 0x7c, 0x78, 0xad, 0xac,
0xb9, 0x35, 0xbe, 0x31, 0x3e, 0xe4, 0x6c, 0xdc, 0x9b, 0x0c, 0x8b, 0x6d, 0x58, 0xab, 0x92, 0x7e,
0x02, 0x34, 0x11, 0x16, 0xa8, 0x1d, 0xd5, 0x18, 0xcb, 0x75, 0x47, 0x9c, 0xf3, 0xfe, 0x25, 0x85,
0x18, 0xf2, 0xac, 0x93, 0xf7, 0xe1, 0xf7, 0x1c, 0x90, 0xd2, 0xa0, 0xe3, 0x16, 0x18, 0x7d, 0x5b,
0x26, 0x67, 0xf4, 0xc0, 0xf9, 0xf7, 0xa5, 0xf8, 0xcf, 0x7b, 0x2f, 0xa6, 0xcd, 0xd9, 0x98, 0x4d,
0xfe, 0x95, 0xab, 0xa3, 0x38, 0xe1, 0xfd, 0x46, 0xbd, 0xbe, 0x99, 0x3c, 0x1b, 0xb3, 0xc9, 0xb0,
0xd8, 0xd9, 0xd0, 0xec, 0x6a, 0x79, 0xe3, 0xe7, 0x64, 0x55, 0x8d, 0x65, 0xe2, 0xcf, 0xb2, 0x53,
0x76, 0x71, 0xcc, 0xb7, 0x2a, 0xb2, 0x7f, 0xf4, 0x59, 0xb2, 0xfb, 0x9e, 0xc6, 0xf0, 0x9e, 0x89,
0xbb, 0xa2, 0x54, 0x2d, 0xcc, 0x56, 0x6f, 0x53, 0xe7, 0x60, 0x8e, 0xe1, 0x71, 0xd0, 0x2d, 0xe9,
0xe8, 0x33, 0x00, 0x00, 0xff, 0xff, 0x2d, 0xe1, 0x96, 0x19, 0xb5, 0x01, 0x00, 0x00,
var fileDescriptor_config_209d2630698ab6f5 = []byte{
// 338 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x51, 0x4b, 0xf3, 0x30,
0x14, 0x86, 0x69, 0xcb, 0xc6, 0x96, 0x7d, 0x7c, 0x48, 0x2e, 0xa4, 0xf4, 0xc6, 0xe9, 0x10, 0x87,
0x42, 0x0a, 0x75, 0x4c, 0xd1, 0x1b, 0xe7, 0x36, 0x70, 0x37, 0x3a, 0x2a, 0x78, 0xa1, 0x17, 0x12,
0x9b, 0x28, 0xc1, 0xf5, 0x24, 0x24, 0xb1, 0xd0, 0xbf, 0xe4, 0xdf, 0xf1, 0x0f, 0xc9, 0x12, 0x86,
0x43, 0x9d, 0x77, 0x3d, 0xf4, 0x7d, 0x9e, 0xf7, 0x1c, 0x82, 0x7a, 0x55, 0xa6, 0x69, 0x4d, 0x0a,
0x59, 0xa6, 0x85, 0xd4, 0x3c, 0xa5, 0x4a, 0xa5, 0x0c, 0x4c, 0x5a, 0x48, 0x78, 0x16, 0x2f, 0x44,
0x69, 0x69, 0x25, 0xc6, 0xab, 0x90, 0xe6, 0x84, 0x2a, 0x45, 0x18, 0x98, 0xe4, 0xe0, 0x1b, 0x58,
0xc8, 0xb2, 0x94, 0x90, 0x02, 0xb7, 0x29, 0x65, 0x4c, 0x73, 0x63, 0x3c, 0x9c, 0x1c, 0x6d, 0x0e,
0x32, 0x6e, 0xac, 0x00, 0x6a, 0x85, 0x04, 0x1f, 0xde, 0xfb, 0x08, 0x51, 0x73, 0xec, 0xaa, 0xf1,
0x08, 0x75, 0xae, 0x69, 0xc9, 0x6f, 0xb9, 0xae, 0xb8, 0x36, 0x71, 0xd0, 0x8d, 0xfa, 0x9d, 0x6c,
0x87, 0xac, 0xad, 0xe2, 0x4d, 0x04, 0xb8, 0x25, 0x53, 0x60, 0x4a, 0x0a, 0xb0, 0xf9, 0x3a, 0x83,
0xcf, 0x51, 0xe3, 0x4a, 0x1a, 0x6b, 0xe2, 0xd0, 0xc1, 0xfb, 0xe4, 0xe7, 0x1d, 0xc4, 0xb7, 0x11,
0x97, 0x9b, 0x82, 0xd5, 0x75, 0xee, 0x19, 0x7c, 0x81, 0xda, 0xc5, 0x42, 0x70, 0xb0, 0x8f, 0x42,
0xc5, 0x51, 0x37, 0xe8, 0x77, 0xb2, 0xde, 0x1f, 0x82, 0xb1, 0xcb, 0xce, 0xe6, 0x79, 0xcb, 0x53,
0x33, 0x95, 0x3c, 0x20, 0xf4, 0xa5, 0xc5, 0x5b, 0x28, 0x7a, 0xe5, 0x75, 0x1c, 0x74, 0x83, 0x7e,
0x3b, 0x5f, 0x7e, 0xe2, 0x13, 0xd4, 0xa8, 0xe8, 0xe2, 0x8d, 0xc7, 0xa1, 0xb3, 0xef, 0x6e, 0xb8,
0x6d, 0x36, 0xbf, 0xd1, 0x13, 0x59, 0x52, 0x01, 0xb9, 0xcf, 0x9f, 0x85, 0xa7, 0x41, 0x72, 0x88,
0x5a, 0xab, 0x4a, 0xfc, 0x1f, 0x85, 0xd5, 0xc0, 0x99, 0xff, 0xe5, 0x61, 0x35, 0x70, 0xf3, 0xd0,
0x59, 0x97, 0xf3, 0xf0, 0x72, 0x80, 0xb6, 0x0b, 0x59, 0xfe, 0xb2, 0xfc, 0x3c, 0xb8, 0x8f, 0x18,
0x98, 0xf7, 0x10, 0xdf, 0x65, 0x39, 0xad, 0xc9, 0x78, 0xf9, 0x6f, 0xa4, 0x14, 0x99, 0x80, 0x79,
0x6a, 0xba, 0x27, 0x39, 0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x55, 0xb0, 0x77, 0x62, 0x23, 0x02,
0x00, 0x00,
}

View File

@ -16,4 +16,14 @@ message Config {
// Static hosts. Domain to IP.
map<string, v2ray.core.common.net.IPOrDomain> Hosts = 2;
message ClientIP {
// IPv4 address of the client. Must be 4 bytes.
bytes v4 = 1;
// IPv6 address of the client. Must be 4 bytes.
bytes v6 = 2;
}
// Client IP for EDNS client subnet.
ClientIP client_ip = 3;
}

View File

@ -14,8 +14,9 @@ import (
type Server struct {
sync.Mutex
hosts map[string]net.IP
servers []NameServer
hosts map[string]net.IP
servers []NameServer
clientIP *Config_ClientIP
}
func New(ctx context.Context, config *Config) (*Server, error) {
@ -23,6 +24,10 @@ func New(ctx context.Context, config *Config) (*Server, error) {
servers: make([]NameServer, len(config.NameServers)),
hosts: config.GetInternalHosts(),
}
if config.ClientIp != nil {
server.clientIP = config.ClientIp
}
v := core.MustFromContext(ctx)
if err := v.RegisterFeature((*core.DNSClient)(nil), server); err != nil {
return nil, newError("unable to register DNSClient.").Base(err)
@ -38,7 +43,7 @@ func New(ctx context.Context, config *Config) (*Server, error) {
dest.Network = net.Network_UDP
}
if dest.Network == net.Network_UDP {
server.servers[idx] = NewClassicNameServer(dest, v.Dispatcher())
server.servers[idx] = NewClassicNameServer(dest, v.Dispatcher(), server.clientIP)
}
}
}

View File

@ -37,13 +37,15 @@ type ClassicNameServer struct {
udpServer *udp.Dispatcher
cleanup *task.Periodic
reqID uint32
clientIP *Config_ClientIP
}
func NewClassicNameServer(address net.Destination, dispatcher core.Dispatcher) *ClassicNameServer {
func NewClassicNameServer(address net.Destination, dispatcher core.Dispatcher, clientIP *Config_ClientIP) *ClassicNameServer {
s := &ClassicNameServer{
address: address,
ips: make(map[string][]IPRecord),
udpServer: udp.NewDispatcher(dispatcher),
clientIP: clientIP,
}
s.cleanup = &task.Periodic{
Interval: time.Minute,
@ -134,27 +136,66 @@ func (s *ClassicNameServer) updateIP(domain string, ips []IPRecord) {
s.updated.Signal()
}
func (s *ClassicNameServer) getMsgOptions() *dns.OPT {
if s.clientIP == nil {
return nil
}
o := new(dns.OPT)
o.Hdr.Name = "."
o.Hdr.Rrtype = dns.TypeOPT
if len(s.clientIP.V4) == 4 {
e := new(dns.EDNS0_SUBNET)
e.Code = dns.EDNS0SUBNET
e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
e.SourceNetmask = 24 // 32 for IPV4, 128 for IPv6
e.SourceScope = 0
e.Address = net.IP(s.clientIP.V4)
o.Option = append(o.Option, e)
}
if len(s.clientIP.V6) == 16 {
e := new(dns.EDNS0_SUBNET)
e.Code = dns.EDNS0SUBNET
e.Family = 2 // 1 for IPv4 source address, 2 for IPv6
e.SourceNetmask = 24 // 32 for IPV4, 128 for IPv6
e.SourceScope = 0
e.Address = net.IP(s.clientIP.V6)
o.Option = append(o.Option, e)
}
return o
}
func (s *ClassicNameServer) buildMsgs(domain string) []*dns.Msg {
allowMulti := multiQuestionDNS[s.address.Address]
qA := dns.Question{
Name: domain,
Qtype: dns.TypeA,
Qclass: dns.ClassINET,
}
qAAAA := dns.Question{
Name: domain,
Qtype: dns.TypeAAAA,
Qclass: dns.ClassINET,
}
var msgs []*dns.Msg
{
msg := new(dns.Msg)
msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
msg.RecursionDesired = true
msg.Question = []dns.Question{
{
Name: domain,
Qtype: dns.TypeA,
Qclass: dns.ClassINET,
}}
msg.Question = []dns.Question{qA}
if allowMulti {
msg.Question = append(msg.Question, dns.Question{
Name: domain,
Qtype: dns.TypeAAAA,
Qclass: dns.ClassINET,
})
msg.Question = append(msg.Question, qAAAA)
}
if opt := s.getMsgOptions(); opt != nil {
msg.Extra = append(msg.Extra, opt)
}
msgs = append(msgs, msg)
}
@ -163,12 +204,9 @@ func (s *ClassicNameServer) buildMsgs(domain string) []*dns.Msg {
msg := new(dns.Msg)
msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
msg.RecursionDesired = true
msg.Question = []dns.Question{
{
Name: domain,
Qtype: dns.TypeAAAA,
Qclass: dns.ClassINET,
},
msg.Question = []dns.Question{qAAAA}
if opt := s.getMsgOptions(); opt != nil {
msg.Extra = append(msg.Extra, opt)
}
msgs = append(msgs, msg)
}