bettercap/net/arp.go
2017-11-17 14:49:59 +01:00

90 lines
1.7 KiB
Go

package net
import (
"fmt"
"regexp"
"strings"
"sync"
"github.com/op/go-logging"
"github.com/evilsocket/bettercap/core"
)
type ArpTable map[string]string
var (
log = logging.MustGetLogger("mitm")
arp_parsed = false
arp_lock = &sync.Mutex{}
arp_table = make(ArpTable)
)
var ArpTableParser = regexp.MustCompile("^[^\\d\\.]+([\\d\\.]+).+\\s+([a-f0-9:]{17}).+\\s+(.+)$")
var ArpTableTokens = 4
func ArpDiff(current, before ArpTable) ArpTable {
diff := make(ArpTable)
for ip, mac := range current {
_, found := before[ip]
if !found {
diff[ip] = mac
}
}
return diff
}
func ArpLookup(iface string, address string, refresh bool) (string, error) {
// Refresh ARP table if first run or if a force refresh has been instructed.
if ArpParsed() == false || refresh == true {
if _, err := ArpUpdate(iface); err != nil {
return "", err
}
}
// Lookup the hardware address of this ip.
if mac, found := arp_table[address]; found == true {
return mac, nil
}
return "", fmt.Errorf("Could not find mac for %s", address)
}
func ArpParsed() bool {
arp_lock.Lock()
defer arp_lock.Unlock()
return arp_parsed
}
func ArpUpdate(iface string) (ArpTable, error) {
arp_lock.Lock()
defer arp_lock.Unlock()
// Signal we parsed the ARP table at least once.
arp_parsed = true
// Run "arp -an" and parse the output.
output, err := core.Exec("arp", []string{"-a", "-n"})
if err != nil {
return arp_table, err
}
new_table := make(ArpTable)
for _, line := range strings.Split(output, "\n") {
m := ArpTableParser.FindStringSubmatch(line)
if len(m) == ArpTableTokens {
address := m[1]
mac := m[2]
ifname := m[3]
if ifname == iface {
new_table[address] = mac
}
}
}
arp_table = new_table
return arp_table, nil
}