mirror of
https://github.com/bettercap/bettercap
synced 2025-08-14 02:36:57 -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/session"
|
||||
"github.com/evilsocket/islazy/ops"
|
||||
"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),
|
||||
tui.Green(e.Tag),
|
||||
source,
|
||||
ops.Ternary(event.Query.QR, "RESPONSE", "QUERY"),
|
||||
strings.Join(services, ", "),
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -105,9 +105,46 @@ func listMulticastInterfaces() []net.Interface {
|
|||
return nil
|
||||
}
|
||||
for _, ifi := range ifaces {
|
||||
// not up
|
||||
if (ifi.Flags & net.FlagUp) == 0 {
|
||||
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 {
|
||||
interfaces = append(interfaces, ifi)
|
||||
}
|
||||
|
|
|
@ -48,9 +48,10 @@ func Register(instance, service, domain string, port int, text []string, ifaces
|
|||
if err != nil {
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -431,7 +432,7 @@ func (s *Server) composeBrowsingAnswers(resp *dns.Msg, ifIndex int) {
|
|||
Ttl: s.ttl,
|
||||
},
|
||||
Priority: 0,
|
||||
Weight: 0,
|
||||
Weight: 0xffff,
|
||||
Port: uint16(s.service.Port),
|
||||
Target: s.service.HostName,
|
||||
}
|
||||
|
@ -463,7 +464,7 @@ func (s *Server) composeLookupAnswers(resp *dns.Msg, ttl uint32, ifIndex int, fl
|
|||
Ttl: ttl,
|
||||
},
|
||||
Priority: 0,
|
||||
Weight: 0,
|
||||
Weight: 0xffff,
|
||||
Port: uint16(s.service.Port),
|
||||
Target: s.service.HostName,
|
||||
}
|
||||
|
@ -539,7 +540,7 @@ func (s *Server) probe() {
|
|||
Ttl: s.ttl,
|
||||
},
|
||||
Priority: 0,
|
||||
Weight: 0,
|
||||
Weight: 0xffff,
|
||||
Port: uint16(s.service.Port),
|
||||
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."))
|
||||
|
||||
mod.AddParam(session.NewBoolParameter("zerogod.verbose",
|
||||
"false",
|
||||
"Log every mDNS query."))
|
||||
|
||||
return mod
|
||||
}
|
||||
|
||||
|
|
|
@ -103,9 +103,7 @@ func (mod *ZeroGod) startAdvertiser(fileName string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("could not get hostname: %v", err)
|
||||
}
|
||||
if !strings.HasSuffix(hostName, ".") {
|
||||
hostName += "."
|
||||
}
|
||||
hostName = strings.ReplaceAll(hostName, ".local", "")
|
||||
|
||||
data, err := ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package zerogod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
"github.com/bettercap/bettercap/v2/modules/zerogod/zeroconf"
|
||||
"github.com/bettercap/bettercap/v2/network"
|
||||
"github.com/bettercap/bettercap/v2/session"
|
||||
"github.com/evilsocket/islazy/ops"
|
||||
"github.com/evilsocket/islazy/tui"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
@ -81,6 +83,119 @@ func (mod *ZeroGod) onServiceDiscovered(svc *zeroconf.ServiceEntry) {
|
|||
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) {
|
||||
mod.Debug("%++v", pkt)
|
||||
|
||||
|
@ -105,12 +220,6 @@ func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
|||
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)
|
||||
if udp == nil {
|
||||
mod.Warning("not udp layer in packet %+v", pkt)
|
||||
|
@ -123,6 +232,18 @@ func (mod *ZeroGod) onPacket(pkt gopacket.Packet) {
|
|||
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
|
||||
numQs := len(dns.Questions)
|
||||
if numQs == 0 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue