Skip to content

Instantly share code, notes, and snippets.

@003random
Created September 11, 2021 00:33
Show Gist options
  • Save 003random/7a545253fc2f65e0c3cf0e5d0e5e48e7 to your computer and use it in GitHub Desktop.
Save 003random/7a545253fc2f65e0c3cf0e5d0e5e48e7 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"log"
"net"
"os"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
func main() {
// Store arguments as variables of the right type
iface := os.Args[1]
srcMAC, err := net.ParseMAC(os.Args[2])
if err != nil {
log.Fatal(err)
}
srcIP := net.ParseIP(os.Args[3])
// Create mapping to store ARP reply values
replies := make(map[string]string)
// Open socket
handle, err := pcap.OpenLive(iface, 2048, false, 100*time.Nanosecond)
if err != nil {
log.Fatal(err)
}
// Only capture ARP replies
if err := handle.SetBPFFilter("arp[6:2] = 2"); err != nil {
log.Fatal(err)
}
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
// Loop over the incoming packets channel
for packet := range packetSource.Packets() {
arpLayer := packet.Layer(layers.LayerTypeARP)
arp, ok := arpLayer.(*layers.ARP)
if !ok {
continue
}
err = sendARPRequest(handle, srcMAC, srcIP, arp.SourceProtAddress)
if err != nil {
log.Fatal(err)
}
if previousMAC, ok := replies[net.IP(arp.SourceProtAddress).String()]; ok {
if previousMAC != net.HardwareAddr(arp.SourceHwAddress).String() {
fmt.Println("ARP Spoofing Detected for IP Address", net.IP(arp.SourceProtAddress).String())
}
}
replies[net.IP(arp.SourceProtAddress).String()] = net.HardwareAddr(arp.SourceHwAddress).String()
time.AfterFunc(time.Second*50, func() {
delete(replies, net.IP(arp.SourceProtAddress).String())
})
}
}
func sendARPRequest(handle *pcap.Handle, srcMAC net.HardwareAddr, srcIP, dstIP net.IP) error {
// Construct layers for the ARP request
eth := layers.Ethernet{
SrcMAC: srcMAC,
DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
EthernetType: layers.EthernetTypeARP,
}
arp := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv4,
HwAddressSize: 6,
ProtAddressSize: 4,
Operation: layers.ARPRequest,
SourceHwAddress: []byte(srcMAC),
SourceProtAddress: srcIP.To4(),
DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
DstProtAddress: dstIP.To4(),
}
buf := gopacket.NewSerializeBuffer()
// Send a single ARP request packet (we never retry a send, since this
err := gopacket.SerializeLayers(buf, gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}, &eth, &arp)
if err != nil {
return err
}
return handle.WritePacketData(buf.Bytes())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment