mirror of
https://github.com/bettercap/bettercap
synced 2025-08-19 04:59:25 -07:00
misc: small fix or general refactoring i did not bother commenting
This commit is contained in:
parent
7b4fc3d31d
commit
5652d15426
6 changed files with 177 additions and 14 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/bettercap/bettercap/v2/modules/zerogod"
|
"github.com/bettercap/bettercap/v2/modules/zerogod"
|
||||||
"github.com/bettercap/bettercap/v2/session"
|
"github.com/bettercap/bettercap/v2/session"
|
||||||
|
"github.com/evilsocket/islazy/ops"
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,10 +51,11 @@ func (mod *EventsStream) viewZeroConfEvent(output io.Writer, e session.Event) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fmt.Fprintf(output, "[%s] [%s] %s is browsing for services %s\n",
|
fmt.Fprintf(output, "[%s] [%s] %s is browsing (%s) for services %s\n",
|
||||||
e.Time.Format(mod.timeFormat),
|
e.Time.Format(mod.timeFormat),
|
||||||
tui.Green(e.Tag),
|
tui.Green(e.Tag),
|
||||||
source,
|
source,
|
||||||
|
ops.Ternary(event.Query.QR, "RESPONSE", "QUERY"),
|
||||||
strings.Join(services, ", "),
|
strings.Join(services, ", "),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -105,9 +105,46 @@ func listMulticastInterfaces() []net.Interface {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, ifi := range ifaces {
|
for _, ifi := range ifaces {
|
||||||
|
// not up
|
||||||
if (ifi.Flags & net.FlagUp) == 0 {
|
if (ifi.Flags & net.FlagUp) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// localhost
|
||||||
|
if (ifi.Flags & net.FlagLoopback) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// not running
|
||||||
|
if (ifi.Flags & net.FlagRunning) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// vpn and similar
|
||||||
|
if (ifi.Flags & net.FlagPointToPoint) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// at least one ipv4 address assigned
|
||||||
|
hasIPv4 := false
|
||||||
|
if addresses, _ := ifi.Addrs(); addresses != nil {
|
||||||
|
for _, addr := range addresses {
|
||||||
|
// ipv4 or ipv4 CIDR
|
||||||
|
if ip, ipnet, err := net.ParseCIDR(addr.String()); err == nil {
|
||||||
|
if ip.To4() != nil || ipnet.IP.To4() != nil {
|
||||||
|
hasIPv4 = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if ipAddr, ok := addr.(*net.IPAddr); ok {
|
||||||
|
if ipAddr.IP.To4() != nil {
|
||||||
|
hasIPv4 = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasIPv4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (ifi.Flags & net.FlagMulticast) > 0 {
|
if (ifi.Flags & net.FlagMulticast) > 0 {
|
||||||
interfaces = append(interfaces, ifi)
|
interfaces = append(interfaces, ifi)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,10 @@ func Register(instance, service, domain string, port int, text []string, ifaces
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not determine host")
|
return nil, fmt.Errorf("could not determine host")
|
||||||
}
|
}
|
||||||
|
entry.HostName = strings.ReplaceAll(entry.HostName, ".local", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasSuffix(trimDot(entry.HostName), entry.Domain) {
|
if !strings.HasSuffix(trimDot(entry.HostName), trimDot(entry.Domain)) {
|
||||||
entry.HostName = fmt.Sprintf("%s.%s.", trimDot(entry.HostName), trimDot(entry.Domain))
|
entry.HostName = fmt.Sprintf("%s.%s.", trimDot(entry.HostName), trimDot(entry.Domain))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +432,7 @@ func (s *Server) composeBrowsingAnswers(resp *dns.Msg, ifIndex int) {
|
||||||
Ttl: s.ttl,
|
Ttl: s.ttl,
|
||||||
},
|
},
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
Weight: 0,
|
Weight: 0xffff,
|
||||||
Port: uint16(s.service.Port),
|
Port: uint16(s.service.Port),
|
||||||
Target: s.service.HostName,
|
Target: s.service.HostName,
|
||||||
}
|
}
|
||||||
|
@ -463,7 +464,7 @@ func (s *Server) composeLookupAnswers(resp *dns.Msg, ttl uint32, ifIndex int, fl
|
||||||
Ttl: ttl,
|
Ttl: ttl,
|
||||||
},
|
},
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
Weight: 0,
|
Weight: 0xffff,
|
||||||
Port: uint16(s.service.Port),
|
Port: uint16(s.service.Port),
|
||||||
Target: s.service.HostName,
|
Target: s.service.HostName,
|
||||||
}
|
}
|
||||||
|
@ -539,7 +540,7 @@ func (s *Server) probe() {
|
||||||
Ttl: s.ttl,
|
Ttl: s.ttl,
|
||||||
},
|
},
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
Weight: 0,
|
Weight: 0xffff,
|
||||||
Port: uint16(s.service.Port),
|
Port: uint16(s.service.Port),
|
||||||
Target: s.service.HostName,
|
Target: s.service.HostName,
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,10 @@ func NewZeroGod(s *session.Session) *ZeroGod {
|
||||||
"",
|
"",
|
||||||
"If an IPP acceptor is started, this setting defines where to save documents received for printing."))
|
"If an IPP acceptor is started, this setting defines where to save documents received for printing."))
|
||||||
|
|
||||||
|
mod.AddParam(session.NewBoolParameter("zerogod.verbose",
|
||||||
|
"false",
|
||||||
|
"Log every mDNS query."))
|
||||||
|
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,9 +103,7 @@ func (mod *ZeroGod) startAdvertiser(fileName string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not get hostname: %v", err)
|
return fmt.Errorf("could not get hostname: %v", err)
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(hostName, ".") {
|
hostName = strings.ReplaceAll(hostName, ".local", "")
|
||||||
hostName += "."
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(fileName)
|
data, err := ioutil.ReadFile(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package zerogod
|
package zerogod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -8,6 +9,7 @@ import (
|
||||||
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
||||||
"github.com/bettercap/bettercap/v2/network"
|
"github.com/bettercap/bettercap/v2/network"
|
||||||
"github.com/bettercap/bettercap/v2/session"
|
"github.com/bettercap/bettercap/v2/session"
|
||||||
|
"github.com/evilsocket/islazy/ops"
|
||||||
"github.com/evilsocket/islazy/tui"
|
"github.com/evilsocket/islazy/tui"
|
||||||
"github.com/google/gopacket"
|
"github.com/google/gopacket"
|
||||||
"github.com/google/gopacket/layers"
|
"github.com/google/gopacket/layers"
|
||||||
|
@ -81,6 +83,119 @@ func (mod *ZeroGod) onServiceDiscovered(svc *zeroconf.ServiceEntry) {
|
||||||
session.I.Refresh()
|
session.I.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mod *ZeroGod) DNSResourceRecord2String(rr *layers.DNSResourceRecord) string {
|
||||||
|
|
||||||
|
if rr.Type == layers.DNSTypeOPT {
|
||||||
|
opts := make([]string, len(rr.OPT))
|
||||||
|
for i, opt := range rr.OPT {
|
||||||
|
opts[i] = opt.String()
|
||||||
|
}
|
||||||
|
return "OPT " + strings.Join(opts, ",")
|
||||||
|
}
|
||||||
|
if rr.Type == layers.DNSTypeURI {
|
||||||
|
return fmt.Sprintf("URI %d %d %s", rr.URI.Priority, rr.URI.Weight, string(rr.URI.Target))
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
https://www.rfc-editor.org/rfc/rfc6762
|
||||||
|
|
||||||
|
Note that the cache-flush bit is NOT part of the resource record
|
||||||
|
class. The cache-flush bit is the most significant bit of the second
|
||||||
|
16-bit word of a resource record in a Resource Record Section of a
|
||||||
|
Multicast DNS message (the field conventionally referred to as the
|
||||||
|
rrclass field), and the actual resource record class is the least
|
||||||
|
significant fifteen bits of this field. There is no Multicast DNS
|
||||||
|
resource record class 0x8001. The value 0x8001 in the rrclass field
|
||||||
|
of a resource record in a Multicast DNS response message indicates a
|
||||||
|
resource record with class 1, with the cache-flush bit set. When
|
||||||
|
receiving a resource record with the cache-flush bit set,
|
||||||
|
implementations should take care to mask off that bit before storing
|
||||||
|
the resource record in memory, or otherwise ensure that it is given
|
||||||
|
the correct semantic interpretation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if rr.Class == layers.DNSClassIN || rr.Class == 0x8001 {
|
||||||
|
switch rr.Type {
|
||||||
|
case layers.DNSTypeA, layers.DNSTypeAAAA:
|
||||||
|
return rr.IP.String()
|
||||||
|
case layers.DNSTypeNS:
|
||||||
|
return "NS " + string(rr.NS)
|
||||||
|
case layers.DNSTypeCNAME:
|
||||||
|
return "CNAME " + string(rr.CNAME)
|
||||||
|
case layers.DNSTypePTR:
|
||||||
|
return "PTR " + string(rr.PTR)
|
||||||
|
case layers.DNSTypeTXT:
|
||||||
|
return "TXT \n" + Dump(rr.TXT)
|
||||||
|
case layers.DNSTypeSRV:
|
||||||
|
return fmt.Sprintf("SRV priority=%d weight=%d port=%d name=%s",
|
||||||
|
rr.SRV.Priority,
|
||||||
|
rr.SRV.Weight,
|
||||||
|
rr.SRV.Port,
|
||||||
|
string(rr.SRV.Name))
|
||||||
|
case 47: // NSEC
|
||||||
|
return "NSEC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("<%v (%d), %v (%d)>", rr.Class, rr.Class, rr.Type, rr.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *ZeroGod) logDNS(src net.IP, dns layers.DNS, isLocal bool) {
|
||||||
|
source := tui.Yellow(src.String())
|
||||||
|
if endpoint := mod.Session.Lan.GetByIp(src.String()); endpoint != nil {
|
||||||
|
if endpoint.Alias != "" {
|
||||||
|
source = tui.Bold(endpoint.Alias)
|
||||||
|
} else if endpoint.Hostname != "" {
|
||||||
|
source = tui.Bold(endpoint.Hostname)
|
||||||
|
} else if endpoint.Vendor != "" {
|
||||||
|
source = fmt.Sprintf("%s (%s)", tui.Bold(endpoint.IpAddress), tui.Dim(endpoint.Vendor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
desc := fmt.Sprintf("DNS op=%s %s from %s (r_code=%s)",
|
||||||
|
dns.OpCode.String(),
|
||||||
|
tui.Bold(ops.Ternary(dns.QR, "RESPONSE", "QUERY").(string)),
|
||||||
|
source,
|
||||||
|
dns.ResponseCode.String())
|
||||||
|
|
||||||
|
attrs := []string{}
|
||||||
|
if dns.AA {
|
||||||
|
attrs = append(attrs, "AA")
|
||||||
|
}
|
||||||
|
if dns.TC {
|
||||||
|
attrs = append(attrs, "TC")
|
||||||
|
}
|
||||||
|
if dns.RD {
|
||||||
|
attrs = append(attrs, "RD")
|
||||||
|
}
|
||||||
|
if dns.RA {
|
||||||
|
attrs = append(attrs, "RA")
|
||||||
|
}
|
||||||
|
if len(attrs) > 0 {
|
||||||
|
desc += " [" + strings.Join(attrs, ", ") + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
desc += " :\n"
|
||||||
|
|
||||||
|
for _, q := range dns.Questions {
|
||||||
|
desc += fmt.Sprintf(" Q: %s\n", q)
|
||||||
|
}
|
||||||
|
for _, a := range dns.Answers {
|
||||||
|
desc += fmt.Sprintf(" A: %s\n", mod.DNSResourceRecord2String(&a))
|
||||||
|
}
|
||||||
|
for _, a := range dns.Authorities {
|
||||||
|
desc += fmt.Sprintf(" AU: %s\n", mod.DNSResourceRecord2String(&a))
|
||||||
|
}
|
||||||
|
for _, a := range dns.Additionals {
|
||||||
|
desc += fmt.Sprintf(" AD: %s\n", mod.DNSResourceRecord2String(&a))
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLocal {
|
||||||
|
desc = tui.Dim(desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
mod.Info("%s", desc)
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
||||||
mod.Debug("%++v", pkt)
|
mod.Debug("%++v", pkt)
|
||||||
|
|
||||||
|
@ -105,12 +220,6 @@ func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// not interested in packet generated by us
|
|
||||||
if srcIP.Equal(mod.Session.Interface.IP) || srcIP.Equal(mod.Session.Interface.IPv6) {
|
|
||||||
mod.Debug("skipping local packet")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
udp := pkt.Layer(layers.LayerTypeUDP)
|
udp := pkt.Layer(layers.LayerTypeUDP)
|
||||||
if udp == nil {
|
if udp == nil {
|
||||||
mod.Warning("not udp layer in packet %+v", pkt)
|
mod.Warning("not udp layer in packet %+v", pkt)
|
||||||
|
@ -123,6 +232,18 @@ func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLocal := srcIP.Equal(mod.Session.Interface.IP) || srcIP.Equal(mod.Session.Interface.IPv6)
|
||||||
|
|
||||||
|
if _, verbose := mod.BoolParam("zerogod.verbose"); verbose {
|
||||||
|
mod.logDNS(srcIP, dns, isLocal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// not interested in packet generated by us
|
||||||
|
if isLocal {
|
||||||
|
mod.Debug("skipping local packet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// since the browser is already checking for these, we are only interested in queries
|
// since the browser is already checking for these, we are only interested in queries
|
||||||
numQs := len(dns.Questions)
|
numQs := len(dns.Questions)
|
||||||
if numQs == 0 {
|
if numQs == 0 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue