support client subnet

pull/1173/head
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,9 +19,11 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config struct { type Config struct {
// Nameservers used by this DNS. Only traditional UDP servers are support at the moment. // 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. // 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. // 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"` 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_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -31,7 +33,7 @@ func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) } func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { 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 { func (m *Config) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Config.Unmarshal(m, b) return xxx_messageInfo_Config.Unmarshal(m, b)
@ -65,33 +67,93 @@ func (m *Config) GetHosts() map[string]*net.IPOrDomain {
return nil 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() { func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.app.dns.Config") proto.RegisterType((*Config)(nil), "v2ray.core.app.dns.Config")
proto.RegisterMapType((map[string]*net.IPOrDomain)(nil), "v2ray.core.app.dns.Config.HostsEntry") 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() { 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{ var fileDescriptor_config_209d2630698ab6f5 = []byte{
// 286 bytes of a gzipped FileDescriptorProto // 338 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0x41, 0x4b, 0x33, 0x31, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x51, 0x4b, 0xf3, 0x30,
0x10, 0x86, 0xc9, 0x96, 0x16, 0xbe, 0xf4, 0xf2, 0x91, 0x83, 0x2c, 0xbd, 0x58, 0x15, 0xb1, 0x20, 0x14, 0x86, 0x69, 0xcb, 0xc6, 0x96, 0x7d, 0x7c, 0x48, 0x2e, 0xa4, 0xf4, 0xc6, 0xe9, 0x10, 0x87,
0x4c, 0x60, 0x15, 0x14, 0x3d, 0xd5, 0xb6, 0xa0, 0x17, 0x2d, 0x2b, 0x78, 0xd0, 0x53, 0xdc, 0x44, 0x42, 0x0a, 0x75, 0x4c, 0xd1, 0x1b, 0xe7, 0x36, 0x70, 0x37, 0x3a, 0x2a, 0x78, 0xa1, 0x17, 0x12,
0x59, 0x34, 0x33, 0x21, 0x89, 0x0b, 0xfb, 0x97, 0xfc, 0x5f, 0xfe, 0x0f, 0xe9, 0x06, 0xb1, 0xa8, 0x9b, 0x28, 0xc1, 0xf5, 0x24, 0x24, 0xb1, 0xd0, 0xbf, 0xe4, 0xdf, 0xf1, 0x0f, 0xc9, 0x12, 0x86,
0xbd, 0x85, 0xe4, 0x79, 0xf2, 0xbe, 0x33, 0x7c, 0xaf, 0x29, 0xbc, 0x6a, 0xa1, 0x22, 0x2b, 0x2b, 0x43, 0x9d, 0x77, 0x3d, 0xf4, 0x7d, 0x9e, 0xf7, 0x1c, 0x82, 0x7a, 0x55, 0xa6, 0x69, 0x4d, 0x0a,
0xf2, 0x46, 0x2a, 0xe7, 0xa4, 0xc6, 0x20, 0x2b, 0xc2, 0xa7, 0xfa, 0x19, 0x9c, 0xa7, 0x48, 0x42, 0x59, 0xa6, 0x85, 0xd4, 0x3c, 0xa5, 0x4a, 0xa5, 0x0c, 0x4c, 0x5a, 0x48, 0x78, 0x16, 0x2f, 0x44,
0x7c, 0x41, 0xde, 0x80, 0x72, 0x0e, 0x34, 0x86, 0xd1, 0xc1, 0x0f, 0xb1, 0x22, 0x6b, 0x09, 0x25, 0x69, 0x69, 0x25, 0xc6, 0xab, 0x90, 0xe6, 0x84, 0x2a, 0x45, 0x18, 0x98, 0xe4, 0xe0, 0x1b, 0x58,
0x9a, 0x28, 0x95, 0xd6, 0xde, 0x84, 0x90, 0xe4, 0xd1, 0xe1, 0x66, 0x50, 0x9b, 0x10, 0x6b, 0x54, 0xc8, 0xb2, 0x94, 0x90, 0x02, 0xb7, 0x29, 0x65, 0x4c, 0x73, 0x63, 0x3c, 0x9c, 0x1c, 0x6d, 0x0e,
0xb1, 0x26, 0x4c, 0xf0, 0xee, 0x07, 0xe3, 0x83, 0x59, 0x17, 0x2d, 0xa6, 0x7c, 0x78, 0xad, 0xac, 0x32, 0x6e, 0xac, 0x00, 0x6a, 0x85, 0x04, 0x1f, 0xde, 0xfb, 0x08, 0x51, 0x73, 0xec, 0xaa, 0xf1,
0xb9, 0x35, 0xbe, 0x31, 0x3e, 0xe4, 0x6c, 0xdc, 0x9b, 0x0c, 0x8b, 0x6d, 0x58, 0xab, 0x92, 0x7e, 0x08, 0x75, 0xae, 0x69, 0xc9, 0x6f, 0xb9, 0xae, 0xb8, 0x36, 0x71, 0xd0, 0x8d, 0xfa, 0x9d, 0x6c,
0x02, 0x34, 0x11, 0x16, 0xa8, 0x1d, 0xd5, 0x18, 0xcb, 0x75, 0x47, 0x9c, 0xf3, 0xfe, 0x25, 0x85, 0x87, 0xac, 0xad, 0xe2, 0x4d, 0x04, 0xb8, 0x25, 0x53, 0x60, 0x4a, 0x0a, 0xb0, 0xf9, 0x3a, 0x83,
0x18, 0xf2, 0xac, 0x93, 0xf7, 0xe1, 0xf7, 0x1c, 0x90, 0xd2, 0xa0, 0xe3, 0x16, 0x18, 0x7d, 0x5b, 0xcf, 0x51, 0xe3, 0x4a, 0x1a, 0x6b, 0xe2, 0xd0, 0xc1, 0xfb, 0xe4, 0xe7, 0x1d, 0xc4, 0xb7, 0x11,
0x26, 0x67, 0xf4, 0xc0, 0xf9, 0xf7, 0xa5, 0xf8, 0xcf, 0x7b, 0x2f, 0xa6, 0xcd, 0xd9, 0x98, 0x4d, 0x97, 0x9b, 0x82, 0xd5, 0x75, 0xee, 0x19, 0x7c, 0x81, 0xda, 0xc5, 0x42, 0x70, 0xb0, 0x8f, 0x42,
0xfe, 0x95, 0xab, 0xa3, 0x38, 0xe1, 0xfd, 0x46, 0xbd, 0xbe, 0x99, 0x3c, 0x1b, 0xb3, 0xc9, 0xb0, 0xc5, 0x51, 0x37, 0xe8, 0x77, 0xb2, 0xde, 0x1f, 0x82, 0xb1, 0xcb, 0xce, 0xe6, 0x79, 0xcb, 0x53,
0xd8, 0xd9, 0xd0, 0xec, 0x6a, 0x79, 0xe3, 0xe7, 0x64, 0x55, 0x8d, 0x65, 0xe2, 0xcf, 0xb2, 0x53, 0x33, 0x95, 0x3c, 0x20, 0xf4, 0xa5, 0xc5, 0x5b, 0x28, 0x7a, 0xe5, 0x75, 0x1c, 0x74, 0x83, 0x7e,
0x76, 0x71, 0xcc, 0xb7, 0x2a, 0xb2, 0x7f, 0xf4, 0x59, 0xb2, 0xfb, 0x9e, 0xc6, 0xf0, 0x9e, 0x89, 0x3b, 0x5f, 0x7e, 0xe2, 0x13, 0xd4, 0xa8, 0xe8, 0xe2, 0x8d, 0xc7, 0xa1, 0xb3, 0xef, 0x6e, 0xb8,
0xbb, 0xa2, 0x54, 0x2d, 0xcc, 0x56, 0x6f, 0x53, 0xe7, 0x60, 0x8e, 0xe1, 0x71, 0xd0, 0x2d, 0xe9, 0x6d, 0x36, 0xbf, 0xd1, 0x13, 0x59, 0x52, 0x01, 0xb9, 0xcf, 0x9f, 0x85, 0xa7, 0x41, 0x72, 0x88,
0xe8, 0x33, 0x00, 0x00, 0xff, 0xff, 0x2d, 0xe1, 0x96, 0x19, 0xb5, 0x01, 0x00, 0x00, 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. // Static hosts. Domain to IP.
map<string, v2ray.core.common.net.IPOrDomain> Hosts = 2; 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

@ -16,6 +16,7 @@ type Server struct {
sync.Mutex sync.Mutex
hosts map[string]net.IP hosts map[string]net.IP
servers []NameServer servers []NameServer
clientIP *Config_ClientIP
} }
func New(ctx context.Context, config *Config) (*Server, error) { 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)), servers: make([]NameServer, len(config.NameServers)),
hosts: config.GetInternalHosts(), hosts: config.GetInternalHosts(),
} }
if config.ClientIp != nil {
server.clientIP = config.ClientIp
}
v := core.MustFromContext(ctx) v := core.MustFromContext(ctx)
if err := v.RegisterFeature((*core.DNSClient)(nil), server); err != nil { if err := v.RegisterFeature((*core.DNSClient)(nil), server); err != nil {
return nil, newError("unable to register DNSClient.").Base(err) 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 dest.Network = net.Network_UDP
} }
if 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 udpServer *udp.Dispatcher
cleanup *task.Periodic cleanup *task.Periodic
reqID uint32 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{ s := &ClassicNameServer{
address: address, address: address,
ips: make(map[string][]IPRecord), ips: make(map[string][]IPRecord),
udpServer: udp.NewDispatcher(dispatcher), udpServer: udp.NewDispatcher(dispatcher),
clientIP: clientIP,
} }
s.cleanup = &task.Periodic{ s.cleanup = &task.Periodic{
Interval: time.Minute, Interval: time.Minute,
@ -134,27 +136,66 @@ func (s *ClassicNameServer) updateIP(domain string, ips []IPRecord) {
s.updated.Signal() 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 { func (s *ClassicNameServer) buildMsgs(domain string) []*dns.Msg {
allowMulti := multiQuestionDNS[s.address.Address] 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 var msgs []*dns.Msg
{ {
msg := new(dns.Msg) msg := new(dns.Msg)
msg.Id = uint16(atomic.AddUint32(&s.reqID, 1)) msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
msg.RecursionDesired = true msg.RecursionDesired = true
msg.Question = []dns.Question{ msg.Question = []dns.Question{qA}
{
Name: domain,
Qtype: dns.TypeA,
Qclass: dns.ClassINET,
}}
if allowMulti { if allowMulti {
msg.Question = append(msg.Question, dns.Question{ msg.Question = append(msg.Question, qAAAA)
Name: domain, }
Qtype: dns.TypeAAAA, if opt := s.getMsgOptions(); opt != nil {
Qclass: dns.ClassINET, msg.Extra = append(msg.Extra, opt)
})
} }
msgs = append(msgs, msg) msgs = append(msgs, msg)
} }
@ -163,12 +204,9 @@ func (s *ClassicNameServer) buildMsgs(domain string) []*dns.Msg {
msg := new(dns.Msg) msg := new(dns.Msg)
msg.Id = uint16(atomic.AddUint32(&s.reqID, 1)) msg.Id = uint16(atomic.AddUint32(&s.reqID, 1))
msg.RecursionDesired = true msg.RecursionDesired = true
msg.Question = []dns.Question{ msg.Question = []dns.Question{qAAAA}
{ if opt := s.getMsgOptions(); opt != nil {
Name: domain, msg.Extra = append(msg.Extra, opt)
Qtype: dns.TypeAAAA,
Qclass: dns.ClassINET,
},
} }
msgs = append(msgs, msg) msgs = append(msgs, msg)
} }