mirror of
https://github.com/bettercap/bettercap
synced 2025-07-05 20:42:09 -07:00
init dns.proxy
This commit is contained in:
parent
e190737c91
commit
a49d561dce
6 changed files with 736 additions and 0 deletions
124
modules/dns_proxy/dns_proxy.go
Normal file
124
modules/dns_proxy/dns_proxy.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"github.com/bettercap/bettercap/v2/session"
|
||||
)
|
||||
|
||||
type DnsProxy struct {
|
||||
session.SessionModule
|
||||
proxy *DNSProxy
|
||||
}
|
||||
|
||||
func (mod *DnsProxy) Author() string {
|
||||
return "Yarwin Kolff <@buffermet>"
|
||||
}
|
||||
|
||||
func (mod *DnsProxy) Configure() error {
|
||||
var err error
|
||||
var address string
|
||||
var dnsPort int
|
||||
var doRedirect bool
|
||||
var nameserver string
|
||||
var netProtocol string
|
||||
var proxyPort int
|
||||
var scriptPath string
|
||||
|
||||
if mod.Running() {
|
||||
return session.ErrAlreadyStarted(mod.Name())
|
||||
} else if err, dnsPort = mod.IntParam("dns.port"); err != nil {
|
||||
return err
|
||||
} else if err, address = mod.StringParam("dns.proxy.address"); err != nil {
|
||||
return err
|
||||
} else if err, nameserver = mod.StringParam("dns.proxy.nameserver"); err != nil {
|
||||
return err
|
||||
} else if err, netProtocol = mod.StringParam("dns.proxy.networkprotocol"); err != nil {
|
||||
return err
|
||||
} else if err, proxyPort = mod.IntParam("dns.proxy.port"); err != nil {
|
||||
return err
|
||||
} else if err, doRedirect = mod.BoolParam("dns.proxy.redirect"); err != nil {
|
||||
return err
|
||||
} else if err, scriptPath = mod.StringParam("dns.proxy.script"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
error := mod.proxy.Configure(address, dnsPort, doRedirect, nameserver, netProtocol, proxyPort, scriptPath)
|
||||
|
||||
return error
|
||||
}
|
||||
|
||||
func (mod *DnsProxy) Description() string {
|
||||
return "A full featured DNS proxy that can be used to manipulate DNS traffic."
|
||||
}
|
||||
|
||||
func (mod *DnsProxy) Name() string {
|
||||
return "dns.proxy"
|
||||
}
|
||||
|
||||
func NewDnsProxy(s *session.Session) *DnsProxy {
|
||||
mod := &DnsProxy{
|
||||
SessionModule: session.NewSessionModule("dns.proxy", s),
|
||||
proxy: NewDNSProxy(s, "dns.proxy"),
|
||||
}
|
||||
|
||||
mod.AddParam(session.NewIntParameter("dns.port",
|
||||
"53",
|
||||
"DNS port to redirect when the proxy is activated."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.address",
|
||||
session.ParamIfaceAddress,
|
||||
session.IPv4Validator,
|
||||
"Address to bind the DNS proxy to."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.nameserver",
|
||||
"1.1.1.1",
|
||||
session.IPv4Validator,
|
||||
"DNS resolver address."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.networkprotocol",
|
||||
"udp",
|
||||
"^(udp|tcp|tcp-tls)$",
|
||||
"Network protocol for the DNS proxy server to use. Accepted values: udp, tcp, tcp-tls"))
|
||||
|
||||
mod.AddParam(session.NewIntParameter("dns.proxy.port",
|
||||
"8053",
|
||||
"Port to bind the DNS proxy to."))
|
||||
|
||||
mod.AddParam(session.NewBoolParameter("dns.proxy.redirect",
|
||||
"true",
|
||||
"Enable or disable port redirection with iptables."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.script",
|
||||
"",
|
||||
"",
|
||||
"Path of a JS proxy script."))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("dns.proxy on", "",
|
||||
"Start the DNS proxy.",
|
||||
func(args []string) error {
|
||||
return mod.Start()
|
||||
}))
|
||||
|
||||
mod.AddHandler(session.NewModuleHandler("dns.proxy off", "",
|
||||
"Stop the DNS proxy.",
|
||||
func(args []string) error {
|
||||
return mod.Stop()
|
||||
}))
|
||||
|
||||
return mod
|
||||
}
|
||||
|
||||
func (mod *DnsProxy) Start() error {
|
||||
if err := mod.Configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mod.SetRunning(true, func() {
|
||||
mod.proxy.Start()
|
||||
})
|
||||
}
|
||||
|
||||
func (mod *DnsProxy) Stop() error {
|
||||
return mod.SetRunning(false, func() {
|
||||
mod.proxy.Stop()
|
||||
})
|
||||
}
|
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)
|
||||
}
|
86
modules/dns_proxy/dns_proxy_base_filters.go
Normal file
86
modules/dns_proxy/dns_proxy_base_filters.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func shortenResourceRecords(records []string) []string {
|
||||
shorterRecords := []string{}
|
||||
for _, record := range records {
|
||||
shorterRecord := strings.ReplaceAll(record, "\t", " ")
|
||||
shorterRecords = append(shorterRecords, shorterRecord)
|
||||
}
|
||||
return shorterRecords
|
||||
}
|
||||
|
||||
func (p *DNSProxy) logRequestAction(j *JSQuery) {
|
||||
p.Sess.Events.Add(p.Name+".spoofed-request", struct {
|
||||
Client string
|
||||
Questions []string
|
||||
}{
|
||||
j.Client["IP"],
|
||||
shortenResourceRecords(j.Questions),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *DNSProxy) logResponseAction(j *JSQuery) {
|
||||
p.Sess.Events.Add(p.Name+".spoofed-response", struct {
|
||||
client string
|
||||
Extras []string
|
||||
Answers []string
|
||||
Nameservers []string
|
||||
Questions []string
|
||||
}{
|
||||
j.Client["IP"],
|
||||
shortenResourceRecords(j.Extras),
|
||||
shortenResourceRecords(j.Answers),
|
||||
shortenResourceRecords(j.Nameservers),
|
||||
shortenResourceRecords(j.Questions),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *DNSProxy) onRequestFilter(query *dns.Msg, clientIP string) (req, res *dns.Msg) {
|
||||
p.Debug("< %s %s", clientIP, query.Question)
|
||||
|
||||
// do we have a proxy script?
|
||||
if p.Script == nil {
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// run the module OnRequest callback if defined
|
||||
jsreq, jsres := p.Script.OnRequest(query, clientIP)
|
||||
if jsreq != nil {
|
||||
// the request has been changed by the script
|
||||
p.logRequestAction(jsreq)
|
||||
return jsreq.ToQuery(), nil
|
||||
} else if jsres != nil {
|
||||
// a fake response has been returned by the script
|
||||
p.logResponseAction(jsres)
|
||||
return query, jsres.ToQuery()
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
func (p *DNSProxy) onResponseFilter(req, res *dns.Msg, clientIP string) *dns.Msg {
|
||||
// sometimes it happens ¯\_(ツ)_/¯
|
||||
if res == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.Debug("> %s %s", clientIP, res.Answer)
|
||||
|
||||
// do we have a proxy script?
|
||||
if p.Script != nil {
|
||||
_, jsres := p.Script.OnResponse(req, res, clientIP)
|
||||
if jsres != nil {
|
||||
// the response has been changed by the script
|
||||
p.logResponseAction(jsres)
|
||||
return jsres.ToQuery()
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
231
modules/dns_proxy/dns_proxy_js_query.go
Normal file
231
modules/dns_proxy/dns_proxy_js_query.go
Normal file
|
@ -0,0 +1,231 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/log"
|
||||
"github.com/bettercap/bettercap/v2/session"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
var whiteSpaceRegexp = regexp.MustCompile(`\s+`)
|
||||
var stripWhiteSpaceRegexp = regexp.MustCompile(`^\s*(.*?)\s*$`)
|
||||
|
||||
type JSQuery struct {
|
||||
Answers []string
|
||||
Client map[string]string
|
||||
Compress bool `json:"-"`
|
||||
Extras []string
|
||||
Header *JSQueryHeader
|
||||
Nameservers []string
|
||||
Questions []string
|
||||
|
||||
refHash string
|
||||
}
|
||||
|
||||
type JSQueryHeader struct {
|
||||
AuthenticatedData bool
|
||||
Authoritative bool
|
||||
CheckingDisabled bool
|
||||
Id uint16
|
||||
Opcode int
|
||||
Rcode int
|
||||
RecursionAvailable bool
|
||||
RecursionDesired bool
|
||||
Response bool
|
||||
Truncated bool
|
||||
Zero bool
|
||||
}
|
||||
|
||||
func (j *JSQuery) NewHash() string {
|
||||
headerHash := fmt.Sprintf("%t.%t.%t.%d.%d.%d.%t.%t.%t.%t.%t",
|
||||
j.Header.AuthenticatedData,
|
||||
j.Header.Authoritative,
|
||||
j.Header.CheckingDisabled,
|
||||
j.Header.Id,
|
||||
j.Header.Opcode,
|
||||
j.Header.Rcode,
|
||||
j.Header.RecursionAvailable,
|
||||
j.Header.RecursionDesired,
|
||||
j.Header.Response,
|
||||
j.Header.Truncated,
|
||||
j.Header.Zero)
|
||||
hash := fmt.Sprintf("%s.%s.%t.%s.%s.%s.%s",
|
||||
strings.Join(j.Answers, ""),
|
||||
j.Client["IP"],
|
||||
j.Compress,
|
||||
strings.Join(j.Extras, ""),
|
||||
headerHash,
|
||||
strings.Join(j.Nameservers, ""),
|
||||
strings.Join(j.Questions, ""))
|
||||
return hash
|
||||
}
|
||||
|
||||
func NewJSQuery(query *dns.Msg, clientIP string) *JSQuery {
|
||||
answers := []string{}
|
||||
extras := []string{}
|
||||
nameservers := []string{}
|
||||
questions := []string{}
|
||||
|
||||
header := &JSQueryHeader{
|
||||
AuthenticatedData: query.MsgHdr.AuthenticatedData,
|
||||
Authoritative: query.MsgHdr.Authoritative,
|
||||
CheckingDisabled: query.MsgHdr.CheckingDisabled,
|
||||
Id: query.MsgHdr.Id,
|
||||
Opcode: query.MsgHdr.Opcode,
|
||||
Rcode: query.MsgHdr.Rcode,
|
||||
RecursionAvailable: query.MsgHdr.RecursionAvailable,
|
||||
RecursionDesired: query.MsgHdr.RecursionDesired,
|
||||
Response: query.MsgHdr.Response,
|
||||
Truncated: query.MsgHdr.Truncated,
|
||||
Zero: query.MsgHdr.Zero,
|
||||
}
|
||||
|
||||
for _, rr := range query.Answer {
|
||||
answers = append(answers, rr.String())
|
||||
}
|
||||
for _, rr := range query.Extra {
|
||||
extras = append(extras, rr.String())
|
||||
}
|
||||
for _, rr := range query.Ns {
|
||||
nameservers = append(nameservers, rr.String())
|
||||
}
|
||||
for _, q := range query.Question {
|
||||
qType := dns.Type(q.Qtype).String()
|
||||
qClass := dns.Class(q.Qclass).String()
|
||||
questions = append(questions, fmt.Sprintf("%s\t%s\t%s", q.Name, qClass, qType))
|
||||
}
|
||||
|
||||
clientMAC := ""
|
||||
clientAlias := ""
|
||||
if endpoint := session.I.Lan.GetByIp(clientIP); endpoint != nil {
|
||||
clientMAC = endpoint.HwAddress
|
||||
clientAlias = endpoint.Alias
|
||||
}
|
||||
client := map[string]string{"IP": clientIP, "MAC": clientMAC, "Alias": clientAlias}
|
||||
|
||||
jsquery := &JSQuery{
|
||||
Answers: answers,
|
||||
Client: client,
|
||||
Compress: query.Compress,
|
||||
Extras: extras,
|
||||
Header: header,
|
||||
Nameservers: nameservers,
|
||||
Questions: questions,
|
||||
}
|
||||
jsquery.UpdateHash()
|
||||
|
||||
return jsquery
|
||||
}
|
||||
|
||||
func stringToClass(s string) (uint16, error) {
|
||||
for i, dnsClass := range dns.ClassToString {
|
||||
if s == dnsClass {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("unkown DNS class (got %s)", s)
|
||||
}
|
||||
|
||||
func stringToType(s string) (uint16, error) {
|
||||
for i, dnsType := range dns.TypeToString {
|
||||
if s == dnsType {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("unkown DNS type (got %s)", s)
|
||||
}
|
||||
|
||||
func (j *JSQuery) ToQuery() *dns.Msg {
|
||||
var answers []dns.RR
|
||||
var extras []dns.RR
|
||||
var nameservers []dns.RR
|
||||
var questions []dns.Question
|
||||
|
||||
for _, s := range j.Answers {
|
||||
rr, err := dns.NewRR(s)
|
||||
if err != nil {
|
||||
log.Error("error parsing DNS answer resource record: %s", err.Error())
|
||||
return nil
|
||||
} else {
|
||||
answers = append(answers, rr)
|
||||
}
|
||||
}
|
||||
for _, s := range j.Extras {
|
||||
rr, err := dns.NewRR(s)
|
||||
if err != nil {
|
||||
log.Error("error parsing DNS extra resource record: %s", err.Error())
|
||||
return nil
|
||||
} else {
|
||||
extras = append(extras, rr)
|
||||
}
|
||||
}
|
||||
for _, s := range j.Nameservers {
|
||||
rr, err := dns.NewRR(s)
|
||||
if err != nil {
|
||||
log.Error("error parsing DNS nameserver resource record: %s", err.Error())
|
||||
return nil
|
||||
} else {
|
||||
nameservers = append(nameservers, rr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range j.Questions {
|
||||
qStripped := stripWhiteSpaceRegexp.FindStringSubmatch(s)
|
||||
qParts := whiteSpaceRegexp.Split(qStripped[1], -1)
|
||||
|
||||
if len(qParts) != 3 {
|
||||
log.Error("invalid DNS question format: (got %s)", s)
|
||||
return nil
|
||||
}
|
||||
|
||||
qName := dns.Fqdn(qParts[0])
|
||||
qClass, err := stringToClass(qParts[1])
|
||||
if err != nil {
|
||||
log.Error("error parsing DNS question class: %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
qType, err := stringToType(qParts[2])
|
||||
if err != nil {
|
||||
log.Error("error parsing DNS question type: %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
questions = append(questions, dns.Question{qName, qType, qClass})
|
||||
}
|
||||
|
||||
query := &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{
|
||||
Id: j.Header.Id,
|
||||
Response: j.Header.Response,
|
||||
Opcode: j.Header.Opcode,
|
||||
Authoritative: j.Header.Authoritative,
|
||||
Truncated: j.Header.Truncated,
|
||||
RecursionDesired: j.Header.RecursionDesired,
|
||||
RecursionAvailable: j.Header.RecursionAvailable,
|
||||
Zero: j.Header.Zero,
|
||||
AuthenticatedData: j.Header.AuthenticatedData,
|
||||
CheckingDisabled: j.Header.CheckingDisabled,
|
||||
Rcode: j.Header.Rcode,
|
||||
},
|
||||
Compress: j.Compress,
|
||||
Question: questions,
|
||||
Answer: answers,
|
||||
Ns: nameservers,
|
||||
Extra: extras,
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
func (j *JSQuery) UpdateHash() {
|
||||
j.refHash = j.NewHash()
|
||||
}
|
||||
|
||||
func (j *JSQuery) WasModified() bool {
|
||||
// check if any of the fields has been changed
|
||||
return j.NewHash() != j.refHash
|
||||
}
|
99
modules/dns_proxy/dns_proxy_script.go
Normal file
99
modules/dns_proxy/dns_proxy_script.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"github.com/bettercap/bettercap/v2/log"
|
||||
"github.com/bettercap/bettercap/v2/session"
|
||||
"github.com/evilsocket/islazy/plugin"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
type DnsProxyScript struct {
|
||||
*plugin.Plugin
|
||||
|
||||
doOnRequest bool
|
||||
doOnResponse bool
|
||||
doOnCommand bool
|
||||
}
|
||||
|
||||
func LoadDnsProxyScript(path string, sess *session.Session) (err error, s *DnsProxyScript) {
|
||||
log.Debug("loading proxy script %s ...", path)
|
||||
|
||||
plug, err := plugin.Load(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// define session pointer
|
||||
if err = plug.Set("env", sess.Env.Data); err != nil {
|
||||
log.Error("Error while defining environment: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// run onLoad if defined
|
||||
if plug.HasFunc("onLoad") {
|
||||
if _, err = plug.Call("onLoad"); err != nil {
|
||||
log.Error("Error while executing onLoad callback: %s", "\nTraceback:\n "+err.(*otto.Error).String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s = &DnsProxyScript{
|
||||
Plugin: plug,
|
||||
doOnRequest: plug.HasFunc("onRequest"),
|
||||
doOnResponse: plug.HasFunc("onResponse"),
|
||||
doOnCommand: plug.HasFunc("onCommand"),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *DnsProxyScript) OnRequest(req *dns.Msg, clientIP string) (jsreq, jsres *JSQuery) {
|
||||
if s.doOnRequest {
|
||||
jsreq := NewJSQuery(req, clientIP)
|
||||
jsres := NewJSQuery(req, clientIP)
|
||||
|
||||
if _, err := s.Call("onRequest", jsreq, jsres); err != nil {
|
||||
log.Error("%s", err)
|
||||
return nil, nil
|
||||
} else if jsreq.WasModified() {
|
||||
jsreq.UpdateHash()
|
||||
return jsreq, nil
|
||||
} else if jsres.WasModified() {
|
||||
jsres.UpdateHash()
|
||||
return nil, jsres
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *DnsProxyScript) OnResponse(req, res *dns.Msg, clientIP string) (jsreq, jsres *JSQuery) {
|
||||
if s.doOnResponse {
|
||||
jsreq := NewJSQuery(req, clientIP)
|
||||
jsres := NewJSQuery(res, clientIP)
|
||||
|
||||
if _, err := s.Call("onResponse", jsreq, jsres); err != nil {
|
||||
log.Error("%s", err)
|
||||
return nil, nil
|
||||
} else if jsres.WasModified() {
|
||||
jsres.UpdateHash()
|
||||
return nil, jsres
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *DnsProxyScript) OnCommand(cmd string) bool {
|
||||
if s.doOnCommand {
|
||||
if ret, err := s.Call("onCommand", cmd); err != nil {
|
||||
log.Error("Error while executing onCommand callback: %+v", err)
|
||||
return false
|
||||
} else if v, ok := ret.(bool); ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/bettercap/bettercap/v2/modules/can"
|
||||
"github.com/bettercap/bettercap/v2/modules/caplets"
|
||||
"github.com/bettercap/bettercap/v2/modules/dhcp6_spoof"
|
||||
"github.com/bettercap/bettercap/v2/modules/dns_proxy"
|
||||
"github.com/bettercap/bettercap/v2/modules/dns_spoof"
|
||||
"github.com/bettercap/bettercap/v2/modules/events_stream"
|
||||
"github.com/bettercap/bettercap/v2/modules/gps"
|
||||
|
@ -45,6 +46,7 @@ func LoadModules(sess *session.Session) {
|
|||
sess.Register(can.NewCanModule(sess))
|
||||
sess.Register(dhcp6_spoof.NewDHCP6Spoofer(sess))
|
||||
sess.Register(net_recon.NewDiscovery(sess))
|
||||
sess.Register(dns_proxy.NewDnsProxy(sess))
|
||||
sess.Register(dns_spoof.NewDNSSpoofer(sess))
|
||||
sess.Register(events_stream.NewEventsStream(sess))
|
||||
sess.Register(gps.NewGPS(sess))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue