mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-10-10 20:23:11 +08:00
131 lines
2.8 KiB
Go
131 lines
2.8 KiB
Go
package dns
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
|
|
"github.com/metacubex/mihomo/common/sockopt"
|
|
"github.com/metacubex/mihomo/component/resolver"
|
|
C "github.com/metacubex/mihomo/constant"
|
|
"github.com/metacubex/mihomo/log"
|
|
|
|
D "github.com/miekg/dns"
|
|
)
|
|
|
|
var (
|
|
address string
|
|
server = &Server{}
|
|
|
|
dnsDefaultTTL uint32 = 600
|
|
)
|
|
|
|
type Server struct {
|
|
service resolver.Service
|
|
tcpServer *D.Server
|
|
udpServer *D.Server
|
|
}
|
|
|
|
type serverHandler struct {
|
|
*Server
|
|
isUDP bool
|
|
}
|
|
|
|
// ServeDNS implement D.Handler ServeDNS
|
|
func (s serverHandler) ServeDNS(w D.ResponseWriter, r *D.Msg) {
|
|
msg, err := s.service.ServeMsg(context.Background(), r)
|
|
if err != nil {
|
|
m := new(D.Msg)
|
|
m.SetRcode(r, D.RcodeServerFailure)
|
|
// does not matter if this write fails
|
|
w.WriteMsg(m)
|
|
return
|
|
}
|
|
if s.isUDP {
|
|
// RFC 6891: fit the reply into the client's advertised buffer size,
|
|
// setting the TC bit if records must be dropped; 512 when no OPT present
|
|
msg.Truncate(resolver.RequestUDPSize(r))
|
|
}
|
|
msg.Compress = true
|
|
w.WriteMsg(msg)
|
|
}
|
|
|
|
func (s *Server) UDPHandler() D.Handler {
|
|
return serverHandler{Server: s, isUDP: true}
|
|
}
|
|
|
|
func (s *Server) TCPHandler() D.Handler {
|
|
return serverHandler{Server: s, isUDP: false}
|
|
}
|
|
|
|
func (s *Server) SetService(service resolver.Service) {
|
|
s.service = service
|
|
}
|
|
|
|
func ReCreateServer(addr string, lc C.InboundListenConfig, service resolver.Service) {
|
|
if addr == address && service != nil {
|
|
server.SetService(service)
|
|
return
|
|
}
|
|
|
|
if server.tcpServer != nil {
|
|
_ = server.tcpServer.Shutdown()
|
|
server.tcpServer = nil
|
|
}
|
|
|
|
if server.udpServer != nil {
|
|
_ = server.udpServer.Shutdown()
|
|
server.udpServer = nil
|
|
}
|
|
|
|
server.service = nil
|
|
address = ""
|
|
|
|
if addr == "" || lc == nil || service == nil {
|
|
return
|
|
}
|
|
|
|
var err error
|
|
defer func() {
|
|
if err != nil {
|
|
log.Errorln("Start DNS server error: %s", err.Error())
|
|
}
|
|
}()
|
|
|
|
_, port, err := net.SplitHostPort(addr)
|
|
if port == "0" || port == "" || err != nil {
|
|
return
|
|
}
|
|
|
|
address = addr
|
|
server = &Server{service: service}
|
|
|
|
go func() {
|
|
p, err := lc.ListenPacket(context.Background(), "udp", addr)
|
|
if err != nil {
|
|
log.Errorln("Start DNS server(UDP) error: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if err := sockopt.UDPReuseaddr(p); err != nil {
|
|
log.Warnln("Failed to Reuse UDP Address: %s", err)
|
|
}
|
|
|
|
log.Infoln("DNS server(UDP) listening at: %s", p.LocalAddr().String())
|
|
server.udpServer = &D.Server{Addr: addr, PacketConn: p, Handler: server.UDPHandler()}
|
|
_ = server.udpServer.ActivateAndServe()
|
|
}()
|
|
|
|
go func() {
|
|
l, err := lc.Listen(context.Background(), "tcp", addr)
|
|
if err != nil {
|
|
log.Errorln("Start DNS server(TCP) error: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
log.Infoln("DNS server(TCP) listening at: %s", l.Addr().String())
|
|
server.tcpServer = &D.Server{Addr: addr, Listener: l, Handler: server.TCPHandler()}
|
|
_ = server.tcpServer.ActivateAndServe()
|
|
}()
|
|
|
|
}
|