dns: imporve dns client to be compatible with upstream dnsmasq servers

This commit is contained in:
nadoo 2017-12-21 10:10:56 +08:00
parent 47022d6d27
commit a560864ef1
3 changed files with 24 additions and 17 deletions

38
dns.go
View File

@ -4,7 +4,7 @@ package main
import ( import (
"encoding/binary" "encoding/binary"
"io/ioutil" "io"
"net" "net"
"strings" "strings"
) )
@ -98,13 +98,11 @@ func (s *DNS) ListenAndServe() {
data = data[:n] data = data[:n]
go func() { go func() {
// TODO: check domain rules and get a proper upstream name server.
query := parseQuery(data) query := parseQuery(data)
domain := query.DomainName domain := query.DomainName
dnsServer := s.GetServer(domain) dnsServer := s.GetServer(domain)
// TODO: check here; ADD dnsServer to rule ip lists
rc, err := s.sDialer.NextDialer(domain+":53").Dial("tcp", dnsServer) rc, err := s.sDialer.NextDialer(domain+":53").Dial("tcp", dnsServer)
if err != nil { if err != nil {
logf("failed to connect to server %v: %v", dnsServer, err) logf("failed to connect to server %v: %v", dnsServer, err)
@ -113,26 +111,36 @@ func (s *DNS) ListenAndServe() {
defer rc.Close() defer rc.Close()
// 2 bytes length after tcp header, before dns message // 2 bytes length after tcp header, before dns message
length := make([]byte, 2) reqLen := make([]byte, 2)
binary.BigEndian.PutUint16(length, uint16(len(data))) binary.BigEndian.PutUint16(reqLen, uint16(len(data)))
rc.Write(length) rc.Write(reqLen)
rc.Write(data) rc.Write(data)
resp, err := ioutil.ReadAll(rc) // fmt.Printf("dns req len %d:\n%s\n\n", reqLen, hex.Dump(data[:]))
var respLen uint16
err = binary.Read(rc, binary.BigEndian, &respLen)
if err != nil { if err != nil {
logf("error in ioutil.ReadAll: %s\n", err) logf("proxy-dns: error in read respLen %s\n", err)
return return
} }
respMsg := make([]byte, respLen)
_, err = io.ReadFull(rc, respMsg)
if err != nil {
logf("proxy-dns: error in read respMsg %s\n", err)
return
}
// fmt.Printf("dns resp len %d:\n%s\n\n", respLen, hex.Dump(respMsg[:]))
var ip string var ip string
// length is not needed in udp dns response. (2 bytes) // 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. // 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 { if respLen > 0 {
msg := resp[2:] query := parseQuery(respMsg)
// TODO: Get IP from response, check and add to ipset if len(respMsg) > query.Offset {
query := parseQuery(msg) answers := parseAnswers(respMsg[query.Offset:])
if len(msg) > query.Offset {
answers := parseAnswers(msg[query.Offset:])
for _, answer := range answers { for _, answer := range answers {
if answer.IP != "" { if answer.IP != "" {
ip += answer.IP + "," ip += answer.IP + ","
@ -146,7 +154,7 @@ func (s *DNS) ListenAndServe() {
} }
_, err = c.WriteTo(msg, clientAddr) _, err = c.WriteTo(respMsg, clientAddr)
if err != nil { if err != nil {
logf("error in local write: %s\n", err) logf("error in local write: %s\n", err)
} }

View File

@ -9,7 +9,7 @@ import (
) )
// VERSION . // VERSION .
const VERSION = "0.4.2" const VERSION = "0.4.3"
func dialerFromConf() Dialer { func dialerFromConf() Dialer {
// global forwarders in xx.conf // global forwarders in xx.conf

View File

@ -61,7 +61,6 @@ func (rd *RuleDialer) Addr() string { return "RULES" }
// NextDialer return next dialer according to rule // NextDialer return next dialer according to rule
func (rd *RuleDialer) NextDialer(dstAddr string) Dialer { func (rd *RuleDialer) NextDialer(dstAddr string) Dialer {
// TODO: change to index finders
host, _, err := net.SplitHostPort(dstAddr) host, _, err := net.SplitHostPort(dstAddr)
if err != nil { if err != nil {
// TODO: check here // TODO: check here