2017-12-19 17:55:09 -05:00
package dns
2016-05-16 02:09:28 -04:00
import (
2017-01-26 14:46:44 -05:00
"context"
2016-05-16 02:09:28 -04:00
"sync"
"time"
2017-01-26 14:46:44 -05:00
"github.com/miekg/dns"
2018-01-10 06:22:37 -05:00
"v2ray.com/core"
2018-04-03 18:29:30 -04:00
"v2ray.com/core/common"
2016-12-09 05:35:27 -05:00
"v2ray.com/core/common/buf"
2016-08-20 14:55:45 -04:00
"v2ray.com/core/common/dice"
2017-08-29 06:56:57 -04:00
"v2ray.com/core/common/net"
2018-02-22 11:29:21 -05:00
"v2ray.com/core/common/signal"
2016-08-20 14:55:45 -04:00
"v2ray.com/core/transport/internet/udp"
2016-05-16 02:09:28 -04:00
)
2016-06-01 16:09:24 -04:00
var (
2017-11-19 15:43:20 -05:00
multiQuestionDNS = map [ net . Address ] bool {
2017-11-19 14:42:34 -05:00
net . IPAddress ( [ ] byte { 8 , 8 , 8 , 8 } ) : true ,
net . IPAddress ( [ ] byte { 8 , 8 , 4 , 4 } ) : true ,
net . IPAddress ( [ ] byte { 9 , 9 , 9 , 9 } ) : true ,
}
2016-06-01 16:09:24 -04:00
)
2016-05-16 02:09:28 -04:00
type ARecord struct {
IPs [ ] net . IP
Expire time . Time
}
type NameServer interface {
QueryA ( domain string ) <- chan * ARecord
}
type PendingRequest struct {
expire time . Time
response chan <- * ARecord
}
type UDPNameServer struct {
sync . Mutex
2018-02-22 11:29:21 -05:00
address net . Destination
requests map [ uint16 ] * PendingRequest
udpServer * udp . Dispatcher
cleanup * signal . PeriodicTask
2016-05-16 02:09:28 -04:00
}
2018-01-10 06:22:37 -05:00
func NewUDPNameServer ( address net . Destination , dispatcher core . Dispatcher ) * UDPNameServer {
2016-05-16 02:09:28 -04:00
s := & UDPNameServer {
2016-11-13 08:33:00 -05:00
address : address ,
requests : make ( map [ uint16 ] * PendingRequest ) ,
2017-01-27 08:45:16 -05:00
udpServer : udp . NewDispatcher ( dispatcher ) ,
2016-05-16 02:09:28 -04:00
}
2018-02-22 11:29:21 -05:00
s . cleanup = & signal . PeriodicTask {
Interval : time . Minute ,
Execute : s . Cleanup ,
}
2018-04-03 18:29:30 -04:00
common . Must ( s . cleanup . Start ( ) )
2016-05-16 02:09:28 -04:00
return s
}
2018-02-22 11:29:21 -05:00
func ( s * UDPNameServer ) Cleanup ( ) error {
2016-05-16 20:30:00 -04:00
now := time . Now ( )
2017-11-19 15:43:20 -05:00
s . Lock ( )
for id , r := range s . requests {
2016-05-16 20:30:00 -04:00
if r . expire . Before ( now ) {
close ( r . response )
2018-02-22 11:29:21 -05:00
delete ( s . requests , id )
2016-05-16 02:09:28 -04:00
}
}
2017-11-19 15:43:20 -05:00
s . Unlock ( )
2018-02-22 11:29:21 -05:00
return nil
2016-05-16 02:09:28 -04:00
}
2017-11-19 15:43:20 -05:00
func ( s * UDPNameServer ) AssignUnusedID ( response chan <- * ARecord ) uint16 {
2016-05-16 02:09:28 -04:00
var id uint16
2017-11-19 15:43:20 -05:00
s . Lock ( )
2016-05-16 20:30:00 -04:00
2016-05-16 02:09:28 -04:00
for {
2017-04-27 05:54:15 -04:00
id = dice . RollUint16 ( )
2017-11-19 15:43:20 -05:00
if _ , found := s . requests [ id ] ; found {
2018-02-22 11:29:21 -05:00
time . Sleep ( time . Millisecond * 500 )
2016-05-16 02:09:28 -04:00
continue
}
2017-12-19 15:28:12 -05:00
newError ( "add pending request id " , id ) . AtDebug ( ) . WriteToLog ( )
2017-11-19 15:43:20 -05:00
s . requests [ id ] = & PendingRequest {
2016-06-01 16:09:24 -04:00
expire : time . Now ( ) . Add ( time . Second * 8 ) ,
2016-05-16 02:09:28 -04:00
response : response ,
}
break
}
2017-11-19 15:43:20 -05:00
s . Unlock ( )
2016-05-16 02:09:28 -04:00
return id
}
2017-11-19 15:43:20 -05:00
func ( s * UDPNameServer ) HandleResponse ( payload * buf . Buffer ) {
2016-05-16 02:09:28 -04:00
msg := new ( dns . Msg )
2016-12-05 09:19:14 -05:00
err := msg . Unpack ( payload . Bytes ( ) )
2017-11-18 14:00:09 -05:00
if err == dns . ErrTruncated {
2017-12-19 15:28:12 -05:00
newError ( "truncated message received. DNS server should still work. If you see anything abnormal, please submit an issue to v2ray-core." ) . AtWarning ( ) . WriteToLog ( )
2017-11-18 14:00:09 -05:00
} else if err != nil {
2017-12-19 15:28:12 -05:00
newError ( "failed to parse DNS response" ) . Base ( err ) . AtWarning ( ) . WriteToLog ( )
2016-05-16 02:09:28 -04:00
return
}
record := & ARecord {
IPs : make ( [ ] net . IP , 0 , 16 ) ,
}
id := msg . Id
2017-11-14 18:36:14 -05:00
ttl := uint32 ( 3600 ) // an hour
2017-12-19 15:28:12 -05:00
newError ( "handling response for id " , id , " content: " , msg ) . AtDebug ( ) . WriteToLog ( )
2016-05-16 02:09:28 -04:00
2017-11-19 15:43:20 -05:00
s . Lock ( )
request , found := s . requests [ id ]
2016-05-16 02:09:28 -04:00
if ! found {
2017-11-19 15:43:20 -05:00
s . Unlock ( )
2016-05-16 02:09:28 -04:00
return
}
2017-11-19 15:43:20 -05:00
delete ( s . requests , id )
s . Unlock ( )
2016-05-16 02:09:28 -04:00
for _ , rr := range msg . Answer {
2016-05-16 14:53:18 -04:00
switch rr := rr . ( type ) {
case * dns . A :
record . IPs = append ( record . IPs , rr . A )
if rr . Hdr . Ttl < ttl {
ttl = rr . Hdr . Ttl
}
case * dns . AAAA :
record . IPs = append ( record . IPs , rr . AAAA )
if rr . Hdr . Ttl < ttl {
ttl = rr . Hdr . Ttl
2016-05-16 02:09:28 -04:00
}
}
}
record . Expire = time . Now ( ) . Add ( time . Second * time . Duration ( ttl ) )
request . response <- record
close ( request . response )
}
2017-12-23 15:11:17 -05:00
func ( s * UDPNameServer ) buildAMsg ( domain string , id uint16 ) * dns . Msg {
2016-05-16 02:09:28 -04:00
msg := new ( dns . Msg )
2016-06-01 16:09:24 -04:00
msg . Id = id
2016-05-16 02:09:28 -04:00
msg . RecursionDesired = true
msg . Question = [ ] dns . Question {
2016-07-24 07:44:29 -04:00
{
2016-05-16 02:09:28 -04:00
Name : dns . Fqdn ( domain ) ,
Qtype : dns . TypeA ,
Qclass : dns . ClassINET ,
2017-11-19 14:42:34 -05:00
} }
2017-11-19 15:43:20 -05:00
if multiQuestionDNS [ s . address . Address ] {
2017-11-19 14:42:34 -05:00
msg . Question = append ( msg . Question , dns . Question {
2017-11-14 18:36:14 -05:00
Name : dns . Fqdn ( domain ) ,
Qtype : dns . TypeAAAA ,
Qclass : dns . ClassINET ,
2017-11-19 14:42:34 -05:00
} )
}
2016-05-16 02:09:28 -04:00
2017-12-23 15:11:17 -05:00
return msg
}
func msgToBuffer ( msg * dns . Msg ) ( * buf . Buffer , error ) {
2016-12-11 15:43:16 -05:00
buffer := buf . New ( )
2017-12-23 15:11:17 -05:00
if err := buffer . Reset ( func ( b [ ] byte ) ( int , error ) {
2016-12-11 15:43:16 -05:00
writtenBuffer , err := msg . PackBuffer ( b )
return len ( writtenBuffer ) , err
2017-12-23 15:11:17 -05:00
} ) ; err != nil {
return nil , err
}
return buffer , nil
2016-06-01 16:09:24 -04:00
}
2017-11-19 15:43:20 -05:00
func ( s * UDPNameServer ) QueryA ( domain string ) <- chan * ARecord {
2016-06-01 16:09:24 -04:00
response := make ( chan * ARecord , 1 )
2017-11-19 15:43:20 -05:00
id := s . AssignUnusedID ( response )
2016-06-01 16:09:24 -04:00
2017-12-23 15:11:17 -05:00
msg := s . buildAMsg ( domain , id )
b , err := msgToBuffer ( msg )
if err != nil {
newError ( "failed to build A query for domain " , domain ) . Base ( err ) . WriteToLog ( )
2018-03-10 03:34:38 -05:00
s . Lock ( )
delete ( s . requests , id )
s . Unlock ( )
2017-12-23 15:11:17 -05:00
close ( response )
return response
}
2017-11-14 18:36:14 -05:00
ctx , cancel := context . WithCancel ( context . Background ( ) )
2017-12-23 15:11:17 -05:00
s . udpServer . Dispatch ( ctx , s . address , b , s . HandleResponse )
2016-06-01 16:09:24 -04:00
go func ( ) {
for i := 0 ; i < 2 ; i ++ {
time . Sleep ( time . Second )
2017-11-19 15:43:20 -05:00
s . Lock ( )
_ , found := s . requests [ id ]
s . Unlock ( )
2017-11-14 18:36:14 -05:00
if ! found {
2016-06-01 16:09:24 -04:00
break
}
2017-12-23 15:11:17 -05:00
b , _ := msgToBuffer ( msg )
s . udpServer . Dispatch ( ctx , s . address , b , s . HandleResponse )
2016-06-01 16:09:24 -04:00
}
2017-01-26 14:46:44 -05:00
cancel ( )
2016-06-01 16:09:24 -04:00
} ( )
2016-05-16 02:09:28 -04:00
return response
}
2016-05-16 12:05:01 -04:00
type LocalNameServer struct {
}
2017-11-19 15:43:20 -05:00
func ( * LocalNameServer ) QueryA ( domain string ) <- chan * ARecord {
2016-05-16 14:53:18 -04:00
response := make ( chan * ARecord , 1 )
2016-05-16 12:05:01 -04:00
go func ( ) {
defer close ( response )
2018-01-10 07:32:48 -05:00
ips , err := net . LookupIP ( domain )
2016-05-16 12:05:01 -04:00
if err != nil {
2017-12-27 16:25:12 -05:00
newError ( "failed to lookup IPs for domain " , domain ) . Base ( err ) . AtWarning ( ) . WriteToLog ( )
2016-05-16 12:05:01 -04:00
return
}
response <- & ARecord {
IPs : ips ,
2017-11-14 18:36:14 -05:00
Expire : time . Now ( ) . Add ( time . Hour ) ,
2016-05-16 12:05:01 -04:00
}
} ( )
return response
}