glider/dns/server.go

148 lines
3.1 KiB
Go
Raw Normal View History

2018-07-29 23:44:23 +08:00
package dns
import (
"encoding/binary"
2018-07-31 00:03:36 +08:00
"io"
2018-07-29 23:44:23 +08:00
"net"
"sync"
2018-07-31 00:03:36 +08:00
"time"
2018-07-29 23:44:23 +08:00
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
)
2018-07-31 00:03:36 +08:00
// conn timeout, seconds
const timeout = 30
// Server is a dns server struct.
2018-07-29 23:44:23 +08:00
type Server struct {
addr string
// Client is used to communicate with upstream dns servers
*Client
}
// NewServer returns a new dns server.
func NewServer(addr string, p proxy.Proxy, config *Config) (*Server, error) {
c, err := NewClient(p, config)
2020-04-13 00:55:11 +08:00
if err != nil {
return nil, err
}
2018-07-29 23:44:23 +08:00
s := &Server{
addr: addr,
Client: c,
}
2020-04-13 00:55:11 +08:00
return s, nil
2018-07-29 23:44:23 +08:00
}
// Start starts the dns forwarding server.
// We use WaitGroup here to ensure both udp and tcp serer are completly running,
// so we can start any other services later, since they may rely on dns service.
func (s *Server) Start() {
var wg sync.WaitGroup
wg.Add(2)
go s.ListenAndServeTCP(&wg)
go s.ListenAndServeUDP(&wg)
wg.Wait()
2018-07-31 00:03:36 +08:00
}
// ListenAndServeUDP listen and serves on udp port.
func (s *Server) ListenAndServeUDP(wg *sync.WaitGroup) {
2018-07-29 23:44:23 +08:00
c, err := net.ListenPacket("udp", s.addr)
wg.Done()
2018-07-29 23:44:23 +08:00
if err != nil {
log.F("[dns] failed to listen on %s, error: %v", s.addr, err)
return
}
defer c.Close()
log.F("[dns] listening UDP on %s", s.addr)
for {
reqBytes := make([]byte, 2+UDPMaxLen)
n, caddr, err := c.ReadFrom(reqBytes[2:])
if err != nil {
log.F("[dns] local read error: %v", err)
continue
}
reqLen := uint16(n)
if reqLen <= HeaderLen+2 {
log.F("[dns] not enough message data")
continue
}
binary.BigEndian.PutUint16(reqBytes[:2], reqLen)
go func() {
respBytes, err := s.Client.Exchange(reqBytes[:2+n], caddr.String(), false)
2018-07-29 23:44:23 +08:00
if err != nil {
log.F("[dns] error in exchange: %s", err)
return
}
_, err = c.WriteTo(respBytes[2:], caddr)
if err != nil {
log.F("[dns] error in local write: %s", err)
return
}
}()
}
}
2018-07-31 00:03:36 +08:00
// ListenAndServeTCP listen and serves on tcp port.
func (s *Server) ListenAndServeTCP(wg *sync.WaitGroup) {
2018-07-31 00:03:36 +08:00
l, err := net.Listen("tcp", s.addr)
wg.Done()
2018-07-31 00:03:36 +08:00
if err != nil {
log.F("[dns-tcp] error: %v", err)
2018-07-31 00:03:36 +08:00
return
}
defer l.Close()
2018-07-31 00:03:36 +08:00
log.F("[dns-tcp] listening TCP on %s", s.addr)
2018-07-31 00:03:36 +08:00
for {
c, err := l.Accept()
if err != nil {
log.F("[dns-tcp] error: failed to accept: %v", err)
2018-07-31 00:03:36 +08:00
continue
}
go s.ServeTCP(c)
}
}
// ServeTCP serves a tcp connection.
2018-07-31 00:03:36 +08:00
func (s *Server) ServeTCP(c net.Conn) {
defer c.Close()
c.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
var reqLen uint16
if err := binary.Read(c, binary.BigEndian, &reqLen); err != nil {
log.F("[dns-tcp] failed to get request length: %v", err)
2018-07-31 00:03:36 +08:00
return
}
reqBytes := make([]byte, reqLen+2)
_, err := io.ReadFull(c, reqBytes[2:])
if err != nil {
log.F("[dns-tcp] error in read reqBytes %s", err)
2018-07-31 00:03:36 +08:00
return
}
binary.BigEndian.PutUint16(reqBytes[:2], reqLen)
respBytes, err := s.Exchange(reqBytes, c.RemoteAddr().String(), true)
2018-07-31 00:03:36 +08:00
if err != nil {
log.F("[dns-tcp] error in exchange: %s", err)
2018-07-31 00:03:36 +08:00
return
}
if err := binary.Write(c, binary.BigEndian, respBytes); err != nil {
log.F("[dns-tcp] error in local write respBytes: %s", err)
2018-07-31 00:03:36 +08:00
return
}
}