Skip to content

Instantly share code, notes, and snippets.

@Oleksii909
Forked from sullemanhossam/sniff-mac.go
Last active August 10, 2024 03:08
Show Gist options
  • Save Oleksii909/3e01e8d6f34318c5beaba44d40def694 to your computer and use it in GitHub Desktop.
Save Oleksii909/3e01e8d6f34318c5beaba44d40def694 to your computer and use it in GitHub Desktop.
package mac
import (
"context"
"fmt"
"log"
"network-chesswork/utilities"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
const (
snapLen = 1600
promiscuous = true
timeout = pcap.BlockForever
sourcePath = "./temp/source-mac.json"
destPath = "./temp/dest-mac.json"
)
func Sniff(ctx context.Context, iface string) error {
if iface == "" {
return fmt.Errorf("network interface is required")
}
log.Printf("Sniffing package received interface: %s", iface)
// Open the network interface for packet capture
handle, err := pcap.OpenLive(iface, snapLen, promiscuous, timeout)
if err != nil {
return fmt.Errorf("failed to open live capture: %w", err)
}
defer handle.Close()
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
macAddresses := sync.Map{}
// Create a channel to receive OS signals
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
// Use a WaitGroup to wait for all goroutines to finish
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case <-sigChan:
log.Println("Received termination signal. Stopping packet capture...")
return
case packet := <-packetSource.Packets():
processPacket(packet, &macAddresses)
}
}
}()
wg.Wait()
return nil
}
func processPacket(packet gopacket.Packet, macAddresses *sync.Map) {
ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
if ethernetLayer == nil {
return
}
ethernetPacket, ok := ethernetLayer.(*layers.Ethernet)
if !ok {
return
}
processMAC(ethernetPacket.SrcMAC.String(), sourcePath, macAddresses)
processMAC(ethernetPacket.DstMAC.String(), destPath, macAddresses)
}
func processMAC(mac, path string, macAddresses *sync.Map) {
if _, loaded := macAddresses.LoadOrStore(mac, true); !loaded {
log.Printf("New MAC Address: %s", mac)
data := map[string]interface{}{
mac: map[string]interface{}{
"time": time.Now().UTC().Format(time.RFC3339),
},
}
if err := utilities.AppendJSON(path, data); err != nil {
log.Printf("Failed to append MAC address to JSON: %v", err)
}
}
}
// To use this enhanced version, you'll need to pass a context when calling the Sniff function:
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
err := mac.Sniff(ctx, "your_interface_name")
if err != nil {
log.Fatalf("Error while sniffing: %v", err)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment