diff --git a/modules/net_probe.go b/modules/net_probe.go index ea989652..8d7ba32d 100644 --- a/modules/net_probe.go +++ b/modules/net_probe.go @@ -15,6 +15,7 @@ import ( type Probes struct { NBNS bool MDNS bool + UPNP bool } type Prober struct { @@ -38,6 +39,10 @@ func NewProber(s *session.Session) *Prober { "true", "Enable mDNS discovery probes.")) + p.AddParam(session.NewBoolParameter("net.probe.upnp", + "true", + "Enable UPNP discovery probes.")) + p.AddParam(session.NewIntParameter("net.probe.throttle", "10", "If greater than 0, probe packets will be throttled by this value in milliseconds.")) @@ -89,6 +94,8 @@ func (p *Prober) Configure() error { return err } else if err, p.probes.MDNS = p.BoolParam("net.probe.mdns"); err != nil { return err + } else if err, p.probes.UPNP = p.BoolParam("net.probe.upnp"); err != nil { + return err } else { log.Debug("Throttling packets of %d ms.", p.throttle) } @@ -124,6 +131,10 @@ func (p *Prober) Start() error { p.sendProbeMDNS(from, from_hw) } + if p.probes.UPNP { + p.sendProbeUPNP(from, from_hw) + } + for _, ip := range addresses { if !p.Running() { return diff --git a/modules/net_probe_upnp.go b/modules/net_probe_upnp.go new file mode 100644 index 00000000..ce8889c5 --- /dev/null +++ b/modules/net_probe_upnp.go @@ -0,0 +1,20 @@ +package modules + +import ( + "net" + + "github.com/bettercap/bettercap/log" + "github.com/bettercap/bettercap/packets" +) + +func (p *Prober) sendProbeUPNP(from net.IP, from_hw net.HardwareAddr) { + err, raw := packets.NewUPNPProbe(from, from_hw) + if err != nil { + log.Error("error while sending upnp probe: %v", err) + return + } else if err := p.Session.Queue.Send(raw); err != nil { + log.Error("error sending upnp packet: %s", err) + } else { + log.Debug("sent %d bytes of UPNP probe", len(raw)) + } +} diff --git a/packets/upnp.go b/packets/upnp.go new file mode 100644 index 00000000..ae5aed87 --- /dev/null +++ b/packets/upnp.go @@ -0,0 +1,52 @@ +package packets + +import ( + "fmt" + "net" + + "github.com/google/gopacket" + "github.com/google/gopacket/layers" +) + +const ( + UPNPPort = 1900 +) + +var ( + UPNPDestMac = net.HardwareAddr{0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb} + UPNPDestIP = net.ParseIP("239.255.255.250") +) + +func NewUPNPProbe(from net.IP, from_hw net.HardwareAddr) (error, []byte) { + eth := layers.Ethernet{ + SrcMAC: from_hw, + DstMAC: UPNPDestMac, + EthernetType: layers.EthernetTypeIPv4, + } + + ip4 := layers.IPv4{ + Protocol: layers.IPProtocolUDP, + Version: 4, + TTL: 64, + SrcIP: from, + DstIP: UPNPDestIP, + } + + udp := layers.UDP{ + SrcPort: layers.UDPPort(12345), + DstPort: layers.UDPPort(UPNPPort), + } + + payload := []byte("M-SEARCH * HTTP/1.1\r\n" + + fmt.Sprintf("Host: %s:%d\r\n", UPNPDestIP, UPNPPort) + + "Man: ssdp:discover\r\n" + + "ST: ssdp:all\r\n" + + "MX: 2\r\n" + + "\r\n") + + if err := udp.SetNetworkLayerForChecksum(&ip4); err != nil { + return err, nil + } + + return Serialize(ð, &ip4, &udp, gopacket.Payload(payload)) +}