Merge pull request #1143 from buffermet/master

dns.proxy module
This commit is contained in:
Simone Margaritelli 2024-11-13 11:17:03 +01:00 committed by GitHub
commit 906162e5fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 2256 additions and 0 deletions

View 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()
})
}

View 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)
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View 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
}

View file

@ -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))

View file

@ -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) {