dns: change parseAnswers function to return error

This commit is contained in:
nadoo 2018-01-11 14:44:24 +08:00
parent e91d4bcb6e
commit ff632f23a6

130
dns.go
View File

@ -44,11 +44,11 @@ const DNSQTypeAAAA = 28
// | Authority | RRs pointing toward an authority // | Authority | RRs pointing toward an authority
// +---------------------+ // +---------------------+
// | Additional | RRs holding additional information // | Additional | RRs holding additional information
type DNSMsg struct { // type DNSMsg struct {
DNSHeader // DNSHeader
Questions []*DNSQuestion // Questions []DNSQuestion
Answers []*DNSRR // Answers []DNSRR
} // }
// DNSHeader format // DNSHeader format
// https://tools.ietf.org/html/rfc1035#section-4.1.1 // https://tools.ietf.org/html/rfc1035#section-4.1.1
@ -70,9 +70,9 @@ type DNSMsg struct {
// | ARCOUNT | // | ARCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// //
type DNSHeader struct { // type DNSHeader struct {
ID uint16 // ID uint16
} // }
// DNSQuestion format // DNSQuestion format
// https://tools.ietf.org/html/rfc1035#section-4.1.2 // https://tools.ietf.org/html/rfc1035#section-4.1.2
@ -134,8 +134,8 @@ type DNSRR struct {
IP string IP string
} }
// DNSAnswerHandler . // DNSAnswerHandler function handles the dns TypeA or TypeAAAA answer
type DNSAnswerHandler func(domain, ip string) error type DNSAnswerHandler func(Domain, ip string) error
// DNS . // DNS .
type DNS struct { type DNS struct {
@ -191,22 +191,26 @@ func (s *DNS) ListenAndServeUDP() {
} }
reqLen := uint16(n) reqLen := uint16(n)
if reqLen <= DNSHeaderLen { // TODO: check here
if reqLen <= DNSHeaderLen+2 {
logf("proxy-dns not enough data") logf("proxy-dns not enough data")
continue continue
} }
reqMsg := b[:n] reqMsg := b[:n]
go func() { go func() {
_, respMsg := s.Exchange(reqLen, reqMsg) _, respMsg, err := s.Exchange(reqLen, reqMsg, clientAddr.String())
if err != nil {
logf("proxy-dns error in exchange: %s", err)
return
}
_, err = c.WriteTo(respMsg, clientAddr) _, err = c.WriteTo(respMsg, clientAddr)
if err != nil { if err != nil {
logf("proxy-dns error in local write: %s", err) logf("proxy-dns error in local write: %s", err)
return return
} }
// logf("proxy-dns %s <-> %s, type: %d, %s: %s", clientAddr.String(), dnsServer, query.QueryType, domain, ip)
}() }()
} }
} }
@ -241,11 +245,12 @@ func (s *DNS) ServeTCP(c net.Conn) {
var reqLen uint16 var reqLen uint16
if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil { if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil {
logf("proxy-dns-tcp failed to read request length: %v", err) logf("proxy-dns-tcp failed to get request length: %v", err)
return return
} }
if reqLen <= DNSHeaderLen { // TODO: check here
if reqLen <= DNSHeaderLen+2 {
logf("proxy-dns-tcp not enough data") logf("proxy-dns-tcp not enough data")
return return
} }
@ -257,29 +262,34 @@ func (s *DNS) ServeTCP(c net.Conn) {
return return
} }
respLen, respMsg := s.Exchange(reqLen, reqMsg) respLen, respMsg, err := s.Exchange(reqLen, reqMsg, c.RemoteAddr().String())
if err := binary.Write(c, binary.BigEndian, respLen); err != nil {
logf("proxy-dns-tcp error in local write respLen: %s\n", err)
}
if err := binary.Write(c, binary.BigEndian, respMsg); err != nil {
logf("proxy-dns-tcp error in local write respMsg: %s\n", err)
}
// logf("proxy-dns-tcp %s <-> %s, type: %d, %s: %s", c.RemoteAddr(), dnsServer, query.QueryType, domain, ip)
}
// Exchange handles request msg and return response msg
func (s *DNS) Exchange(reqLen uint16, reqMsg []byte) (respLen uint16, respMsg []byte) {
// fmt.Printf("\ndns req len %d:\n%s\n", reqLen, hex.Dump(reqMsg[:]))
query, err := parseQuestion(reqMsg)
if err != nil { if err != nil {
logf("proxy-dns error in parseQuestion reqMsg %s", err) logf("proxy-dns-tcp error in exchange: %s", err)
return return
} }
dnsServer := s.GetServer(query.QNAME) if err := binary.Write(c, binary.BigEndian, respLen); err != nil {
if s.Tunnel { logf("proxy-dns-tcp error in local write respLen: %s", err)
dnsServer = s.DNSServer return
}
if err := binary.Write(c, binary.BigEndian, respMsg); err != nil {
logf("proxy-dns-tcp error in local write respMsg: %s", err)
return
}
}
// Exchange handles request msg and returns response msg
func (s *DNS) Exchange(reqLen uint16, reqMsg []byte, addr string) (respLen uint16, respMsg []byte, err error) {
// fmt.Printf("\ndns req len %d:\n%s\n", reqLen, hex.Dump(reqMsg[:]))
query, err := parseQuestion(reqMsg)
if err != nil {
logf("proxy-dns error in parseQuestion reqMsg: %s", err)
return
}
dnsServer := s.DNSServer
if !s.Tunnel {
dnsServer = s.GetServer(query.QNAME)
} }
rc, err := s.sDialer.NextDialer(query.QNAME+":53").Dial("tcp", dnsServer) rc, err := s.sDialer.NextDialer(query.QNAME+":53").Dial("tcp", dnsServer)
@ -289,16 +299,16 @@ func (s *DNS) Exchange(reqLen uint16, reqMsg []byte) (respLen uint16, respMsg []
} }
defer rc.Close() defer rc.Close()
if err := binary.Write(rc, binary.BigEndian, reqLen); err != nil { if err = binary.Write(rc, binary.BigEndian, reqLen); err != nil {
logf("proxy-dns failed to write req length: %v", err) logf("proxy-dns failed to write req length: %v", err)
return return
} }
if err := binary.Write(rc, binary.BigEndian, reqMsg); err != nil { if err = binary.Write(rc, binary.BigEndian, reqMsg); err != nil {
logf("proxy-dns failed to write req message: %v", err) logf("proxy-dns failed to write req message: %v", err)
return return
} }
if err := binary.Read(rc, binary.BigEndian, &respLen); err != nil { if err = binary.Read(rc, binary.BigEndian, &respLen); err != nil {
logf("proxy-dns failed to read response length: %v", err) logf("proxy-dns failed to read response length: %v", err)
return return
} }
@ -313,30 +323,35 @@ func (s *DNS) Exchange(reqLen uint16, reqMsg []byte) (respLen uint16, respMsg []
// fmt.Printf("\ndns resp len %d:\n%s\n", respLen, hex.Dump(respMsg[:])) // fmt.Printf("\ndns resp len %d:\n%s\n", respLen, hex.Dump(respMsg[:]))
var ip string var ip string
if respLen > 0 { respReq, err := parseQuestion(respMsg)
query, err := parseQuestion(respMsg)
if err != nil { if err != nil {
logf("proxy-dns error in parseQuestion respMsg %s", err) logf("proxy-dns error in parseQuestion respMsg: %s", err)
return return
} }
if (query.QTYPE == DNSQTypeA || query.QTYPE == DNSQTypeAAAA) && if (respReq.QTYPE == DNSQTypeA || respReq.QTYPE == DNSQTypeAAAA) &&
len(respMsg) > query.Offset { len(respMsg) > respReq.Offset {
var answers []*DNSRR
answers, err = parseAnswers(respMsg[respReq.Offset:])
if err != nil {
logf("proxy-dns error in parseAnswers: %s", err)
return
}
answers := parseAnswers(respMsg[query.Offset:])
for _, answer := range answers { for _, answer := range answers {
for _, h := range s.AnswerHandlers {
h(respReq.QNAME, answer.IP)
}
if answer.IP != "" { if answer.IP != "" {
ip += answer.IP + "," ip += answer.IP + ","
} }
for _, h := range s.AnswerHandlers {
h(query.QNAME, answer.IP)
}
}
} }
} }
logf("proxy-dns %s <-> %s, type: %d, %s: %s", addr, dnsServer, query.QTYPE, query.QNAME, ip)
return return
} }
@ -389,9 +404,13 @@ func parseQuestion(p []byte) (*DNSQuestion, error) {
i = i + l + 1 i = i + l + 1
} }
if len(domain) == 0 {
return nil, errors.New("no QNAME")
}
q.QNAME = string(domain[:len(domain)-1]) q.QNAME = string(domain[:len(domain)-1])
if len(p) < i+4 { if lenP < i+4 {
return nil, errors.New("not enough data") return nil, errors.New("not enough data")
} }
@ -402,10 +421,11 @@ func parseQuestion(p []byte) (*DNSQuestion, error) {
return q, nil return q, nil
} }
func parseAnswers(p []byte) []*DNSRR { func parseAnswers(p []byte) ([]*DNSRR, error) {
var answers []*DNSRR var answers []*DNSRR
lenP := len(p)
for i := 0; i < len(p); { for i := 0; i < lenP; {
// https://tools.ietf.org/html/rfc1035#section-4.1.4 // https://tools.ietf.org/html/rfc1035#section-4.1.4
// "Message compression", // "Message compression",
@ -420,6 +440,10 @@ func parseAnswers(p []byte) []*DNSRR {
break break
} }
if lenP <= i+10 {
return nil, errors.New("not enough data")
}
answer := &DNSRR{} answer := &DNSRR{}
answer.TYPE = binary.BigEndian.Uint16(p[i:]) answer.TYPE = binary.BigEndian.Uint16(p[i:])
@ -439,5 +463,5 @@ func parseAnswers(p []byte) []*DNSRR {
i = i + 10 + int(answer.RDLENGTH) i = i + 10 + int(answer.RDLENGTH)
} }
return answers return answers, nil
} }