mirror of
https://github.com/bettercap/bettercap
synced 2025-08-19 21:13:18 -07:00
commit
906162e5fa
10 changed files with 2256 additions and 0 deletions
185
modules/dns_proxy/dns_proxy.go
Normal file
185
modules/dns_proxy/dns_proxy.go
Normal file
|
@ -0,0 +1,185 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"github.com/bettercap/bettercap/v2/session"
|
||||
"github.com/bettercap/bettercap/v2/tls"
|
||||
|
||||
"github.com/evilsocket/islazy/fs"
|
||||
"github.com/evilsocket/islazy/str"
|
||||
)
|
||||
|
||||
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
|
||||
var certFile string
|
||||
var keyFile string
|
||||
var whitelist string
|
||||
var blacklist 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, certFile = mod.StringParam("dns.proxy.certificate"); err != nil {
|
||||
return err
|
||||
} else if certFile, err = fs.Expand(certFile); err != nil {
|
||||
return err
|
||||
} else if err, keyFile = mod.StringParam("dns.proxy.key"); err != nil {
|
||||
return err
|
||||
} else if keyFile, err = fs.Expand(keyFile); err != nil {
|
||||
return err
|
||||
} else if err, nameserver = mod.StringParam("dns.proxy.nameserver"); err != nil {
|
||||
return err
|
||||
} else if err, proxyPort = mod.IntParam("dns.proxy.port"); err != nil {
|
||||
return err
|
||||
} else if err, netProtocol = mod.StringParam("dns.proxy.protocol"); 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
|
||||
} else if err, blacklist = mod.StringParam("dns.proxy.blacklist"); err != nil {
|
||||
return err
|
||||
} else if err, whitelist = mod.StringParam("dns.proxy.whitelist"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mod.proxy.Blacklist = str.Comma(blacklist)
|
||||
mod.proxy.Whitelist = str.Comma(whitelist)
|
||||
|
||||
if netProtocol == "tcp-tls" {
|
||||
if !fs.Exists(certFile) || !fs.Exists(keyFile) {
|
||||
cfg, err := tls.CertConfigFromModule("dns.proxy", mod.SessionModule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mod.Debug("%+v", cfg)
|
||||
mod.Info("generating proxy certification authority TLS key to %s", keyFile)
|
||||
mod.Info("generating proxy certification authority TLS certificate to %s", certFile)
|
||||
if err := tls.Generate(cfg, certFile, keyFile, true); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
mod.Info("loading proxy certification authority TLS key from %s", keyFile)
|
||||
mod.Info("loading proxy certification authority TLS certificate from %s", certFile)
|
||||
}
|
||||
}
|
||||
|
||||
err = mod.proxy.Configure(address, dnsPort, doRedirect, nameserver, netProtocol,
|
||||
proxyPort, scriptPath, certFile, keyFile)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
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.blacklist", "", "",
|
||||
"Comma separated list of client IPs to skip while proxying (wildcard allowed)."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.whitelist", "", "",
|
||||
"Comma separated list of client IPs to proxy if the blacklist is used."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.nameserver",
|
||||
"1.1.1.1",
|
||||
session.IPv4Validator,
|
||||
"DNS resolver address."))
|
||||
|
||||
mod.AddParam(session.NewIntParameter("dns.proxy.port",
|
||||
"8053",
|
||||
"Port to bind the DNS proxy to."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.protocol",
|
||||
"udp",
|
||||
"^(udp|tcp|tcp-tls)$",
|
||||
"Network protocol for the DNS proxy server to use. Accepted values: udp, tcp, tcp-tls"))
|
||||
|
||||
mod.AddParam(session.NewBoolParameter("dns.proxy.redirect",
|
||||
"true",
|
||||
"Enable or disable port redirection with iptables."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.certificate",
|
||||
"~/.bettercap-ca.cert.pem",
|
||||
"",
|
||||
"DNS proxy certification authority TLS certificate file."))
|
||||
|
||||
mod.AddParam(session.NewStringParameter("dns.proxy.key",
|
||||
"~/.bettercap-ca.key.pem",
|
||||
"",
|
||||
"DNS proxy certification authority TLS key file."))
|
||||
|
||||
tls.CertConfigToModule("dns.proxy", &mod.SessionModule, tls.DefaultCloudflareDNSConfig)
|
||||
|
||||
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()
|
||||
})
|
||||
}
|
241
modules/dns_proxy/dns_proxy_base.go
Normal file
241
modules/dns_proxy/dns_proxy_base.go
Normal file
|
@ -0,0 +1,241 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"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 {
|
||||
Name string
|
||||
Address string
|
||||
Server *dns.Server
|
||||
Redirection *firewall.Redirection
|
||||
Nameserver string
|
||||
NetProtocol string
|
||||
Script *DnsProxyScript
|
||||
CertFile string
|
||||
KeyFile string
|
||||
Blacklist []string
|
||||
Whitelist []string
|
||||
Sess *session.Session
|
||||
|
||||
doRedirect bool
|
||||
isRunning bool
|
||||
tag string
|
||||
}
|
||||
|
||||
func (p *DNSProxy) shouldProxy(clientIP string) bool {
|
||||
// check if this client is in the whitelist
|
||||
for _, ip := range p.Whitelist {
|
||||
if clientIP == ip {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// check if this client is in the blacklist
|
||||
for _, ip := range p.Blacklist {
|
||||
if ip == "*" || clientIP == ip {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *DNSProxy) Configure(address string, dnsPort int, doRedirect bool, nameserver string, netProtocol string, proxyPort int, scriptPath string, certFile string, keyFile string) error {
|
||||
var err error
|
||||
|
||||
p.Address = address
|
||||
p.doRedirect = doRedirect
|
||||
p.CertFile = certFile
|
||||
p.KeyFile = keyFile
|
||||
|
||||
if scriptPath != "" {
|
||||
if err, p.Script = LoadDnsProxyScript(scriptPath, p.Sess); err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.Debug("proxy script %s loaded.", scriptPath)
|
||||
}
|
||||
}
|
||||
|
||||
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.Debug("response is nil")
|
||||
m.SetRcode(req, dns.RcodeServerFailure)
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
} 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 netProtocol == "tcp-tls" && p.CertFile != "" && p.KeyFile != "" {
|
||||
rawCert, _ := ioutil.ReadFile(p.CertFile)
|
||||
rawKey, _ := ioutil.ReadFile(p.KeyFile)
|
||||
ourCa, err := tls.X509KeyPair(rawCert, rawKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ourCa.Leaf, err = x509.ParseCertificate(ourCa.Certificate[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Server.TLSConfig = &tls.Config{
|
||||
Certificates: []tls.Certificate{ourCa},
|
||||
}
|
||||
}
|
||||
|
||||
if p.doRedirect {
|
||||
if !p.Sess.Firewall.IsForwardingEnabled() {
|
||||
p.Info("enabling forwarding.")
|
||||
p.Sess.Firewall.EnableForwarding(true)
|
||||
}
|
||||
|
||||
redirectProtocol := netProtocol
|
||||
if redirectProtocol == "tcp-tls" {
|
||||
redirectProtocol = "tcp"
|
||||
}
|
||||
p.Redirection = firewall.NewRedirection(p.Sess.Interface.Name(),
|
||||
redirectProtocol,
|
||||
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)
|
||||
}
|
113
modules/dns_proxy/dns_proxy_base_filters.go
Normal file
113
modules/dns_proxy/dns_proxy_base_filters.go
Normal file
|
@ -0,0 +1,113 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func questionsToStrings(qs []dns.Question) []string {
|
||||
questions := []string{}
|
||||
for _, q := range qs {
|
||||
questions = append(questions, tabsToSpaces(q.String()))
|
||||
}
|
||||
return questions
|
||||
}
|
||||
|
||||
func recordsToStrings(rrs []dns.RR) []string {
|
||||
records := []string{}
|
||||
for _, rr := range rrs {
|
||||
if rr != nil {
|
||||
records = append(records, tabsToSpaces(rr.String()))
|
||||
}
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
func tabsToSpaces(s string) string {
|
||||
return strings.ReplaceAll(s, "\t", " ")
|
||||
}
|
||||
|
||||
func (p *DNSProxy) logRequestAction(m *dns.Msg, clientIP string) {
|
||||
p.Sess.Events.Add(p.Name+".spoofed-request", struct {
|
||||
Client string
|
||||
Questions []string
|
||||
}{
|
||||
clientIP,
|
||||
questionsToStrings(m.Question),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *DNSProxy) logResponseAction(m *dns.Msg, clientIP string) {
|
||||
p.Sess.Events.Add(p.Name+".spoofed-response", struct {
|
||||
client string
|
||||
Answers []string
|
||||
Extras []string
|
||||
Nameservers []string
|
||||
Questions []string
|
||||
}{
|
||||
clientIP,
|
||||
recordsToStrings(m.Answer),
|
||||
recordsToStrings(m.Extra),
|
||||
recordsToStrings(m.Ns),
|
||||
questionsToStrings(m.Question),
|
||||
})
|
||||
}
|
||||
|
||||
func (p *DNSProxy) onRequestFilter(query *dns.Msg, clientIP string) (req, res *dns.Msg) {
|
||||
if p.shouldProxy(clientIP) {
|
||||
p.Debug("< %s q[%s]",
|
||||
clientIP,
|
||||
strings.Join(questionsToStrings(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
|
||||
req := jsreq.ToQuery()
|
||||
p.logRequestAction(req, clientIP)
|
||||
return req, nil
|
||||
} else if jsres != nil {
|
||||
// a fake response has been returned by the script
|
||||
res := jsres.ToQuery()
|
||||
p.logResponseAction(res, clientIP)
|
||||
return query, res
|
||||
}
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
func (p *DNSProxy) onResponseFilter(req, res *dns.Msg, clientIP string) *dns.Msg {
|
||||
if p.shouldProxy(clientIP) {
|
||||
// sometimes it happens ¯\_(ツ)_/¯
|
||||
if res == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.Debug("> %s q[%s] a[%s] e[%s] n[%s]",
|
||||
clientIP,
|
||||
strings.Join(questionsToStrings(res.Question), ","),
|
||||
strings.Join(recordsToStrings(res.Answer), ","),
|
||||
strings.Join(recordsToStrings(res.Extra), ","),
|
||||
strings.Join(recordsToStrings(res.Ns), ","))
|
||||
|
||||
// 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
|
||||
res := jsres.ToQuery()
|
||||
p.logResponseAction(res, clientIP)
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
295
modules/dns_proxy/dns_proxy_js_query.go
Normal file
295
modules/dns_proxy/dns_proxy_js_query.go
Normal file
|
@ -0,0 +1,295 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/log"
|
||||
"github.com/bettercap/bettercap/v2/session"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type JSQuery struct {
|
||||
Answers []map[string]interface{}
|
||||
Client map[string]string
|
||||
Compress bool
|
||||
Extras []map[string]interface{}
|
||||
Header JSQueryHeader
|
||||
Nameservers []map[string]interface{}
|
||||
Questions []map[string]interface{}
|
||||
|
||||
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 jsPropToMap(obj map[string]interface{}, key string) map[string]interface{} {
|
||||
if v, ok := obj[key].(map[string]interface{}); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to map[string]interface{} where key is: %s", key)
|
||||
return map[string]interface{}{}
|
||||
}
|
||||
|
||||
func jsPropToMapArray(obj map[string]interface{}, key string) []map[string]interface{} {
|
||||
if v, ok := obj[key].([]map[string]interface{}); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to []map[string]interface{} where key is: %s", key)
|
||||
return []map[string]interface{}{}
|
||||
}
|
||||
|
||||
func jsPropToString(obj map[string]interface{}, key string) string {
|
||||
if v, ok := obj[key].(string); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to string where key is: %s", key)
|
||||
return ""
|
||||
}
|
||||
|
||||
func jsPropToStringArray(obj map[string]interface{}, key string) []string {
|
||||
if v, ok := obj[key].([]string); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to []string where key is: %s", key)
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func jsPropToUint8(obj map[string]interface{}, key string) uint8 {
|
||||
if v, ok := obj[key].(uint8); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to uint8 where key is: %s", key)
|
||||
return 0
|
||||
}
|
||||
|
||||
func jsPropToUint8Array(obj map[string]interface{}, key string) []uint8 {
|
||||
if v, ok := obj[key].([]uint8); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to []uint8 where key is: %s", key)
|
||||
return []uint8{}
|
||||
}
|
||||
|
||||
func jsPropToUint16(obj map[string]interface{}, key string) uint16 {
|
||||
if v, ok := obj[key].(uint16); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to uint16 where key is: %s", key)
|
||||
return 0
|
||||
}
|
||||
|
||||
func jsPropToUint16Array(obj map[string]interface{}, key string) []uint16 {
|
||||
if v, ok := obj[key].([]uint16); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to []uint16 where key is: %s", key)
|
||||
return []uint16{}
|
||||
}
|
||||
|
||||
func jsPropToUint32(obj map[string]interface{}, key string) uint32 {
|
||||
if v, ok := obj[key].(uint32); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to uint32 where key is: %s", key)
|
||||
return 0
|
||||
}
|
||||
|
||||
func jsPropToUint64(obj map[string]interface{}, key string) uint64 {
|
||||
if v, ok := obj[key].(uint64); ok {
|
||||
return v
|
||||
}
|
||||
log.Debug("error converting JS property to uint64 where key is: %s", key)
|
||||
return 0
|
||||
}
|
||||
|
||||
func (j *JSQuery) NewHash() string {
|
||||
answers, _ := json.Marshal(j.Answers)
|
||||
extras, _ := json.Marshal(j.Extras)
|
||||
nameservers, _ := json.Marshal(j.Nameservers)
|
||||
questions, _ := json.Marshal(j.Questions)
|
||||
|
||||
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",
|
||||
answers,
|
||||
j.Client["IP"],
|
||||
j.Compress,
|
||||
extras,
|
||||
headerHash,
|
||||
nameservers,
|
||||
questions)
|
||||
|
||||
return hash
|
||||
}
|
||||
|
||||
func NewJSQuery(query *dns.Msg, clientIP string) (jsQuery *JSQuery) {
|
||||
answers := make([]map[string]interface{}, len(query.Answer))
|
||||
extras := make([]map[string]interface{}, len(query.Extra))
|
||||
nameservers := make([]map[string]interface{}, len(query.Ns))
|
||||
questions := make([]map[string]interface{}, len(query.Question))
|
||||
|
||||
for i, rr := range query.Answer {
|
||||
jsRecord, err := NewJSResourceRecord(rr)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
answers[i] = jsRecord
|
||||
}
|
||||
|
||||
for i, rr := range query.Extra {
|
||||
jsRecord, err := NewJSResourceRecord(rr)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
extras[i] = jsRecord
|
||||
}
|
||||
|
||||
for i, rr := range query.Ns {
|
||||
jsRecord, err := NewJSResourceRecord(rr)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
nameservers[i] = jsRecord
|
||||
}
|
||||
|
||||
for i, question := range query.Question {
|
||||
questions[i] = map[string]interface{}{
|
||||
"Name": question.Name,
|
||||
"Qtype": question.Qtype,
|
||||
"Qclass": question.Qclass,
|
||||
}
|
||||
}
|
||||
|
||||
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: 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,
|
||||
},
|
||||
Nameservers: nameservers,
|
||||
Questions: questions,
|
||||
}
|
||||
jsquery.UpdateHash()
|
||||
|
||||
return jsquery
|
||||
}
|
||||
|
||||
func (j *JSQuery) ToQuery() *dns.Msg {
|
||||
var answers []dns.RR
|
||||
var extras []dns.RR
|
||||
var nameservers []dns.RR
|
||||
var questions []dns.Question
|
||||
|
||||
for _, jsRR := range j.Answers {
|
||||
rr, err := ToRR(jsRR)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
answers = append(answers, rr)
|
||||
}
|
||||
for _, jsRR := range j.Extras {
|
||||
rr, err := ToRR(jsRR)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
extras = append(extras, rr)
|
||||
}
|
||||
for _, jsRR := range j.Nameservers {
|
||||
rr, err := ToRR(jsRR)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
nameservers = append(nameservers, rr)
|
||||
}
|
||||
|
||||
for _, jsQ := range j.Questions {
|
||||
questions = append(questions, dns.Question{
|
||||
Name: jsPropToString(jsQ, "Name"),
|
||||
Qtype: jsPropToUint16(jsQ, "Qtype"),
|
||||
Qclass: jsPropToUint16(jsQ, "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
|
||||
}
|
951
modules/dns_proxy/dns_proxy_js_record.go
Normal file
951
modules/dns_proxy/dns_proxy_js_record.go
Normal file
|
@ -0,0 +1,951 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/log"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func NewJSResourceRecord(rr dns.RR) (jsRecord map[string]interface{}, err error) {
|
||||
header := rr.Header()
|
||||
|
||||
jsRecord = map[string]interface{}{
|
||||
"Header": map[string]interface{}{
|
||||
"Class": header.Class,
|
||||
"Name": header.Name,
|
||||
"Rrtype": header.Rrtype,
|
||||
"Ttl": header.Ttl,
|
||||
},
|
||||
}
|
||||
|
||||
switch rr := rr.(type) {
|
||||
case *dns.A:
|
||||
jsRecord["A"] = rr.A.String()
|
||||
case *dns.AAAA:
|
||||
jsRecord["AAAA"] = rr.AAAA.String()
|
||||
case *dns.APL:
|
||||
jsPrefixes := make([]map[string]interface{}, len(rr.Prefixes))
|
||||
for i, v := range rr.Prefixes {
|
||||
jsPrefixes[i] = map[string]interface{}{
|
||||
"Negation": v.Negation,
|
||||
"Network": v.Network.String(),
|
||||
}
|
||||
}
|
||||
jsRecord["Prefixes"] = jsPrefixes
|
||||
case *dns.CNAME:
|
||||
jsRecord["Target"] = rr.Target
|
||||
case *dns.MB:
|
||||
jsRecord["Mb"] = rr.Mb
|
||||
case *dns.MD:
|
||||
jsRecord["Md"] = rr.Md
|
||||
case *dns.MF:
|
||||
jsRecord["Mf"] = rr.Mf
|
||||
case *dns.MG:
|
||||
jsRecord["Mg"] = rr.Mg
|
||||
case *dns.MR:
|
||||
jsRecord["Mr"] = rr.Mr
|
||||
case *dns.MX:
|
||||
jsRecord["Mx"] = rr.Mx
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.NULL:
|
||||
jsRecord["Data"] = rr.Data
|
||||
case *dns.SOA:
|
||||
jsRecord["Expire"] = rr.Expire
|
||||
jsRecord["Minttl"] = rr.Minttl
|
||||
jsRecord["Ns"] = rr.Ns
|
||||
jsRecord["Refresh"] = rr.Refresh
|
||||
jsRecord["Retry"] = rr.Retry
|
||||
jsRecord["Mbox"] = rr.Mbox
|
||||
jsRecord["Serial"] = rr.Serial
|
||||
case *dns.TXT:
|
||||
jsRecord["Txt"] = rr.Txt
|
||||
case *dns.SRV:
|
||||
jsRecord["Port"] = rr.Port
|
||||
jsRecord["Priority"] = rr.Priority
|
||||
jsRecord["Target"] = rr.Target
|
||||
jsRecord["Weight"] = rr.Weight
|
||||
case *dns.PTR:
|
||||
jsRecord["Ptr"] = rr.Ptr
|
||||
case *dns.NS:
|
||||
jsRecord["Ns"] = rr.Ns
|
||||
case *dns.DNAME:
|
||||
jsRecord["Target"] = rr.Target
|
||||
case *dns.AFSDB:
|
||||
jsRecord["Subtype"] = rr.Subtype
|
||||
jsRecord["Hostname"] = rr.Hostname
|
||||
case *dns.CAA:
|
||||
jsRecord["Flag"] = rr.Flag
|
||||
jsRecord["Tag"] = rr.Tag
|
||||
jsRecord["Value"] = rr.Value
|
||||
case *dns.HINFO:
|
||||
jsRecord["Cpu"] = rr.Cpu
|
||||
jsRecord["Os"] = rr.Os
|
||||
case *dns.MINFO:
|
||||
jsRecord["Email"] = rr.Email
|
||||
jsRecord["Rmail"] = rr.Rmail
|
||||
case *dns.ISDN:
|
||||
jsRecord["Address"] = rr.Address
|
||||
jsRecord["SubAddress"] = rr.SubAddress
|
||||
case *dns.KX:
|
||||
jsRecord["Exchanger"] = rr.Exchanger
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.LOC:
|
||||
jsRecord["Altitude"] = rr.Altitude
|
||||
jsRecord["HorizPre"] = rr.HorizPre
|
||||
jsRecord["Latitude"] = rr.Latitude
|
||||
jsRecord["Longitude"] = rr.Longitude
|
||||
jsRecord["Size"] = rr.Size
|
||||
jsRecord["Version"] = rr.Version
|
||||
jsRecord["VertPre"] = rr.VertPre
|
||||
case *dns.SSHFP:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["FingerPrint"] = rr.FingerPrint
|
||||
jsRecord["Type"] = rr.Type
|
||||
case *dns.TLSA:
|
||||
jsRecord["Certificate"] = rr.Certificate
|
||||
jsRecord["MatchingType"] = rr.MatchingType
|
||||
jsRecord["Selector"] = rr.Selector
|
||||
jsRecord["Usage"] = rr.Usage
|
||||
case *dns.CERT:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Certificate"] = rr.Certificate
|
||||
jsRecord["KeyTag"] = rr.KeyTag
|
||||
jsRecord["Type"] = rr.Type
|
||||
case *dns.DS:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Digest"] = rr.Digest
|
||||
jsRecord["DigestType"] = rr.DigestType
|
||||
jsRecord["KeyTag"] = rr.KeyTag
|
||||
case *dns.NAPTR:
|
||||
jsRecord["Order"] = rr.Order
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Service"] = rr.Service
|
||||
jsRecord["Regexp"] = rr.Regexp
|
||||
jsRecord["Replacement"] = rr.Replacement
|
||||
case *dns.RRSIG:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Expiration"] = rr.Expiration
|
||||
jsRecord["Inception"] = rr.Inception
|
||||
jsRecord["KeyTag"] = rr.KeyTag
|
||||
jsRecord["Labels"] = rr.Labels
|
||||
jsRecord["OrigTtl"] = rr.OrigTtl
|
||||
jsRecord["Signature"] = rr.Signature
|
||||
jsRecord["SignerName"] = rr.SignerName
|
||||
jsRecord["TypeCovered"] = rr.TypeCovered
|
||||
case *dns.NSEC:
|
||||
jsRecord["NextDomain"] = rr.NextDomain
|
||||
jsRecord["TypeBitMap"] = rr.TypeBitMap
|
||||
case *dns.NSEC3:
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Hash"] = rr.Hash
|
||||
jsRecord["HashLength"] = rr.HashLength
|
||||
jsRecord["Iterations"] = rr.Iterations
|
||||
jsRecord["NextDomain"] = rr.NextDomain
|
||||
jsRecord["Salt"] = rr.Salt
|
||||
jsRecord["SaltLength"] = rr.SaltLength
|
||||
jsRecord["TypeBitMap"] = rr.TypeBitMap
|
||||
case *dns.NSEC3PARAM:
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Hash"] = rr.Hash
|
||||
jsRecord["Iterations"] = rr.Iterations
|
||||
jsRecord["Salt"] = rr.Salt
|
||||
jsRecord["SaltLength"] = rr.SaltLength
|
||||
case *dns.TKEY:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Error"] = rr.Error
|
||||
jsRecord["Expiration"] = rr.Expiration
|
||||
jsRecord["Inception"] = rr.Inception
|
||||
jsRecord["Key"] = rr.Key
|
||||
jsRecord["KeySize"] = rr.KeySize
|
||||
jsRecord["Mode"] = rr.Mode
|
||||
jsRecord["OtherData"] = rr.OtherData
|
||||
jsRecord["OtherLen"] = rr.OtherLen
|
||||
case *dns.TSIG:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Error"] = rr.Error
|
||||
jsRecord["Fudge"] = rr.Fudge
|
||||
jsRecord["MACSize"] = rr.MACSize
|
||||
jsRecord["MAC"] = rr.MAC
|
||||
jsRecord["OrigId"] = rr.OrigId
|
||||
jsRecord["OtherData"] = rr.OtherData
|
||||
jsRecord["OtherLen"] = rr.OtherLen
|
||||
jsRecord["TimeSigned"] = rr.TimeSigned
|
||||
case *dns.IPSECKEY:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["GatewayAddr"] = rr.GatewayAddr.String()
|
||||
jsRecord["GatewayHost"] = rr.GatewayHost
|
||||
jsRecord["GatewayType"] = rr.GatewayType
|
||||
jsRecord["Precedence"] = rr.Precedence
|
||||
jsRecord["PublicKey"] = rr.PublicKey
|
||||
case *dns.KEY:
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Protocol"] = rr.Protocol
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["PublicKey"] = rr.PublicKey
|
||||
case *dns.CDS:
|
||||
jsRecord["KeyTag"] = rr.KeyTag
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["DigestType"] = rr.DigestType
|
||||
jsRecord["Digest"] = rr.Digest
|
||||
case *dns.CDNSKEY:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Protocol"] = rr.Protocol
|
||||
jsRecord["PublicKey"] = rr.PublicKey
|
||||
case *dns.NID:
|
||||
jsRecord["NodeID"] = rr.NodeID
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.L32:
|
||||
jsRecord["Locator32"] = rr.Locator32.String()
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.L64:
|
||||
jsRecord["Locator64"] = rr.Locator64
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.LP:
|
||||
jsRecord["Fqdn"] = rr.Fqdn
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.GPOS:
|
||||
jsRecord["Altitude"] = rr.Altitude
|
||||
jsRecord["Latitude"] = rr.Latitude
|
||||
jsRecord["Longitude"] = rr.Longitude
|
||||
case *dns.RP:
|
||||
jsRecord["Mbox"] = rr.Mbox
|
||||
jsRecord["Txt"] = rr.Txt
|
||||
case *dns.RKEY:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Protocol"] = rr.Protocol
|
||||
jsRecord["PublicKey"] = rr.PublicKey
|
||||
case *dns.SMIMEA:
|
||||
jsRecord["Certificate"] = rr.Certificate
|
||||
jsRecord["MatchingType"] = rr.MatchingType
|
||||
jsRecord["Selector"] = rr.Selector
|
||||
jsRecord["Usage"] = rr.Usage
|
||||
case *dns.AMTRELAY:
|
||||
jsRecord["GatewayAddr"] = rr.GatewayAddr.String()
|
||||
jsRecord["GatewayHost"] = rr.GatewayHost
|
||||
jsRecord["GatewayType"] = rr.GatewayType
|
||||
jsRecord["Precedence"] = rr.Precedence
|
||||
case *dns.AVC:
|
||||
jsRecord["Txt"] = rr.Txt
|
||||
case *dns.URI:
|
||||
jsRecord["Priority"] = rr.Priority
|
||||
jsRecord["Weight"] = rr.Weight
|
||||
jsRecord["Target"] = rr.Target
|
||||
case *dns.EUI48:
|
||||
jsRecord["Address"] = rr.Address
|
||||
case *dns.EUI64:
|
||||
jsRecord["Address"] = rr.Address
|
||||
case *dns.GID:
|
||||
jsRecord["Gid"] = rr.Gid
|
||||
case *dns.UID:
|
||||
jsRecord["Uid"] = rr.Uid
|
||||
case *dns.UINFO:
|
||||
jsRecord["Uinfo"] = rr.Uinfo
|
||||
case *dns.SPF:
|
||||
jsRecord["Txt"] = rr.Txt
|
||||
case *dns.HTTPS:
|
||||
jsRecord["Priority"] = rr.Priority
|
||||
jsRecord["Target"] = rr.Target
|
||||
kvs := rr.Value
|
||||
var jsKvs []map[string]interface{}
|
||||
for _, kv := range kvs {
|
||||
jsKv, err := NewJSSVCBKeyValue(kv)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
jsKvs = append(jsKvs, jsKv)
|
||||
}
|
||||
jsRecord["Value"] = jsKvs
|
||||
case *dns.SVCB:
|
||||
jsRecord["Priority"] = rr.Priority
|
||||
jsRecord["Target"] = rr.Target
|
||||
kvs := rr.Value
|
||||
jsKvs := make([]map[string]interface{}, len(kvs))
|
||||
for i, kv := range kvs {
|
||||
jsKv, err := NewJSSVCBKeyValue(kv)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
jsKvs[i] = jsKv
|
||||
}
|
||||
jsRecord["Value"] = jsKvs
|
||||
case *dns.ZONEMD:
|
||||
jsRecord["Digest"] = rr.Digest
|
||||
jsRecord["Hash"] = rr.Hash
|
||||
jsRecord["Scheme"] = rr.Scheme
|
||||
jsRecord["Serial"] = rr.Serial
|
||||
case *dns.CSYNC:
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Serial"] = rr.Serial
|
||||
jsRecord["TypeBitMap"] = rr.TypeBitMap
|
||||
case *dns.OPENPGPKEY:
|
||||
jsRecord["PublicKey"] = rr.PublicKey
|
||||
case *dns.TALINK:
|
||||
jsRecord["NextName"] = rr.NextName
|
||||
jsRecord["PreviousName"] = rr.PreviousName
|
||||
case *dns.NINFO:
|
||||
jsRecord["ZSData"] = rr.ZSData
|
||||
case *dns.DHCID:
|
||||
jsRecord["Digest"] = rr.Digest
|
||||
case *dns.DNSKEY:
|
||||
jsRecord["Flags"] = rr.Flags
|
||||
jsRecord["Protocol"] = rr.Protocol
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["PublicKey"] = rr.PublicKey
|
||||
case *dns.HIP:
|
||||
jsRecord["Hit"] = rr.Hit
|
||||
jsRecord["HitLength"] = rr.HitLength
|
||||
jsRecord["PublicKey"] = rr.PublicKey
|
||||
jsRecord["PublicKeyAlgorithm"] = rr.PublicKeyAlgorithm
|
||||
jsRecord["PublicKeyLength"] = rr.PublicKeyLength
|
||||
jsRecord["RendezvousServers"] = rr.RendezvousServers
|
||||
case *dns.OPT:
|
||||
jsRecord["Option"] = rr.Option
|
||||
case *dns.NIMLOC:
|
||||
jsRecord["Locator"] = rr.Locator
|
||||
case *dns.EID:
|
||||
jsRecord["Endpoint"] = rr.Endpoint
|
||||
case *dns.NXT:
|
||||
jsRecord["NextDomain"] = rr.NextDomain
|
||||
jsRecord["TypeBitMap"] = rr.TypeBitMap
|
||||
case *dns.PX:
|
||||
jsRecord["Mapx400"] = rr.Mapx400
|
||||
jsRecord["Map822"] = rr.Map822
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.SIG:
|
||||
jsRecord["Algorithm"] = rr.Algorithm
|
||||
jsRecord["Expiration"] = rr.Expiration
|
||||
jsRecord["Inception"] = rr.Inception
|
||||
jsRecord["KeyTag"] = rr.KeyTag
|
||||
jsRecord["Labels"] = rr.Labels
|
||||
jsRecord["OrigTtl"] = rr.OrigTtl
|
||||
jsRecord["Signature"] = rr.Signature
|
||||
jsRecord["SignerName"] = rr.SignerName
|
||||
jsRecord["TypeCovered"] = rr.TypeCovered
|
||||
case *dns.RT:
|
||||
jsRecord["Host"] = rr.Host
|
||||
jsRecord["Preference"] = rr.Preference
|
||||
case *dns.NSAPPTR:
|
||||
jsRecord["Ptr"] = rr.Ptr
|
||||
case *dns.X25:
|
||||
jsRecord["PSDNAddress"] = rr.PSDNAddress
|
||||
case *dns.RFC3597:
|
||||
jsRecord["Rdata"] = rr.Rdata
|
||||
// case *dns.ATMA:
|
||||
// case *dns.WKS:
|
||||
// case *dns.DOA:
|
||||
// case *dns.SINK:
|
||||
default:
|
||||
if header.Rrtype == dns.TypeNone {
|
||||
break
|
||||
}
|
||||
return nil, fmt.Errorf("error creating JSResourceRecord: unknown type: %d", header.Rrtype)
|
||||
}
|
||||
|
||||
return jsRecord, nil
|
||||
}
|
||||
|
||||
func ToRR(jsRecord map[string]interface{}) (rr dns.RR, err error) {
|
||||
jsHeader := jsPropToMap(jsRecord, "Header")
|
||||
|
||||
header := dns.RR_Header{
|
||||
Class: jsPropToUint16(jsHeader, "Class"),
|
||||
Name: jsPropToString(jsHeader, "Name"),
|
||||
Rrtype: jsPropToUint16(jsHeader, "Rrtype"),
|
||||
Ttl: jsPropToUint32(jsHeader, "Ttl"),
|
||||
}
|
||||
|
||||
switch header.Rrtype {
|
||||
case dns.TypeNone:
|
||||
break
|
||||
case dns.TypeA:
|
||||
rr = &dns.A{
|
||||
Hdr: header,
|
||||
A: net.ParseIP(jsPropToString(jsRecord, "A")),
|
||||
}
|
||||
case dns.TypeAAAA:
|
||||
rr = &dns.AAAA{
|
||||
Hdr: header,
|
||||
AAAA: net.ParseIP(jsPropToString(jsRecord, "AAAA")),
|
||||
}
|
||||
case dns.TypeAPL:
|
||||
jsPrefixes := jsRecord["Prefixes"].([]map[string]interface{})
|
||||
prefixes := make([]dns.APLPrefix, len(jsPrefixes))
|
||||
for i, jsPrefix := range jsPrefixes {
|
||||
jsNetwork := jsPrefix["Network"].(string)
|
||||
_, network, err := net.ParseCIDR(jsNetwork)
|
||||
if err != nil {
|
||||
log.Error("error parsing CIDR: %s", jsNetwork)
|
||||
continue
|
||||
}
|
||||
prefixes[i] = dns.APLPrefix{
|
||||
Negation: jsPrefix["Negation"].(bool),
|
||||
Network: *network,
|
||||
}
|
||||
}
|
||||
rr = &dns.APL{
|
||||
Hdr: header,
|
||||
Prefixes: prefixes,
|
||||
}
|
||||
case dns.TypeCNAME:
|
||||
rr = &dns.CNAME{
|
||||
Hdr: header,
|
||||
Target: jsPropToString(jsRecord, "Target"),
|
||||
}
|
||||
case dns.TypeMB:
|
||||
rr = &dns.MB{
|
||||
Hdr: header,
|
||||
Mb: jsPropToString(jsRecord, "Mb"),
|
||||
}
|
||||
case dns.TypeMD:
|
||||
rr = &dns.MD{
|
||||
Hdr: header,
|
||||
Md: jsPropToString(jsRecord, "Md"),
|
||||
}
|
||||
case dns.TypeMF:
|
||||
rr = &dns.MF{
|
||||
Hdr: header,
|
||||
Mf: jsPropToString(jsRecord, "Mf"),
|
||||
}
|
||||
case dns.TypeMG:
|
||||
rr = &dns.MG{
|
||||
Hdr: header,
|
||||
Mg: jsPropToString(jsRecord, "Mg"),
|
||||
}
|
||||
case dns.TypeMR:
|
||||
rr = &dns.MR{
|
||||
Hdr: header,
|
||||
Mr: jsPropToString(jsRecord, "Mr"),
|
||||
}
|
||||
case dns.TypeMX:
|
||||
rr = &dns.MX{
|
||||
Hdr: header,
|
||||
Mx: jsPropToString(jsRecord, "Mx"),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
}
|
||||
case dns.TypeNULL:
|
||||
rr = &dns.NULL{
|
||||
Hdr: header,
|
||||
Data: jsPropToString(jsRecord, "Data"),
|
||||
}
|
||||
case dns.TypeSOA:
|
||||
rr = &dns.SOA{
|
||||
Hdr: header,
|
||||
Expire: jsPropToUint32(jsRecord, "Expire"),
|
||||
Mbox: jsPropToString(jsRecord, "Mbox"),
|
||||
Minttl: jsPropToUint32(jsRecord, "Minttl"),
|
||||
Ns: jsPropToString(jsRecord, "Ns"),
|
||||
Refresh: jsPropToUint32(jsRecord, "Refresh"),
|
||||
Retry: jsPropToUint32(jsRecord, "Retry"),
|
||||
Serial: jsPropToUint32(jsRecord, "Serial"),
|
||||
}
|
||||
case dns.TypeTXT:
|
||||
rr = &dns.TXT{
|
||||
Hdr: header,
|
||||
Txt: jsPropToStringArray(jsRecord, "Txt"),
|
||||
}
|
||||
case dns.TypeSRV:
|
||||
rr = &dns.SRV{
|
||||
Hdr: header,
|
||||
Port: jsPropToUint16(jsRecord, "Port"),
|
||||
Priority: jsPropToUint16(jsRecord, "Priority"),
|
||||
Target: jsPropToString(jsRecord, "Target"),
|
||||
Weight: jsPropToUint16(jsRecord, "Weight"),
|
||||
}
|
||||
case dns.TypePTR:
|
||||
rr = &dns.PTR{
|
||||
Hdr: header,
|
||||
Ptr: jsPropToString(jsRecord, "Ptr"),
|
||||
}
|
||||
case dns.TypeNS:
|
||||
rr = &dns.NS{
|
||||
Hdr: header,
|
||||
Ns: jsPropToString(jsRecord, "Ns"),
|
||||
}
|
||||
case dns.TypeDNAME:
|
||||
rr = &dns.DNAME{
|
||||
Hdr: header,
|
||||
Target: jsPropToString(jsRecord, "Target"),
|
||||
}
|
||||
case dns.TypeAFSDB:
|
||||
rr = &dns.AFSDB{
|
||||
Hdr: header,
|
||||
Hostname: jsPropToString(jsRecord, "Hostname"),
|
||||
Subtype: jsPropToUint16(jsRecord, "Subtype"),
|
||||
}
|
||||
case dns.TypeCAA:
|
||||
rr = &dns.CAA{
|
||||
Hdr: header,
|
||||
Flag: jsPropToUint8(jsRecord, "Flag"),
|
||||
Tag: jsPropToString(jsRecord, "Tag"),
|
||||
Value: jsPropToString(jsRecord, "Value"),
|
||||
}
|
||||
case dns.TypeHINFO:
|
||||
rr = &dns.HINFO{
|
||||
Hdr: header,
|
||||
Cpu: jsPropToString(jsRecord, "Cpu"),
|
||||
Os: jsPropToString(jsRecord, "Os"),
|
||||
}
|
||||
case dns.TypeMINFO:
|
||||
rr = &dns.MINFO{
|
||||
Hdr: header,
|
||||
Email: jsPropToString(jsRecord, "Email"),
|
||||
Rmail: jsPropToString(jsRecord, "Rmail"),
|
||||
}
|
||||
case dns.TypeISDN:
|
||||
rr = &dns.ISDN{
|
||||
Hdr: header,
|
||||
Address: jsPropToString(jsRecord, "Address"),
|
||||
SubAddress: jsPropToString(jsRecord, "SubAddress"),
|
||||
}
|
||||
case dns.TypeKX:
|
||||
rr = &dns.KX{
|
||||
Hdr: header,
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
Exchanger: jsPropToString(jsRecord, "Exchanger"),
|
||||
}
|
||||
case dns.TypeLOC:
|
||||
rr = &dns.LOC{
|
||||
Hdr: header,
|
||||
Version: jsPropToUint8(jsRecord, "Version"),
|
||||
Size: jsPropToUint8(jsRecord, "Size"),
|
||||
HorizPre: jsPropToUint8(jsRecord, "HorizPre"),
|
||||
VertPre: jsPropToUint8(jsRecord, "VertPre"),
|
||||
Latitude: jsPropToUint32(jsRecord, "Latitude"),
|
||||
Longitude: jsPropToUint32(jsRecord, "Longitude"),
|
||||
Altitude: jsPropToUint32(jsRecord, "Altitude"),
|
||||
}
|
||||
case dns.TypeSSHFP:
|
||||
rr = &dns.SSHFP{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
FingerPrint: jsPropToString(jsRecord, "FingerPrint"),
|
||||
Type: jsPropToUint8(jsRecord, "Type"),
|
||||
}
|
||||
case dns.TypeTLSA:
|
||||
rr = &dns.TLSA{
|
||||
Hdr: header,
|
||||
Certificate: jsPropToString(jsRecord, "Certificate"),
|
||||
MatchingType: jsPropToUint8(jsRecord, "MatchingType"),
|
||||
Selector: jsPropToUint8(jsRecord, "Selector"),
|
||||
Usage: jsPropToUint8(jsRecord, "Usage"),
|
||||
}
|
||||
case dns.TypeCERT:
|
||||
rr = &dns.CERT{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Certificate: jsPropToString(jsRecord, "Certificate"),
|
||||
KeyTag: jsPropToUint16(jsRecord, "KeyTag"),
|
||||
Type: jsPropToUint16(jsRecord, "Type"),
|
||||
}
|
||||
case dns.TypeDS:
|
||||
rr = &dns.DS{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Digest: jsPropToString(jsRecord, "Digest"),
|
||||
DigestType: jsPropToUint8(jsRecord, "DigestType"),
|
||||
KeyTag: jsPropToUint16(jsRecord, "KeyTag"),
|
||||
}
|
||||
case dns.TypeNAPTR:
|
||||
rr = &dns.NAPTR{
|
||||
Hdr: header,
|
||||
Flags: jsPropToString(jsRecord, "Flags"),
|
||||
Order: jsPropToUint16(jsRecord, "Order"),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
Regexp: jsPropToString(jsRecord, "Regexp"),
|
||||
Replacement: jsPropToString(jsRecord, "Replacement"),
|
||||
Service: jsPropToString(jsRecord, "Service"),
|
||||
}
|
||||
case dns.TypeRRSIG:
|
||||
rr = &dns.RRSIG{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Expiration: jsPropToUint32(jsRecord, "Expiration"),
|
||||
Inception: jsPropToUint32(jsRecord, "Inception"),
|
||||
KeyTag: jsPropToUint16(jsRecord, "KeyTag"),
|
||||
Labels: jsPropToUint8(jsRecord, "Labels"),
|
||||
OrigTtl: jsPropToUint32(jsRecord, "OrigTtl"),
|
||||
Signature: jsPropToString(jsRecord, "Signature"),
|
||||
SignerName: jsPropToString(jsRecord, "SignerName"),
|
||||
TypeCovered: jsPropToUint16(jsRecord, "TypeCovered"),
|
||||
}
|
||||
case dns.TypeNSEC:
|
||||
rr = &dns.NSEC{
|
||||
Hdr: header,
|
||||
NextDomain: jsPropToString(jsRecord, "NextDomain"),
|
||||
TypeBitMap: jsPropToUint16Array(jsRecord, "TypeBitMap"),
|
||||
}
|
||||
case dns.TypeNSEC3:
|
||||
rr = &dns.NSEC3{
|
||||
Hdr: header,
|
||||
Flags: jsPropToUint8(jsRecord, "Flags"),
|
||||
Hash: jsPropToUint8(jsRecord, "Hash"),
|
||||
HashLength: jsPropToUint8(jsRecord, "HashLength"),
|
||||
Iterations: jsPropToUint16(jsRecord, "Iterations"),
|
||||
NextDomain: jsPropToString(jsRecord, "NextDomain"),
|
||||
Salt: jsPropToString(jsRecord, "Salt"),
|
||||
SaltLength: jsPropToUint8(jsRecord, "SaltLength"),
|
||||
TypeBitMap: jsPropToUint16Array(jsRecord, "TypeBitMap"),
|
||||
}
|
||||
case dns.TypeNSEC3PARAM:
|
||||
rr = &dns.NSEC3PARAM{
|
||||
Hdr: header,
|
||||
Flags: jsPropToUint8(jsRecord, "Flags"),
|
||||
Hash: jsPropToUint8(jsRecord, "Hash"),
|
||||
Iterations: jsPropToUint16(jsRecord, "Iterations"),
|
||||
Salt: jsPropToString(jsRecord, "Salt"),
|
||||
SaltLength: jsPropToUint8(jsRecord, "SaltLength"),
|
||||
}
|
||||
case dns.TypeTKEY:
|
||||
rr = &dns.TKEY{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToString(jsRecord, "Algorithm"),
|
||||
Error: jsPropToUint16(jsRecord, "Error"),
|
||||
Expiration: jsPropToUint32(jsRecord, "Expiration"),
|
||||
Inception: jsPropToUint32(jsRecord, "Inception"),
|
||||
Key: jsPropToString(jsRecord, "Key"),
|
||||
KeySize: jsPropToUint16(jsRecord, "KeySize"),
|
||||
Mode: jsPropToUint16(jsRecord, "Mode"),
|
||||
OtherData: jsPropToString(jsRecord, "OtherData"),
|
||||
OtherLen: jsPropToUint16(jsRecord, "OtherLen"),
|
||||
}
|
||||
case dns.TypeTSIG:
|
||||
rr = &dns.TSIG{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToString(jsRecord, "Algorithm"),
|
||||
Error: jsPropToUint16(jsRecord, "Error"),
|
||||
Fudge: jsPropToUint16(jsRecord, "Fudge"),
|
||||
MACSize: jsPropToUint16(jsRecord, "MACSize"),
|
||||
MAC: jsPropToString(jsRecord, "MAC"),
|
||||
OrigId: jsPropToUint16(jsRecord, "OrigId"),
|
||||
OtherData: jsPropToString(jsRecord, "OtherData"),
|
||||
OtherLen: jsPropToUint16(jsRecord, "OtherLen"),
|
||||
TimeSigned: jsPropToUint64(jsRecord, "TimeSigned"),
|
||||
}
|
||||
case dns.TypeIPSECKEY:
|
||||
rr = &dns.IPSECKEY{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
GatewayAddr: net.IP(jsPropToString(jsRecord, "GatewayAddr")),
|
||||
GatewayHost: jsPropToString(jsRecord, "GatewayHost"),
|
||||
GatewayType: jsPropToUint8(jsRecord, "GatewayType"),
|
||||
Precedence: jsPropToUint8(jsRecord, "Precedence"),
|
||||
PublicKey: jsPropToString(jsRecord, "PublicKey"),
|
||||
}
|
||||
case dns.TypeKEY:
|
||||
rr = &dns.KEY{
|
||||
DNSKEY: dns.DNSKEY{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Flags: jsPropToUint16(jsRecord, "Flags"),
|
||||
Protocol: jsPropToUint8(jsRecord, "Protocol"),
|
||||
PublicKey: jsPropToString(jsRecord, "PublicKey"),
|
||||
},
|
||||
}
|
||||
case dns.TypeCDS:
|
||||
rr = &dns.CDS{
|
||||
DS: dns.DS{
|
||||
Hdr: header,
|
||||
KeyTag: jsPropToUint16(jsRecord, "KeyTag"),
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
DigestType: jsPropToUint8(jsRecord, "DigestType"),
|
||||
Digest: jsPropToString(jsRecord, "Digest"),
|
||||
},
|
||||
}
|
||||
case dns.TypeCDNSKEY:
|
||||
rr = &dns.CDNSKEY{
|
||||
DNSKEY: dns.DNSKEY{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Flags: jsPropToUint16(jsRecord, "Flags"),
|
||||
Protocol: jsPropToUint8(jsRecord, "Protocol"),
|
||||
PublicKey: jsPropToString(jsRecord, "PublicKey"),
|
||||
},
|
||||
}
|
||||
case dns.TypeNID:
|
||||
rr = &dns.NID{
|
||||
Hdr: header,
|
||||
NodeID: jsPropToUint64(jsRecord, "NodeID"),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
}
|
||||
case dns.TypeL32:
|
||||
rr = &dns.L32{
|
||||
Hdr: header,
|
||||
Locator32: net.IP(jsPropToString(jsRecord, "Locator32")),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
}
|
||||
case dns.TypeL64:
|
||||
rr = &dns.L64{
|
||||
Hdr: header,
|
||||
Locator64: jsPropToUint64(jsRecord, "Locator64"),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
}
|
||||
case dns.TypeLP:
|
||||
rr = &dns.LP{
|
||||
Hdr: header,
|
||||
Fqdn: jsPropToString(jsRecord, "Fqdn"),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
}
|
||||
case dns.TypeGPOS:
|
||||
rr = &dns.GPOS{
|
||||
Hdr: header,
|
||||
Altitude: jsPropToString(jsRecord, "Altitude"),
|
||||
Latitude: jsPropToString(jsRecord, "Latitude"),
|
||||
Longitude: jsPropToString(jsRecord, "Longitude"),
|
||||
}
|
||||
case dns.TypeRP:
|
||||
rr = &dns.RP{
|
||||
Hdr: header,
|
||||
Mbox: jsPropToString(jsRecord, "Mbox"),
|
||||
Txt: jsPropToString(jsRecord, "Txt"),
|
||||
}
|
||||
case dns.TypeRKEY:
|
||||
rr = &dns.RKEY{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Flags: jsPropToUint16(jsRecord, "Flags"),
|
||||
Protocol: jsPropToUint8(jsRecord, "Protocol"),
|
||||
PublicKey: jsPropToString(jsRecord, "PublicKey"),
|
||||
}
|
||||
case dns.TypeSMIMEA:
|
||||
rr = &dns.SMIMEA{
|
||||
Hdr: header,
|
||||
Certificate: jsPropToString(jsRecord, "Certificate"),
|
||||
MatchingType: jsPropToUint8(jsRecord, "MatchingType"),
|
||||
Selector: jsPropToUint8(jsRecord, "Selector"),
|
||||
Usage: jsPropToUint8(jsRecord, "Usage"),
|
||||
}
|
||||
case dns.TypeAMTRELAY:
|
||||
rr = &dns.AMTRELAY{
|
||||
Hdr: header,
|
||||
GatewayAddr: net.IP(jsPropToString(jsRecord, "GatewayAddr")),
|
||||
GatewayHost: jsPropToString(jsRecord, "GatewayHost"),
|
||||
GatewayType: jsPropToUint8(jsRecord, "GatewayType"),
|
||||
Precedence: jsPropToUint8(jsRecord, "Precedence"),
|
||||
}
|
||||
case dns.TypeAVC:
|
||||
rr = &dns.AVC{
|
||||
Hdr: header,
|
||||
Txt: jsPropToStringArray(jsRecord, "Txt"),
|
||||
}
|
||||
case dns.TypeURI:
|
||||
rr = &dns.URI{
|
||||
Hdr: header,
|
||||
Priority: jsPropToUint16(jsRecord, "Priority"),
|
||||
Weight: jsPropToUint16(jsRecord, "Weight"),
|
||||
Target: jsPropToString(jsRecord, "Target"),
|
||||
}
|
||||
case dns.TypeEUI48:
|
||||
rr = &dns.EUI48{
|
||||
Hdr: header,
|
||||
Address: jsPropToUint64(jsRecord, "Address"),
|
||||
}
|
||||
case dns.TypeEUI64:
|
||||
rr = &dns.EUI64{
|
||||
Hdr: header,
|
||||
Address: jsPropToUint64(jsRecord, "Address"),
|
||||
}
|
||||
case dns.TypeGID:
|
||||
rr = &dns.GID{
|
||||
Hdr: header,
|
||||
Gid: jsPropToUint32(jsRecord, "Gid"),
|
||||
}
|
||||
case dns.TypeUID:
|
||||
rr = &dns.UID{
|
||||
Hdr: header,
|
||||
Uid: jsPropToUint32(jsRecord, "Uid"),
|
||||
}
|
||||
case dns.TypeUINFO:
|
||||
rr = &dns.UINFO{
|
||||
Hdr: header,
|
||||
Uinfo: jsPropToString(jsRecord, "Uinfo"),
|
||||
}
|
||||
case dns.TypeSPF:
|
||||
rr = &dns.SPF{
|
||||
Hdr: header,
|
||||
Txt: jsPropToStringArray(jsRecord, "Txt"),
|
||||
}
|
||||
case dns.TypeHTTPS:
|
||||
jsKvs := jsPropToMapArray(jsRecord, "Value")
|
||||
var kvs []dns.SVCBKeyValue
|
||||
for _, jsKv := range jsKvs {
|
||||
kv, err := ToSVCBKeyValue(jsKv)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
kvs = append(kvs, kv)
|
||||
}
|
||||
rr = &dns.HTTPS{
|
||||
SVCB: dns.SVCB{
|
||||
Hdr: header,
|
||||
Priority: jsPropToUint16(jsRecord, "Priority"),
|
||||
Target: jsPropToString(jsRecord, "Target"),
|
||||
Value: kvs,
|
||||
},
|
||||
}
|
||||
case dns.TypeSVCB:
|
||||
jsKvs := jsPropToMapArray(jsRecord, "Value")
|
||||
var kvs []dns.SVCBKeyValue
|
||||
for _, jsKv := range jsKvs {
|
||||
kv, err := ToSVCBKeyValue(jsKv)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
kvs = append(kvs, kv)
|
||||
}
|
||||
rr = &dns.SVCB{
|
||||
Hdr: header,
|
||||
Priority: jsPropToUint16(jsRecord, "Priority"),
|
||||
Target: jsPropToString(jsRecord, "Target"),
|
||||
Value: kvs,
|
||||
}
|
||||
case dns.TypeZONEMD:
|
||||
rr = &dns.ZONEMD{
|
||||
Hdr: header,
|
||||
Digest: jsPropToString(jsRecord, "Digest"),
|
||||
Hash: jsPropToUint8(jsRecord, "Hash"),
|
||||
Scheme: jsPropToUint8(jsRecord, "Scheme"),
|
||||
Serial: jsPropToUint32(jsRecord, "Serial"),
|
||||
}
|
||||
case dns.TypeCSYNC:
|
||||
rr = &dns.CSYNC{
|
||||
Hdr: header,
|
||||
Flags: jsPropToUint16(jsRecord, "Flags"),
|
||||
Serial: jsPropToUint32(jsRecord, "Serial"),
|
||||
TypeBitMap: jsPropToUint16Array(jsRecord, "TypeBitMap"),
|
||||
}
|
||||
case dns.TypeOPENPGPKEY:
|
||||
rr = &dns.OPENPGPKEY{
|
||||
Hdr: header,
|
||||
PublicKey: jsPropToString(jsRecord, "PublicKey"),
|
||||
}
|
||||
case dns.TypeTALINK:
|
||||
rr = &dns.TALINK{
|
||||
Hdr: header,
|
||||
NextName: jsPropToString(jsRecord, "NextName"),
|
||||
PreviousName: jsPropToString(jsRecord, "PreviousName"),
|
||||
}
|
||||
case dns.TypeNINFO:
|
||||
rr = &dns.NINFO{
|
||||
Hdr: header,
|
||||
ZSData: jsPropToStringArray(jsRecord, "ZSData"),
|
||||
}
|
||||
case dns.TypeDHCID:
|
||||
rr = &dns.DHCID{
|
||||
Hdr: header,
|
||||
Digest: jsPropToString(jsRecord, "Digest"),
|
||||
}
|
||||
case dns.TypeDNSKEY:
|
||||
rr = &dns.DNSKEY{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Flags: jsPropToUint16(jsRecord, "Flags"),
|
||||
Protocol: jsPropToUint8(jsRecord, "Protocol"),
|
||||
PublicKey: jsPropToString(jsRecord, "PublicKey"),
|
||||
}
|
||||
case dns.TypeHIP:
|
||||
rr = &dns.HIP{
|
||||
Hdr: header,
|
||||
Hit: jsPropToString(jsRecord, "Hit"),
|
||||
HitLength: jsPropToUint8(jsRecord, "HitLength"),
|
||||
PublicKey: jsPropToString(jsRecord, "PublicKey"),
|
||||
PublicKeyAlgorithm: jsPropToUint8(jsRecord, "PublicKeyAlgorithm"),
|
||||
PublicKeyLength: jsPropToUint16(jsRecord, "PublicKeyLength"),
|
||||
RendezvousServers: jsPropToStringArray(jsRecord, "RendezvousServers"),
|
||||
}
|
||||
case dns.TypeOPT:
|
||||
jsOptions := jsPropToMapArray(jsRecord, "Option")
|
||||
var options []dns.EDNS0
|
||||
for _, jsOption := range jsOptions {
|
||||
option, err := ToEDNS0(jsOption)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
options = append(options, option)
|
||||
}
|
||||
rr = &dns.OPT{
|
||||
Hdr: header,
|
||||
Option: options,
|
||||
}
|
||||
case dns.TypeNIMLOC:
|
||||
rr = &dns.NIMLOC{
|
||||
Hdr: header,
|
||||
Locator: jsPropToString(jsRecord, "Locator"),
|
||||
}
|
||||
case dns.TypeEID:
|
||||
rr = &dns.EID{
|
||||
Hdr: header,
|
||||
Endpoint: jsPropToString(jsRecord, "Endpoint"),
|
||||
}
|
||||
case dns.TypeNXT:
|
||||
rr = &dns.NXT{
|
||||
NSEC: dns.NSEC{
|
||||
Hdr: header,
|
||||
NextDomain: jsPropToString(jsRecord, "NextDomain"),
|
||||
TypeBitMap: jsPropToUint16Array(jsRecord, "TypeBitMap"),
|
||||
},
|
||||
}
|
||||
case dns.TypePX:
|
||||
rr = &dns.PX{
|
||||
Hdr: header,
|
||||
Mapx400: jsPropToString(jsRecord, "Mapx400"),
|
||||
Map822: jsPropToString(jsRecord, "Map822"),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
}
|
||||
case dns.TypeSIG:
|
||||
rr = &dns.SIG{
|
||||
RRSIG: dns.RRSIG{
|
||||
Hdr: header,
|
||||
Algorithm: jsPropToUint8(jsRecord, "Algorithm"),
|
||||
Expiration: jsPropToUint32(jsRecord, "Expiration"),
|
||||
Inception: jsPropToUint32(jsRecord, "Inception"),
|
||||
KeyTag: jsPropToUint16(jsRecord, "KeyTag"),
|
||||
Labels: jsPropToUint8(jsRecord, "Labels"),
|
||||
OrigTtl: jsPropToUint32(jsRecord, "OrigTtl"),
|
||||
Signature: jsPropToString(jsRecord, "Signature"),
|
||||
SignerName: jsPropToString(jsRecord, "SignerName"),
|
||||
TypeCovered: jsPropToUint16(jsRecord, "TypeCovered"),
|
||||
},
|
||||
}
|
||||
case dns.TypeRT:
|
||||
rr = &dns.RT{
|
||||
Hdr: header,
|
||||
Host: jsPropToString(jsRecord, "Host"),
|
||||
Preference: jsPropToUint16(jsRecord, "Preference"),
|
||||
}
|
||||
case dns.TypeNSAPPTR:
|
||||
rr = &dns.NSAPPTR{
|
||||
Hdr: header,
|
||||
Ptr: jsPropToString(jsRecord, "Ptr"),
|
||||
}
|
||||
case dns.TypeX25:
|
||||
rr = &dns.X25{
|
||||
Hdr: header,
|
||||
PSDNAddress: jsPropToString(jsRecord, "PSDNAddress"),
|
||||
}
|
||||
// case dns.TypeATMA:
|
||||
// case dns.TypeWKS:
|
||||
// case dns.TypeDOA:
|
||||
// case dns.TypeSINK:
|
||||
default:
|
||||
if rdata, ok := jsRecord["Rdata"].(string); ok {
|
||||
rr = &dns.RFC3597{
|
||||
Hdr: header,
|
||||
Rdata: rdata,
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("error converting to dns.RR: unknown type: %d", header.Rrtype)
|
||||
}
|
||||
}
|
||||
|
||||
return rr, nil
|
||||
}
|
208
modules/dns_proxy/dns_proxy_js_record_edns0.go
Normal file
208
modules/dns_proxy/dns_proxy_js_record_edns0.go
Normal file
|
@ -0,0 +1,208 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/log"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func NewJSEDNS0(e dns.EDNS0) (jsEDNS0 map[string]interface{}, err error) {
|
||||
option := e.Option()
|
||||
|
||||
jsEDNS0 = map[string]interface{}{
|
||||
"Option": option,
|
||||
}
|
||||
|
||||
var jsVal map[string]interface{}
|
||||
|
||||
switch opt := e.(type) {
|
||||
case *dns.EDNS0_LLQ:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Error": opt.Error,
|
||||
"Id": opt.Id,
|
||||
"LeaseLife": opt.LeaseLife,
|
||||
"Opcode": opt.Opcode,
|
||||
"Version": opt.Version,
|
||||
}
|
||||
case *dns.EDNS0_UL:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Lease": opt.Lease,
|
||||
"KeyLease": opt.KeyLease,
|
||||
}
|
||||
case *dns.EDNS0_NSID:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Nsid": opt.Nsid,
|
||||
}
|
||||
case *dns.EDNS0_ESU:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Uri": opt.Uri,
|
||||
}
|
||||
case *dns.EDNS0_DAU:
|
||||
jsVal = map[string]interface{}{
|
||||
"AlgCode": opt.AlgCode,
|
||||
"Code": opt.Code,
|
||||
}
|
||||
case *dns.EDNS0_DHU:
|
||||
jsVal = map[string]interface{}{
|
||||
"AlgCode": opt.AlgCode,
|
||||
"Code": opt.Code,
|
||||
}
|
||||
case *dns.EDNS0_N3U:
|
||||
jsVal = map[string]interface{}{
|
||||
"AlgCode": opt.AlgCode,
|
||||
"Code": opt.Code,
|
||||
}
|
||||
case *dns.EDNS0_SUBNET:
|
||||
jsVal = map[string]interface{}{
|
||||
"Address": opt.Address.String(),
|
||||
"Code": opt.Code,
|
||||
"Family": opt.Family,
|
||||
"SourceNetmask": opt.SourceNetmask,
|
||||
"SourceScope": opt.SourceScope,
|
||||
}
|
||||
case *dns.EDNS0_EXPIRE:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Empty": opt.Empty,
|
||||
"Expire": opt.Expire,
|
||||
}
|
||||
case *dns.EDNS0_COOKIE:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Cookie": opt.Cookie,
|
||||
}
|
||||
case *dns.EDNS0_TCP_KEEPALIVE:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Length": opt.Length,
|
||||
"Timeout": opt.Timeout,
|
||||
}
|
||||
case *dns.EDNS0_PADDING:
|
||||
jsVal = map[string]interface{}{
|
||||
"Padding": string(opt.Padding),
|
||||
}
|
||||
case *dns.EDNS0_EDE:
|
||||
jsVal = map[string]interface{}{
|
||||
"ExtraText": opt.ExtraText,
|
||||
"InfoCode": opt.InfoCode,
|
||||
}
|
||||
case *dns.EDNS0_LOCAL:
|
||||
jsVal = map[string]interface{}{
|
||||
"Code": opt.Code,
|
||||
"Data": string(opt.Data),
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported EDNS0 option: %d", option)
|
||||
}
|
||||
|
||||
jsEDNS0["Value"] = jsVal
|
||||
|
||||
return jsEDNS0, nil
|
||||
}
|
||||
|
||||
func ToEDNS0(jsEDNS0 map[string]interface{}) (e dns.EDNS0, err error) {
|
||||
option := jsPropToUint16(jsEDNS0, "Option")
|
||||
|
||||
jsVal := jsPropToMap(jsEDNS0, "Value")
|
||||
|
||||
switch option {
|
||||
case dns.EDNS0LLQ:
|
||||
e = &dns.EDNS0_LLQ{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Error: jsPropToUint16(jsVal, "Error"),
|
||||
Id: jsPropToUint64(jsVal, "Id"),
|
||||
LeaseLife: jsPropToUint32(jsVal, "LeaseLife"),
|
||||
Opcode: jsPropToUint16(jsVal, "Opcode"),
|
||||
Version: jsPropToUint16(jsVal, "Version"),
|
||||
}
|
||||
case dns.EDNS0UL:
|
||||
e = &dns.EDNS0_UL{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Lease: jsPropToUint32(jsVal, "Lease"),
|
||||
KeyLease: jsPropToUint32(jsVal, "KeyLease"),
|
||||
}
|
||||
case dns.EDNS0NSID:
|
||||
e = &dns.EDNS0_NSID{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Nsid: jsPropToString(jsVal, "Nsid"),
|
||||
}
|
||||
case dns.EDNS0ESU:
|
||||
e = &dns.EDNS0_ESU{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Uri: jsPropToString(jsVal, "Uri"),
|
||||
}
|
||||
case dns.EDNS0DAU:
|
||||
e = &dns.EDNS0_DAU{
|
||||
AlgCode: jsPropToUint8Array(jsVal, "AlgCode"),
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
}
|
||||
case dns.EDNS0DHU:
|
||||
e = &dns.EDNS0_DHU{
|
||||
AlgCode: jsPropToUint8Array(jsVal, "AlgCode"),
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
}
|
||||
case dns.EDNS0N3U:
|
||||
e = &dns.EDNS0_N3U{
|
||||
AlgCode: jsPropToUint8Array(jsVal, "AlgCode"),
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
}
|
||||
case dns.EDNS0SUBNET:
|
||||
e = &dns.EDNS0_SUBNET{
|
||||
Address: net.ParseIP(jsPropToString(jsVal, "Address")),
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Family: jsPropToUint16(jsVal, "Family"),
|
||||
SourceNetmask: jsPropToUint8(jsVal, "SourceNetmask"),
|
||||
SourceScope: jsPropToUint8(jsVal, "SourceScope"),
|
||||
}
|
||||
case dns.EDNS0EXPIRE:
|
||||
if empty, ok := jsVal["Empty"].(bool); !ok {
|
||||
log.Error("invalid or missing EDNS0_EXPIRE.Empty bool value, skipping field.")
|
||||
e = &dns.EDNS0_EXPIRE{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Expire: jsPropToUint32(jsVal, "Expire"),
|
||||
}
|
||||
} else {
|
||||
e = &dns.EDNS0_EXPIRE{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Expire: jsPropToUint32(jsVal, "Expire"),
|
||||
Empty: empty,
|
||||
}
|
||||
}
|
||||
case dns.EDNS0COOKIE:
|
||||
e = &dns.EDNS0_COOKIE{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Cookie: jsPropToString(jsVal, "Cookie"),
|
||||
}
|
||||
case dns.EDNS0TCPKEEPALIVE:
|
||||
e = &dns.EDNS0_TCP_KEEPALIVE{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Length: jsPropToUint16(jsVal, "Length"),
|
||||
Timeout: jsPropToUint16(jsVal, "Timeout"),
|
||||
}
|
||||
case dns.EDNS0PADDING:
|
||||
e = &dns.EDNS0_PADDING{
|
||||
Padding: []byte(jsPropToString(jsVal, "Padding")),
|
||||
}
|
||||
case dns.EDNS0EDE:
|
||||
e = &dns.EDNS0_EDE{
|
||||
ExtraText: jsPropToString(jsVal, "ExtraText"),
|
||||
InfoCode: jsPropToUint16(jsVal, "InfoCode"),
|
||||
}
|
||||
case dns.EDNS0LOCALSTART, dns.EDNS0LOCALEND, 0x8000:
|
||||
// _DO = 0x8000
|
||||
e = &dns.EDNS0_LOCAL{
|
||||
Code: jsPropToUint16(jsVal, "Code"),
|
||||
Data: []byte(jsPropToString(jsVal, "Data")),
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported EDNS0 option: %d", option)
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
127
modules/dns_proxy/dns_proxy_js_record_svcb.go
Normal file
127
modules/dns_proxy/dns_proxy_js_record_svcb.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/bettercap/bettercap/v2/log"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func NewJSSVCBKeyValue(kv dns.SVCBKeyValue) (map[string]interface{}, error) {
|
||||
key := kv.Key()
|
||||
|
||||
jsKv := map[string]interface{}{
|
||||
"Key": uint16(key),
|
||||
}
|
||||
|
||||
switch v := kv.(type) {
|
||||
case *dns.SVCBAlpn:
|
||||
jsKv["Alpn"] = v.Alpn
|
||||
case *dns.SVCBNoDefaultAlpn:
|
||||
break
|
||||
case *dns.SVCBECHConfig:
|
||||
jsKv["ECH"] = string(v.ECH)
|
||||
case *dns.SVCBPort:
|
||||
jsKv["Port"] = v.Port
|
||||
case *dns.SVCBIPv4Hint:
|
||||
ips := v.Hint
|
||||
jsIps := make([]string, len(ips))
|
||||
for i, ip := range ips {
|
||||
jsIps[i] = ip.String()
|
||||
}
|
||||
jsKv["Hint"] = jsIps
|
||||
case *dns.SVCBIPv6Hint:
|
||||
ips := v.Hint
|
||||
jsIps := make([]string, len(ips))
|
||||
for i, ip := range ips {
|
||||
jsIps[i] = ip.String()
|
||||
}
|
||||
jsKv["Hint"] = jsIps
|
||||
case *dns.SVCBDoHPath:
|
||||
jsKv["Template"] = v.Template
|
||||
case *dns.SVCBOhttp:
|
||||
break
|
||||
case *dns.SVCBMandatory:
|
||||
keys := v.Code
|
||||
jsKeys := make([]uint16, len(keys))
|
||||
for i, _key := range keys {
|
||||
jsKeys[i] = uint16(_key)
|
||||
}
|
||||
jsKv["Code"] = jsKeys
|
||||
default:
|
||||
return nil, fmt.Errorf("error creating JSSVCBKeyValue: unknown key: %d", key)
|
||||
}
|
||||
|
||||
return jsKv, nil
|
||||
}
|
||||
|
||||
func ToSVCBKeyValue(jsKv map[string]interface{}) (dns.SVCBKeyValue, error) {
|
||||
var kv dns.SVCBKeyValue
|
||||
|
||||
key := dns.SVCBKey(jsPropToUint16(jsKv, "Key"))
|
||||
|
||||
switch key {
|
||||
case dns.SVCB_ALPN:
|
||||
kv = &dns.SVCBAlpn{
|
||||
Alpn: jsPropToStringArray(jsKv, "Value"),
|
||||
}
|
||||
case dns.SVCB_NO_DEFAULT_ALPN:
|
||||
kv = &dns.SVCBNoDefaultAlpn{}
|
||||
case dns.SVCB_ECHCONFIG:
|
||||
kv = &dns.SVCBECHConfig{
|
||||
ECH: []byte(jsPropToString(jsKv, "Value")),
|
||||
}
|
||||
case dns.SVCB_PORT:
|
||||
kv = &dns.SVCBPort{
|
||||
Port: jsPropToUint16(jsKv, "Value"),
|
||||
}
|
||||
case dns.SVCB_IPV4HINT:
|
||||
jsIps := jsPropToStringArray(jsKv, "Value")
|
||||
var ips []net.IP
|
||||
for _, jsIp := range jsIps {
|
||||
ip := net.ParseIP(jsIp)
|
||||
if ip == nil {
|
||||
log.Error("error converting to SVCBKeyValue: invalid IPv4Hint IP: %s", jsIp)
|
||||
continue
|
||||
}
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
kv = &dns.SVCBIPv4Hint{
|
||||
Hint: ips,
|
||||
}
|
||||
case dns.SVCB_IPV6HINT:
|
||||
jsIps := jsPropToStringArray(jsKv, "Value")
|
||||
var ips []net.IP
|
||||
for _, jsIp := range jsIps {
|
||||
ip := net.ParseIP(jsIp)
|
||||
if ip == nil {
|
||||
log.Error("error converting to SVCBKeyValue: invalid IPv6Hint IP: %s", jsIp)
|
||||
continue
|
||||
}
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
kv = &dns.SVCBIPv6Hint{
|
||||
Hint: ips,
|
||||
}
|
||||
case dns.SVCB_DOHPATH:
|
||||
kv = &dns.SVCBDoHPath{
|
||||
Template: jsPropToString(jsKv, "Value"),
|
||||
}
|
||||
case dns.SVCB_OHTTP:
|
||||
kv = &dns.SVCBOhttp{}
|
||||
case dns.SVCB_MANDATORY:
|
||||
v := jsPropToUint16Array(jsKv, "Value")
|
||||
keys := make([]dns.SVCBKey, len(v))
|
||||
for i, jsKey := range v {
|
||||
keys[i] = dns.SVCBKey(jsKey)
|
||||
}
|
||||
kv = &dns.SVCBMandatory{
|
||||
Code: keys,
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("error converting to dns.SVCBKeyValue: unknown key: %d", key)
|
||||
}
|
||||
|
||||
return kv, nil
|
||||
}
|
126
modules/dns_proxy/dns_proxy_script.go
Normal file
126
modules/dns_proxy/dns_proxy_script.go
Normal file
|
@ -0,0 +1,126 @@
|
|||
package dns_proxy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// define addSessionEvent function
|
||||
err = plug.Set("addSessionEvent", func(call otto.FunctionCall) otto.Value {
|
||||
if len(call.ArgumentList) < 2 {
|
||||
log.Error("Failed to execute 'addSessionEvent' in DNS proxy: 2 arguments required, but only %d given.", len(call.ArgumentList))
|
||||
return otto.FalseValue()
|
||||
}
|
||||
ottoTag := call.Argument(0)
|
||||
if !ottoTag.IsString() {
|
||||
log.Error("Failed to execute 'addSessionEvent' in DNS proxy: first argument must be a string.")
|
||||
return otto.FalseValue()
|
||||
}
|
||||
tag := strings.TrimSpace(ottoTag.String())
|
||||
if tag == "" {
|
||||
log.Error("Failed to execute 'addSessionEvent' in DNS proxy: tag cannot be empty.")
|
||||
return otto.FalseValue()
|
||||
}
|
||||
data := call.Argument(1)
|
||||
sess.Events.Add(tag, data)
|
||||
return otto.TrueValue()
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("Error while defining addSessionEvent function: %+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))
|
||||
|
|
|
@ -40,6 +40,14 @@ var (
|
|||
OrganizationalUnit: "https://certs.godaddy.com/repository/",
|
||||
CommonName: "Go Daddy Secure Certificate Authority - G2",
|
||||
}
|
||||
DefaultCloudflareDNSConfig = CertConfig{
|
||||
Bits: 4096,
|
||||
Country: "US",
|
||||
Locality: "San Francisco",
|
||||
Organization: "Cloudflare, Inc.",
|
||||
OrganizationalUnit: "",
|
||||
CommonName: "cloudflare-dns.com",
|
||||
}
|
||||
)
|
||||
|
||||
func CertConfigToModule(prefix string, m *session.SessionModule, defaults CertConfig) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue