mirror of
https://github.com/bettercap/bettercap
synced 2025-08-14 02:36:57 -07:00
init dns.proxy
This commit is contained in:
parent
e190737c91
commit
a49d561dce
6 changed files with 736 additions and 0 deletions
194
modules/dns_proxy/dns_proxy_base.go
Normal file
194
modules/dns_proxy/dns_proxy_base.go
Normal file
|
@ -0,0 +1,194 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/firewall"
|
||||
"github.com/bettercap/bettercap/v2/session"
|
||||
"github.com/evilsocket/islazy/log"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const (
|
||||
dialTimeout = 2 * time.Second
|
||||
readTimeout = 2 * time.Second
|
||||
writeTimeout = 2 * time.Second
|
||||
)
|
||||
|
||||
type DNSProxy struct {
|
||||
Address string
|
||||
Name string
|
||||
Nameserver string
|
||||
NetProtocol string
|
||||
Redirection *firewall.Redirection
|
||||
Script *DnsProxyScript
|
||||
Server *dns.Server
|
||||
Sess *session.Session
|
||||
|
||||
doRedirect bool
|
||||
isRunning bool
|
||||
tag string
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Configure(address string, dnsPort int, doRedirect bool, nameserver string, netProtocol string, proxyPort int, scriptPath string) error {
|
||||
var err error
|
||||
|
||||
p.Address = address
|
||||
p.doRedirect = doRedirect
|
||||
|
||||
if scriptPath != "" {
|
||||
if err, p.Script = LoadDnsProxyScript(scriptPath, p.Sess); err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.Debug("proxy script %s loaded.", scriptPath)
|
||||
}
|
||||
} else {
|
||||
p.Script = nil
|
||||
}
|
||||
|
||||
dnsClient := dns.Client{
|
||||
DialTimeout: dialTimeout,
|
||||
Net: netProtocol,
|
||||
ReadTimeout: readTimeout,
|
||||
WriteTimeout: writeTimeout,
|
||||
}
|
||||
|
||||
resolverAddr := fmt.Sprintf("%s:%d", nameserver, dnsPort)
|
||||
|
||||
handler := dns.HandlerFunc(func(w dns.ResponseWriter, req *dns.Msg) {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(req)
|
||||
|
||||
clientIP := strings.Split(w.RemoteAddr().String(), ":")[0]
|
||||
|
||||
req, res := p.onRequestFilter(req, clientIP)
|
||||
if res == nil {
|
||||
// unused var is time til res
|
||||
res, _, err := dnsClient.Exchange(req, resolverAddr)
|
||||
if err != nil {
|
||||
p.Debug("error while resolving DNS query: %s", err.Error())
|
||||
m.SetRcode(req, dns.RcodeServerFailure)
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
}
|
||||
res = p.onResponseFilter(req, res, clientIP)
|
||||
if res == nil {
|
||||
p.Error("response filter returned nil")
|
||||
m.SetRcode(req, dns.RcodeServerFailure)
|
||||
w.WriteMsg(m)
|
||||
} else {
|
||||
if err := w.WriteMsg(res); err != nil {
|
||||
p.Error("Error writing response: %s", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := w.WriteMsg(res); err != nil {
|
||||
p.Error("Error writing response: %s", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
p.Server = &dns.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", address, proxyPort),
|
||||
Net: netProtocol,
|
||||
Handler: handler,
|
||||
}
|
||||
|
||||
if p.doRedirect {
|
||||
if !p.Sess.Firewall.IsForwardingEnabled() {
|
||||
p.Info("enabling forwarding.")
|
||||
p.Sess.Firewall.EnableForwarding(true)
|
||||
}
|
||||
|
||||
p.Redirection = firewall.NewRedirection(p.Sess.Interface.Name(),
|
||||
netProtocol,
|
||||
dnsPort,
|
||||
p.Address,
|
||||
proxyPort)
|
||||
|
||||
if err := p.Sess.Firewall.EnableRedirection(p.Redirection, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Debug("applied redirection %s", p.Redirection.String())
|
||||
} else {
|
||||
p.Warning("port redirection disabled, the proxy must be set manually to work")
|
||||
}
|
||||
|
||||
p.Sess.UnkCmdCallback = func(cmd string) bool {
|
||||
if p.Script != nil {
|
||||
return p.Script.OnCommand(cmd)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *DNSProxy) dnsWorker() error {
|
||||
p.isRunning = true
|
||||
return p.Server.ListenAndServe()
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Debug(format string, args ...interface{}) {
|
||||
p.Sess.Events.Log(log.DEBUG, p.tag+format, args...)
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Info(format string, args ...interface{}) {
|
||||
p.Sess.Events.Log(log.INFO, p.tag+format, args...)
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Warning(format string, args ...interface{}) {
|
||||
p.Sess.Events.Log(log.WARNING, p.tag+format, args...)
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Error(format string, args ...interface{}) {
|
||||
p.Sess.Events.Log(log.ERROR, p.tag+format, args...)
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Fatal(format string, args ...interface{}) {
|
||||
p.Sess.Events.Log(log.FATAL, p.tag+format, args...)
|
||||
}
|
||||
|
||||
func NewDNSProxy(s *session.Session, tag string) *DNSProxy {
|
||||
p := &DNSProxy{
|
||||
Name: "dns.proxy",
|
||||
Sess: s,
|
||||
Server: nil,
|
||||
doRedirect: true,
|
||||
tag: session.AsTag(tag),
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Start() {
|
||||
go func() {
|
||||
p.Info("started on %s", p.Server.Addr)
|
||||
|
||||
err := p.dnsWorker()
|
||||
// TODO: check the dns server closed error
|
||||
if err != nil && err.Error() != "dns: Server closed" {
|
||||
p.Fatal("%s", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Stop() error {
|
||||
if p.doRedirect && p.Redirection != nil {
|
||||
p.Debug("disabling redirection %s", p.Redirection.String())
|
||||
if err := p.Sess.Firewall.EnableRedirection(p.Redirection, false); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Redirection = nil
|
||||
}
|
||||
|
||||
p.Sess.UnkCmdCallback = nil
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
return p.Server.ShutdownContext(ctx)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue