arp

package module
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 17, 2021 License: MIT Imports: 13 Imported by: 1

README

arp golang

The package implements a user level arp table management in golang that monitor the local network for ARP changes and provide notifications when a MAC switch between online and offline.

Force IP address change (IP spoofing)

The most useful function is to force an IP address change by claiming the IP of a target MAC. It achieves this by persistently claiming the IP address using ARP request/reply and activelly hunting the target MAC until it gives up its IP. This is very effective against mobile devices using DHCP however it does not work when client is using static address.

The package uses low level arp packets to enable:

  • network discovery by polling 254 addresses
  • notification when a MAC switch between online and offline
  • forced IP address change

See the arplistener example for how to use it.

Limitations

  • Tested on linux (Raspberry PI arm). Should work on Windows with tiny changes.
  • IPv4 only

Getting started

	$ go get github.com/irai/arp
	$ cd $GOPATH/src/github.com/irai/arp/arplistener
	$ go install
	$ sudo $GOPATH/bin/arplistener -i eth0

Create your own listener in a goroutine

Simply create a new handler and run ListenAndServe in a goroutine. The goroutine will listen for ARP changes and generate a notification each time a mac changes between online/offline.

	HomeRouterIP := net.ParseIP("192.168.0.1").To4()
	HomeLAN := net.IPNet{IP: net.ParseIP("192.168.0.0").To4(), Mask: net.CIDRMask(25, 32)}

	c, err := arp.NewHandler(NIC, HostMAC, HostIP, HomeRouterIP, HomeLAN)
	if err != nil {
		log.Fatal("error ", err)
	}

	go c.ListenAndServe(time.Second * 30 * 5)

	c.printTable()

Listen to changes to mac table

    arpChannel := make(chan arp.MACEntry, 16)
	c.AddNotificationChannel(arpChannel)

	go arpNotification(arpChannel)
func arpNotification(arpChannel chan arp.MACEntry) {
	for {
		select {
		case MACEntry := <-arpChannel:
			log.Warnf("notification got ARP MACEntry for %s", MACEntry.MAC)

		}
	}
}

To force an IP change simply invoke ForceIPChange with the current mac and ip value.

	MACEntry := c.findByMAC("xx:xx:xx:xx:xx:xx")
	c.ForceIPChange(MACEntry.MAC, MACEntry.IP)

Documentation

Index

Constants

View Source
const (
	// StateNormal is used when there is nothing to do
	StateNormal arpState = "normal"

	// StateHunt when activelly hunting the client to change its IP address
	StateHunt arpState = "hunt"

	// StateVirtualHost when claiming an IP address
	StateVirtualHost arpState = "virtual"
)

Variables

View Source
var (
	// ErrNotFound is returned when MAC not found
	ErrNotFound = errors.New("not found")

	// EthernetBroadcast defines the broadcast address
	EthernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
)
View Source
var (
	// Debug - set Debug to true to see debugging messages
	Debug bool
)

Functions

This section is empty.

Types

type Config added in v1.3.0

type Config struct {
	NIC                     string           `yaml:"-"`
	HostMAC                 net.HardwareAddr `yaml:"-"`
	HostIP                  net.IP           `yaml:"-"`
	RouterIP                net.IP           `yaml:"-"`
	HomeLAN                 net.IPNet        `yaml:"-"`
	FullNetworkScanInterval time.Duration    `yaml:"-"` // Set it to zero if no scan required
	ProbeInterval           time.Duration    `yaml:"-"` // how often to probe if IP is online
	OfflineDeadline         time.Duration    `yaml:"-"` // mark offline if more than OfflineInte
	PurgeDeadline           time.Duration    `yaml:"-"`
}

Config holds configuration parameters

Set FullNetworkScanInterval = 0 to avoid network scan

func (Config) String added in v1.3.0

func (c Config) String() string

type Handler added in v1.1.0

type Handler struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Handler stores instance variables

func New added in v1.3.0

func New(config Config) (c *Handler, err error)

New creates an ARP handler for a given interface.

func NewTestHandler added in v1.3.0

func NewTestHandler(config Config, p net.PacketConn) (c *Handler, conn *marp.Client, err error)

NewTestHandler allow you to pass a PacketConn. Useful for testing if p is nil, auto create a bufferedPacketConn

func (*Handler) AddNotificationChannel added in v1.1.0

func (c *Handler) AddNotificationChannel(notification chan<- MACEntry)

AddNotificationChannel set the notification channel for when the MACEntry change state between online and offline.

func (*Handler) ClaimIP added in v1.3.1

func (c *Handler) ClaimIP(ip net.IP)

ClaimIP creates a virtual host to claim the ip When a virtual host exist, the handler will respond to ACD and request packets for the ip

func (*Handler) Close added in v1.3.0

func (c *Handler) Close()

Close will terminate the ListenAndServer goroutine as well as all other pending goroutines.

func (*Handler) FindIP added in v1.1.0

func (c *Handler) FindIP(ip net.IP) (entry MACEntry, found bool)

FindIP returns a MACEntry or empty if not found

func (*Handler) FindMAC added in v1.1.0

func (c *Handler) FindMAC(mac net.HardwareAddr) (entry MACEntry, found bool)

FindMAC returns a MACEntry or empty if not found

func (*Handler) ForceIPChange added in v1.1.0

func (c *Handler) ForceIPChange(mac net.HardwareAddr, claimIP bool) error

