2017-08-13 23:51:08 +08:00
// https://tools.ietf.org/html/rfc1035
package main
import (
"encoding/binary"
"io/ioutil"
"net"
2017-08-16 13:20:12 +08:00
"strings"
2017-08-13 23:51:08 +08:00
)
2017-08-21 23:57:49 +08:00
// DNSUDPHeaderLen is the length of UDP dns msg header
const DNSUDPHeaderLen = 12
2017-08-13 23:51:08 +08:00
2017-08-21 23:57:49 +08:00
// DNSTCPHeaderLen is the length of TCP dns msg header
const DNSTCPHeaderLen = 2 + DNSUDPHeaderLen
2017-08-13 23:51:08 +08:00
2017-08-21 23:57:49 +08:00
// DNSUDPMaxLen is the max size of udp dns request.
2017-08-13 23:51:08 +08:00
// https://tools.ietf.org/html/rfc1035#section-4.2.1
// Messages carried by UDP are restricted to 512 bytes (not counting the IP
// or UDP headers). Longer messages are truncated and the TC bit is set in
// the header.
// TODO: If the request length > 512 then the client will send TCP packets instead,
// so we should also serve tcp requests.
2017-08-21 23:57:49 +08:00
const DNSUDPMaxLen = 512
// DNSQueryTypeA ipv4
const DNSQueryTypeA = 1
// DNSQueryTypeAAAA ipv6
const DNSQueryTypeAAAA = 28
type dnsQuery struct {
DomainName string
QueryType uint16
QueryClass uint16
Offset int
}
type dnsAnswer struct {
2017-08-23 16:35:39 +08:00
// DomainName string
2017-08-21 23:57:49 +08:00
QueryType uint16
QueryClass uint16
TTL uint32
DataLength uint16
Data [ ] byte
IP string
}
2017-08-13 23:51:08 +08:00
2017-08-23 16:35:39 +08:00
// DNSAnswerHandler .
type DNSAnswerHandler func ( domain , ip string ) error
2017-08-20 21:44:18 +08:00
// DNS .
2017-08-16 13:20:12 +08:00
type DNS struct {
2017-08-23 16:35:39 +08:00
* Forwarder // as proxy client
sDialer Dialer // dialer for server
2017-08-16 13:20:12 +08:00
dnsServer string
2017-08-23 16:35:39 +08:00
dnsServerMap map [ string ] string
answerHandlers [ ] DNSAnswerHandler
2017-08-13 23:51:08 +08:00
}
2017-08-20 21:44:18 +08:00
// NewDNS returns a dns forwarder. client -> dns.udp -> glider -> forwarder -> remote dns addr
2017-08-23 16:35:39 +08:00
func NewDNS ( addr , raddr string , sDialer Dialer ) ( * DNS , error ) {
2017-08-16 13:20:12 +08:00
s := & DNS {
2017-08-23 16:35:39 +08:00
Forwarder : NewForwarder ( addr , nil ) ,
sDialer : sDialer ,
2017-08-16 13:20:12 +08:00
dnsServer : raddr ,
dnsServerMap : make ( map [ string ] string ) ,
2017-08-13 23:51:08 +08:00
}
return s , nil
}
// ListenAndServe .
2017-08-16 13:20:12 +08:00
func ( s * DNS ) ListenAndServe ( ) {
2017-08-13 23:51:08 +08:00
l , err := net . ListenPacket ( "udp" , s . addr )
if err != nil {
logf ( "failed to listen on %s: %v" , s . addr , err )
return
}
defer l . Close ( )
logf ( "listening UDP on %s" , s . addr )
for {
2017-08-21 23:57:49 +08:00
data := make ( [ ] byte , DNSUDPMaxLen )
2017-08-13 23:51:08 +08:00
n , clientAddr , err := l . ReadFrom ( data )
if err != nil {
logf ( "DNS local read error: %v" , err )
continue
}
data = data [ : n ]
go func ( ) {
// TODO: check domain rules and get a proper upstream name server.
2017-08-21 23:57:49 +08:00
query := parseQuery ( data )
domain := query . DomainName
2017-08-13 23:51:08 +08:00
2017-08-16 13:20:12 +08:00
dnsServer := s . GetServer ( domain )
2017-08-23 16:35:39 +08:00
// TODO: check here; ADD dnsServer to rule ip lists
rc , err := s . sDialer . Dial ( "tcp" , dnsServer )
2017-08-13 23:51:08 +08:00
if err != nil {
2017-08-16 13:20:12 +08:00
logf ( "failed to connect to server %v: %v" , dnsServer , err )
2017-08-13 23:51:08 +08:00
return
}
defer rc . Close ( )
// 2 bytes length after tcp header, before dns message
length := make ( [ ] byte , 2 )
binary . BigEndian . PutUint16 ( length , uint16 ( len ( data ) ) )
rc . Write ( length )
rc . Write ( data )
resp , err := ioutil . ReadAll ( rc )
if err != nil {
logf ( "error in ioutil.ReadAll: %s\n" , err )
return
}
2017-08-21 23:57:49 +08:00
var ip string
2017-08-13 23:51:08 +08:00
// length is not needed in udp dns response. (2 bytes)
// SEE RFC1035, section 4.2.2 TCP: The message is prefixed with a two byte length field which gives the message length, excluding the two byte length field.
if len ( resp ) > 2 {
msg := resp [ 2 : ]
2017-08-21 23:57:49 +08:00
// TODO: Get IP from response, check and add to ipset
query := parseQuery ( msg )
if len ( msg ) > query . Offset {
answers := parseAnswers ( msg [ query . Offset : ] )
for _ , answer := range answers {
if answer . IP != "" {
ip += answer . IP + ","
}
2017-08-23 16:35:39 +08:00
for _ , h := range s . answerHandlers {
h ( query . DomainName , answer . IP )
}
2017-08-21 23:57:49 +08:00
}
}
2017-08-13 23:51:08 +08:00
_ , err = l . WriteTo ( msg , clientAddr )
if err != nil {
logf ( "error in local write: %s\n" , err )
}
}
2017-08-23 16:35:39 +08:00
logf ( "proxy-dns %s <-> %s, %s: %s" , clientAddr . String ( ) , dnsServer , domain , ip )
2017-08-21 23:57:49 +08:00
2017-08-13 23:51:08 +08:00
} ( )
}
}
2017-08-16 13:20:12 +08:00
// SetServer .
func ( s * DNS ) SetServer ( domain , server string ) {
s . dnsServerMap [ domain ] = server
}
// GetServer .
func ( s * DNS ) GetServer ( domain string ) string {
domainParts := strings . Split ( domain , "." )
length := len ( domainParts )
for i := length - 2 ; i >= 0 ; i -- {
domain := strings . Join ( domainParts [ i : length ] , "." )
if server , ok := s . dnsServerMap [ domain ] ; ok {
return server
}
}
return s . dnsServer
}
2017-08-23 16:35:39 +08:00
// AddAnswerHandler .
func ( s * DNS ) AddAnswerHandler ( h DNSAnswerHandler ) {
s . answerHandlers = append ( s . answerHandlers , h )
}
2017-08-21 23:57:49 +08:00
func parseQuery ( p [ ] byte ) * dnsQuery {
q := & dnsQuery { }
2017-08-13 23:51:08 +08:00
2017-08-21 23:57:49 +08:00
var i int
var domain [ ] byte
for i = DNSUDPHeaderLen ; i < len ( p ) ; {
2017-08-13 23:51:08 +08:00
l := int ( p [ i ] )
if l == 0 {
2017-08-21 23:57:49 +08:00
i ++
2017-08-13 23:51:08 +08:00
break
}
2017-08-21 23:57:49 +08:00
domain = append ( domain , p [ i + 1 : i + l + 1 ] ... )
domain = append ( domain , '.' )
2017-08-13 23:51:08 +08:00
i = i + l + 1
}
2017-08-21 23:57:49 +08:00
q . DomainName = string ( domain [ : len ( domain ) - 1 ] )
q . QueryType = binary . BigEndian . Uint16 ( p [ i : ] )
q . QueryClass = binary . BigEndian . Uint16 ( p [ i + 2 : ] )
q . Offset = i + 4
return q
}
func parseAnswers ( p [ ] byte ) [ ] * dnsAnswer {
var answers [ ] * dnsAnswer
for i := 0 ; i < len ( p ) ; {
l := int ( p [ i ] )
if l == 0 {
i ++
break
}
answer := & dnsAnswer { }
answer . QueryType = binary . BigEndian . Uint16 ( p [ i + 2 : ] )
answer . QueryClass = binary . BigEndian . Uint16 ( p [ i + 4 : ] )
answer . TTL = binary . BigEndian . Uint32 ( p [ i + 6 : ] )
answer . DataLength = binary . BigEndian . Uint16 ( p [ i + 10 : ] )
answer . Data = p [ i + 12 : i + 12 + int ( answer . DataLength ) ]
if answer . QueryType == DNSQueryTypeA {
answer . IP = net . IP ( answer . Data [ : net . IPv4len ] ) . String ( )
} else if answer . QueryType == DNSQueryTypeAAAA {
answer . IP = net . IP ( answer . Data [ : net . IPv6len ] ) . String ( )
}
answers = append ( answers , answer )
i = i + 12 + int ( answer . DataLength )
}
return answers
2017-08-13 23:51:08 +08:00
}