2017-08-13 23:51:08 +08:00
|
|
|
// https://tools.ietf.org/html/rfc1035
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
2018-01-09 13:11:55 +08:00
|
|
|
"errors"
|
2017-12-21 10:10:56 +08:00
|
|
|
"io"
|
2017-08-13 23:51:08 +08:00
|
|
|
"net"
|
2017-08-16 13:20:12 +08:00
|
|
|
"strings"
|
2018-06-26 16:15:48 +08:00
|
|
|
|
|
|
|
"github.com/nadoo/glider/common/log"
|
|
|
|
"github.com/nadoo/glider/proxy"
|
2017-08-13 23:51:08 +08:00
|
|
|
)
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
// DNSHeaderLen is the length of dns msg header
|
|
|
|
const DNSHeaderLen = 12
|
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
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
// DNSQTypeA ipv4
|
|
|
|
const DNSQTypeA = 1
|
|
|
|
|
|
|
|
// DNSQTypeAAAA ipv6
|
|
|
|
const DNSQTypeAAAA = 28
|
|
|
|
|
|
|
|
// DNSMsg format
|
|
|
|
// https://tools.ietf.org/html/rfc1035#section-4.1
|
|
|
|
// All communications inside of the domain protocol are carried in a single
|
|
|
|
// format called a message. The top level format of message is divided
|
|
|
|
// into 5 sections (some of which are empty in certain cases) shown below:
|
|
|
|
//
|
|
|
|
// +---------------------+
|
|
|
|
// | Header |
|
|
|
|
// +---------------------+
|
|
|
|
// | Question | the question for the name server
|
|
|
|
// +---------------------+
|
|
|
|
// | Answer | RRs answering the question
|
|
|
|
// +---------------------+
|
|
|
|
// | Authority | RRs pointing toward an authority
|
|
|
|
// +---------------------+
|
|
|
|
// | Additional | RRs holding additional information
|
2018-01-11 14:44:24 +08:00
|
|
|
// type DNSMsg struct {
|
|
|
|
// DNSHeader
|
|
|
|
// Questions []DNSQuestion
|
|
|
|
// Answers []DNSRR
|
|
|
|
// }
|
2017-08-21 23:57:49 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
// DNSHeader format
|
|
|
|
// https://tools.ietf.org/html/rfc1035#section-4.1.1
|
|
|
|
// The header contains the following fields:
|
|
|
|
//
|
|
|
|
// 1 1 1 1 1 1
|
|
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | ID |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | QDCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | ANCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | NSCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | ARCOUNT |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
//
|
2018-01-11 14:44:24 +08:00
|
|
|
// type DNSHeader struct {
|
|
|
|
// ID uint16
|
|
|
|
// }
|
2017-08-21 23:57:49 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
// DNSQuestion format
|
|
|
|
// https://tools.ietf.org/html/rfc1035#section-4.1.2
|
|
|
|
// The question section is used to carry the "question" in most queries,
|
|
|
|
// i.e., the parameters that define what is being asked. The section
|
|
|
|
// contains QDCOUNT (usually 1) entries, each of the following format:
|
|
|
|
//
|
|
|
|
// 1 1 1 1 1 1
|
|
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | |
|
|
|
|
// / QNAME /
|
|
|
|
// / /
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | QTYPE |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | QCLASS |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
type DNSQuestion struct {
|
|
|
|
QNAME string
|
|
|
|
QTYPE uint16
|
|
|
|
QCLASS uint16
|
|
|
|
|
|
|
|
Offset int
|
2017-08-21 23:57:49 +08:00
|
|
|
}
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
// DNSRR format
|
|
|
|
// https://tools.ietf.org/html/rfc1035#section-3.2.1
|
|
|
|
// All RRs have the same top level format shown below:
|
|
|
|
//
|
|
|
|
// 1 1 1 1 1 1
|
|
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | |
|
|
|
|
// / /
|
|
|
|
// / NAME /
|
|
|
|
// | |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | TYPE |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | CLASS |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | TTL |
|
|
|
|
// | |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | RDLENGTH |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|
|
|
|
// / RDATA /
|
|
|
|
// / /
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
type DNSRR struct {
|
|
|
|
// NAME string
|
|
|
|
TYPE uint16
|
|
|
|
CLASS uint16
|
|
|
|
TTL uint32
|
|
|
|
RDLENGTH uint16
|
|
|
|
RDATA []byte
|
2017-08-21 23:57:49 +08:00
|
|
|
|
|
|
|
IP string
|
|
|
|
}
|
2017-08-13 23:51:08 +08:00
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
// DNSAnswerHandler function handles the dns TypeA or TypeAAAA answer
|
|
|
|
type DNSAnswerHandler func(Domain, ip string) error
|
2017-08-23 16:35:39 +08:00
|
|
|
|
2017-08-20 21:44:18 +08:00
|
|
|
// DNS .
|
2017-08-16 13:20:12 +08:00
|
|
|
type DNS struct {
|
2018-06-26 16:15:48 +08:00
|
|
|
dialer proxy.Dialer
|
2018-03-24 19:57:46 +08:00
|
|
|
addr string
|
2017-08-23 16:35:39 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
Tunnel bool
|
2018-01-08 23:37:58 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
DNSServer string
|
2017-08-16 13:20:12 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
DNSServerMap map[string]string
|
|
|
|
AnswerHandlers []DNSAnswerHandler
|
2017-08-13 23:51:08 +08:00
|
|
|
}
|
|
|
|
|
2017-09-10 20:33:35 +08:00
|
|
|
// NewDNS returns a dns forwarder. client[dns.udp] -> glider[tcp] -> forwarder[dns.tcp] -> remote dns addr
|
2018-06-26 16:15:48 +08:00
|
|
|
func NewDNS(addr, raddr string, dialer proxy.Dialer, tunnel bool) (*DNS, error) {
|
2017-08-16 13:20:12 +08:00
|
|
|
s := &DNS{
|
2018-03-24 19:57:46 +08:00
|
|
|
dialer: dialer,
|
|
|
|
addr: addr,
|
2017-08-23 16:35:39 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
Tunnel: tunnel,
|
2018-01-08 23:37:58 +08:00
|
|
|
|
2018-01-09 23:43:56 +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() {
|
2018-01-08 22:28:11 +08:00
|
|
|
go s.ListenAndServeTCP()
|
|
|
|
s.ListenAndServeUDP()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListenAndServeUDP .
|
|
|
|
func (s *DNS) ListenAndServeUDP() {
|
2017-09-06 16:21:27 +08:00
|
|
|
c, err := net.ListenPacket("udp", s.addr)
|
2017-08-13 23:51:08 +08:00
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns failed to listen on %s, error: %v", s.addr, err)
|
2017-08-13 23:51:08 +08:00
|
|
|
return
|
|
|
|
}
|
2017-09-06 16:21:27 +08:00
|
|
|
defer c.Close()
|
2017-08-13 23:51:08 +08:00
|
|
|
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns listening UDP on %s", s.addr)
|
2017-08-13 23:51:08 +08:00
|
|
|
|
|
|
|
for {
|
2018-01-09 23:43:56 +08:00
|
|
|
b := make([]byte, DNSUDPMaxLen)
|
|
|
|
n, clientAddr, err := c.ReadFrom(b)
|
2017-08-13 23:51:08 +08:00
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns local read error: %v", err)
|
2017-08-13 23:51:08 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
reqLen := uint16(n)
|
2018-01-11 14:44:24 +08:00
|
|
|
// TODO: check here
|
|
|
|
if reqLen <= DNSHeaderLen+2 {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns not enough data")
|
2018-01-09 23:43:56 +08:00
|
|
|
continue
|
|
|
|
}
|
2017-08-13 23:51:08 +08:00
|
|
|
|
2018-01-10 12:25:57 +08:00
|
|
|
reqMsg := b[:n]
|
2017-08-13 23:51:08 +08:00
|
|
|
go func() {
|
2018-01-11 14:44:24 +08:00
|
|
|
_, respMsg, err := s.Exchange(reqLen, reqMsg, clientAddr.String())
|
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns error in exchange: %s", err)
|
2018-01-11 14:44:24 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-09 13:11:55 +08:00
|
|
|
_, err = c.WriteTo(respMsg, clientAddr)
|
2017-08-13 23:51:08 +08:00
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns error in local write: %s", err)
|
2018-01-09 23:43:56 +08:00
|
|
|
return
|
2017-08-13 23:51:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-08 22:28:11 +08:00
|
|
|
// ListenAndServeTCP .
|
|
|
|
func (s *DNS) ListenAndServeTCP() {
|
|
|
|
l, err := net.Listen("tcp", s.addr)
|
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp error: %v", err)
|
2018-01-08 22:28:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp listening TCP on %s", s.addr)
|
2018-01-08 22:28:11 +08:00
|
|
|
|
|
|
|
for {
|
|
|
|
c, err := l.Accept()
|
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp error: failed to accept: %v", err)
|
2018-01-08 22:28:11 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
go s.ServeTCP(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServeTCP .
|
|
|
|
func (s *DNS) ServeTCP(c net.Conn) {
|
|
|
|
defer c.Close()
|
|
|
|
|
|
|
|
if c, ok := c.(*net.TCPConn); ok {
|
|
|
|
c.SetKeepAlive(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
var reqLen uint16
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp failed to get request length: %v", err)
|
2018-01-08 22:28:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
// TODO: check here
|
|
|
|
if reqLen <= DNSHeaderLen+2 {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp not enough data")
|
2018-01-09 23:43:56 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-08 22:28:11 +08:00
|
|
|
reqMsg := make([]byte, reqLen)
|
|
|
|
_, err := io.ReadFull(c, reqMsg)
|
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp error in read reqMsg %s", err)
|
2018-01-08 22:28:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
respLen, respMsg, err := s.Exchange(reqLen, reqMsg, c.RemoteAddr().String())
|
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp error in exchange: %s", err)
|
2018-01-11 14:44:24 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-09 13:11:55 +08:00
|
|
|
if err := binary.Write(c, binary.BigEndian, respLen); err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp error in local write respLen: %s", err)
|
2018-01-11 14:44:24 +08:00
|
|
|
return
|
2018-01-09 13:11:55 +08:00
|
|
|
}
|
|
|
|
if err := binary.Write(c, binary.BigEndian, respMsg); err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns-tcp error in local write respMsg: %s", err)
|
2018-01-11 14:44:24 +08:00
|
|
|
return
|
2018-01-09 13:11:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
// Exchange handles request msg and returns response msg
|
2018-01-11 23:14:09 +08:00
|
|
|
// TODO: multiple questions support, parse header to get the number of questions
|
2018-01-11 14:44:24 +08:00
|
|
|
func (s *DNS) Exchange(reqLen uint16, reqMsg []byte, addr string) (respLen uint16, respMsg []byte, err error) {
|
2018-01-10 13:11:13 +08:00
|
|
|
// fmt.Printf("\ndns req len %d:\n%s\n", reqLen, hex.Dump(reqMsg[:]))
|
2018-01-09 23:43:56 +08:00
|
|
|
query, err := parseQuestion(reqMsg)
|
2018-01-09 13:11:55 +08:00
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns error in parseQuestion reqMsg: %s", err)
|
2018-01-09 13:11:55 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
dnsServer := s.DNSServer
|
|
|
|
if !s.Tunnel {
|
|
|
|
dnsServer = s.GetServer(query.QNAME)
|
2018-01-08 22:28:11 +08:00
|
|
|
}
|
|
|
|
|
2018-03-24 19:57:46 +08:00
|
|
|
rc, err := s.dialer.NextDialer(query.QNAME+":53").Dial("tcp", dnsServer)
|
2018-01-08 22:28:11 +08:00
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns failed to connect to server %v: %v", dnsServer, err)
|
2018-01-08 22:28:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
defer rc.Close()
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
if err = binary.Write(rc, binary.BigEndian, reqLen); err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns failed to write req length: %v", err)
|
2018-01-09 23:43:56 +08:00
|
|
|
return
|
2018-01-08 23:37:58 +08:00
|
|
|
}
|
2018-01-11 14:44:24 +08:00
|
|
|
if err = binary.Write(rc, binary.BigEndian, reqMsg); err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns failed to write req message: %v", err)
|
2018-01-09 23:43:56 +08:00
|
|
|
return
|
2018-01-08 23:37:58 +08:00
|
|
|
}
|
2018-01-08 22:28:11 +08:00
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
if err = binary.Read(rc, binary.BigEndian, &respLen); err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns failed to read response length: %v", err)
|
2018-01-08 22:28:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-09 13:11:55 +08:00
|
|
|
respMsg = make([]byte, respLen)
|
2018-01-08 22:28:11 +08:00
|
|
|
_, err = io.ReadFull(rc, respMsg)
|
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns error in read respMsg %s\n", err)
|
2018-01-08 22:28:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-10 13:11:13 +08:00
|
|
|
// fmt.Printf("\ndns resp len %d:\n%s\n", respLen, hex.Dump(respMsg[:]))
|
2018-01-08 23:37:58 +08:00
|
|
|
|
2018-01-08 22:28:11 +08:00
|
|
|
var ip string
|
2018-01-11 14:44:24 +08:00
|
|
|
respReq, err := parseQuestion(respMsg)
|
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns error in parseQuestion respMsg: %s", err)
|
2018-01-11 14:44:24 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (respReq.QTYPE == DNSQTypeA || respReq.QTYPE == DNSQTypeAAAA) &&
|
|
|
|
len(respMsg) > respReq.Offset {
|
|
|
|
|
|
|
|
var answers []*DNSRR
|
|
|
|
answers, err = parseAnswers(respMsg[respReq.Offset:])
|
2018-01-09 13:11:55 +08:00
|
|
|
if err != nil {
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns error in parseAnswers: %s", err)
|
2018-01-09 13:11:55 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
for _, answer := range answers {
|
|
|
|
for _, h := range s.AnswerHandlers {
|
|
|
|
h(respReq.QNAME, answer.IP)
|
|
|
|
}
|
2018-01-08 22:28:11 +08:00
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
if answer.IP != "" {
|
|
|
|
ip += answer.IP + ","
|
2018-01-08 22:28:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-06-26 16:15:48 +08:00
|
|
|
log.F("proxy-dns %s <-> %s, type: %d, %s: %s", addr, dnsServer, query.QTYPE, query.QNAME, ip)
|
2018-01-09 13:11:55 +08:00
|
|
|
return
|
2018-01-08 22:28:11 +08:00
|
|
|
}
|
|
|
|
|
2017-08-16 13:20:12 +08:00
|
|
|
// SetServer .
|
|
|
|
func (s *DNS) SetServer(domain, server string) {
|
2018-01-09 23:43:56 +08:00
|
|
|
s.DNSServerMap[domain] = server
|
2017-08-16 13:20:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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], ".")
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
if server, ok := s.DNSServerMap[domain]; ok {
|
2017-08-16 13:20:12 +08:00
|
|
|
return server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
return s.DNSServer
|
2017-08-16 13:20:12 +08:00
|
|
|
}
|
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
// AddAnswerHandler .
|
|
|
|
func (s *DNS) AddAnswerHandler(h DNSAnswerHandler) {
|
2018-01-09 23:43:56 +08:00
|
|
|
s.AnswerHandlers = append(s.AnswerHandlers, h)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
func parseQuestion(p []byte) (*DNSQuestion, error) {
|
|
|
|
q := &DNSQuestion{}
|
2018-01-10 12:25:57 +08:00
|
|
|
lenP := len(p)
|
2017-08-13 23:51:08 +08:00
|
|
|
|
2017-08-21 23:57:49 +08:00
|
|
|
var i int
|
|
|
|
var domain []byte
|
2018-01-10 12:25:57 +08:00
|
|
|
for i = DNSHeaderLen; i < lenP; {
|
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
|
|
|
|
}
|
|
|
|
|
2018-01-10 12:25:57 +08:00
|
|
|
if lenP <= i+l+1 {
|
2018-01-10 13:11:13 +08:00
|
|
|
return nil, errors.New("not enough data for QNAME")
|
2018-01-10 12:25:57 +08:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
if len(domain) == 0 {
|
|
|
|
return nil, errors.New("no QNAME")
|
|
|
|
}
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
q.QNAME = string(domain[:len(domain)-1])
|
2018-01-09 13:11:55 +08:00
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
if lenP < i+4 {
|
2018-01-10 13:11:13 +08:00
|
|
|
return nil, errors.New("not enough data")
|
2018-01-09 13:11:55 +08:00
|
|
|
}
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
q.QTYPE = binary.BigEndian.Uint16(p[i:])
|
|
|
|
q.QCLASS = binary.BigEndian.Uint16(p[i+2:])
|
2017-08-21 23:57:49 +08:00
|
|
|
q.Offset = i + 4
|
|
|
|
|
2018-01-09 13:11:55 +08:00
|
|
|
return q, nil
|
2017-08-21 23:57:49 +08:00
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
func parseAnswers(p []byte) ([]*DNSRR, error) {
|
2018-01-09 23:43:56 +08:00
|
|
|
var answers []*DNSRR
|
2018-01-11 14:44:24 +08:00
|
|
|
lenP := len(p)
|
2017-08-21 23:57:49 +08:00
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
for i := 0; i < lenP; {
|
2017-08-21 23:57:49 +08:00
|
|
|
|
2018-01-06 13:33:09 +08:00
|
|
|
// https://tools.ietf.org/html/rfc1035#section-4.1.4
|
|
|
|
// "Message compression",
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
// | 1 1| OFFSET |
|
|
|
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
|
|
|
|
|
|
if p[i]>>6 == 3 {
|
|
|
|
i += 2
|
|
|
|
} else {
|
|
|
|
// TODO: none compressed query name and Additional records will be ignored
|
2017-08-21 23:57:49 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
if lenP <= i+10 {
|
|
|
|
return nil, errors.New("not enough data")
|
|
|
|
}
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
answer := &DNSRR{}
|
2018-01-05 12:29:06 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
answer.TYPE = binary.BigEndian.Uint16(p[i:])
|
|
|
|
answer.CLASS = binary.BigEndian.Uint16(p[i+2:])
|
2018-01-06 13:33:09 +08:00
|
|
|
answer.TTL = binary.BigEndian.Uint32(p[i+4:])
|
2018-01-09 23:43:56 +08:00
|
|
|
answer.RDLENGTH = binary.BigEndian.Uint16(p[i+8:])
|
|
|
|
answer.RDATA = p[i+10 : i+10+int(answer.RDLENGTH)]
|
2017-08-21 23:57:49 +08:00
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
if answer.TYPE == DNSQTypeA {
|
|
|
|
answer.IP = net.IP(answer.RDATA[:net.IPv4len]).String()
|
|
|
|
} else if answer.TYPE == DNSQTypeAAAA {
|
|
|
|
answer.IP = net.IP(answer.RDATA[:net.IPv6len]).String()
|
2017-08-21 23:57:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
answers = append(answers, answer)
|
|
|
|
|
2018-01-09 23:43:56 +08:00
|
|
|
i = i + 10 + int(answer.RDLENGTH)
|
2017-08-21 23:57:49 +08:00
|
|
|
}
|
|
|
|
|
2018-01-11 14:44:24 +08:00
|
|
|
return answers, nil
|
2017-08-13 23:51:08 +08:00
|
|
|
}
|