ForceIPChange performs the following:

  1. set client state to "hunt" which will continuously spoof the client ARP table
  2. create a virtual host for each IP and claim the IP
  3. spoof the client ARP table to redirect all traffic to host
  4. claim the client IP to force client to reaquire DHCP
  5. notify when client change IP

client will revert back to "normal" when a new IP is detected for the MAC

func (*Handler) GetTable added in v1.1.0

func (c *Handler) GetTable() []MACEntry

GetTable return the mac table as a shallow array of MACEntry

func (*Handler) IPChanged added in v1.1.0

func (c *Handler) IPChanged(mac net.HardwareAddr, clientIP net.IP)

IPChanged is used to notify that the IP has changed.

The package will detect IP changes automatically however some clients do not send ARP Collision Detection packets and hence do not appear as an immediate change. This method is used to accelerate the change for example when a new DHCP MACEntry has been allocated.

func (*Handler) ListenAndServe added in v1.1.0

func (c *Handler) ListenAndServe(ctx context.Context) error

ListenAndServe listen for ARP packets and action each.

When a new MAC is detected, it is automatically added to the ARP table and marked as online. Use packet buffer and selectivelly copy mac and ip if we need to keep it

Online and offline notifications It will track when a MAC switch between online and offline and will send a message in the notification channel set via AddNotificationChannel(). It will poll each known device based on the scanInterval parameter using a unicast ARP request.

Virtual MACs A virtual MAC is a fake mac address used when claiming an existing IP during spoofing. ListenAndServe will send ARP reply on behalf of virtual MACs

func (*Handler) PrintTable added in v1.1.0

func (c *Handler) PrintTable()

PrintTable print the ARP table to stdout.

func (*Handler) Probe added in v1.1.0

func (c *Handler) Probe(ip net.IP) error

Probe will send an arp request broadcast on the local link.

The term 'ARP Probe' is used to refer to an ARP Request packet, broadcast on the local link, with an all-zero 'sender IP address'. The 'sender hardware address' MUST contain the hardware address of the interface sending the packet. The 'sender IP address' field MUST be set to all zeroes, to avoid polluting ARP caches in other hosts on the same link in the case where the address turns out to be already in use by another host. The 'target IP address' field MUST be set to the address being probed. An ARP Probe conveys both a question ("Is anyone using this address?") and an implied statement ("This is the address I hope to use.").

func (*Handler) Reply added in v1.1.0

func (c *Handler) Reply(dstEther net.HardwareAddr, srcHwAddr net.HardwareAddr, srcIP net.IP, dstHwAddr net.HardwareAddr, dstIP net.IP) error

Reply send ARP reply from the src to the dst

Call with dstHwAddr = ethernet.Broadcast to reply to all

func (*Handler) Request added in v1.1.0

func (c *Handler) Request(srcHwAddr net.HardwareAddr, srcIP net.IP, dstHwAddr net.HardwareAddr, dstIP net.IP) error

Request send ARP request from src to dst multiple goroutines can call request simultaneously.

Request is almost always broadcast but unicast can be used to maintain ARP table; i.e. unicast polling check for stale ARP entries; useful to test online/offline state

ARP: packet types

note that RFC 3927 specifies 00:00:00:00:00:00 for Request TargetMAC

+============+===+===========+===========+============+============+===================+===========+ | Type | op| dstMAC | srcMAC | SenderMAC | SenderIP | TargetMAC | TargetIP | +============+===+===========+===========+============+============+===================+===========+ | request | 1 | broadcast | clientMAC | clientMAC | clientIP | ff:ff:ff:ff:ff:ff | targetIP | | reply | 2 | clientMAC | targetMAC | targetMAC | targetIP | clientMAC | clientIP | | gratuitous | 2 | broadcast | clientMAC | clientMAC | clientIP | ff:ff:ff:ff:ff:ff | clientIP | | ACD probe | 1 | broadcast | clientMAC | clientMAC | 0x00 | 0x00 | targetIP | | ACD announ | 1 | broadcast | clientMAC | clientMAC | clientIP | ff:ff:ff:ff:ff:ff | clientIP | +============+===+===========+===========+============+============+===================+===========+

func (*Handler) ScanNetwork added in v1.3.0

func (c *Handler) ScanNetwork(ctx context.Context, lan net.IPNet) error

ScanNetwork sends 256 arp requests to identify IPs on the lan

func (*Handler) StopIPChange added in v1.1.0

func (c *Handler) StopIPChange(mac net.HardwareAddr) error

StopIPChange terminate the hunting process

func (*Handler) WhoIs added in v1.1.0

func (c *Handler) WhoIs(ip net.IP) (MACEntry, error)

WhoIs will send a request packet to get the MAC address for the IP. Retry 3 times.

type IPEntry added in v1.3.0

type IPEntry struct {
	IP          net.IP
	LastUpdated time.Time
}

IPEntry holds info about each IP

type MACEntry added in v1.3.0

type MACEntry struct {
	MAC         net.HardwareAddr
	IPArray     [nIPs]IPEntry
	State       arpState
	LastUpdated time.Time
	Online      bool
	ClaimIP     bool // if true, will claim the target IP; likely to force the target IP to stop working
}

MACEntry holds a mac to ip MACEntry

func (*MACEntry) IP added in v1.3.0

func (e *MACEntry) IP() net.IP

IP returns the last IP detected

func (*MACEntry) IPs added in v1.3.0

func (e *MACEntry) IPs() []net.IP

IPs return list of IPs associated with this entry

func (MACEntry) String added in v1.3.0

func (e MACEntry) String() string

String interface

Directories

Path Synopsis
cmd
arplistener command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL