Skip to content

Instantly share code, notes, and snippets.

@bradleypeabody
Created June 14, 2016 18:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bradleypeabody/21ab61ca639bff2008bde2e28b9f5aef to your computer and use it in GitHub Desktop.
Save bradleypeabody/21ab61ca639bff2008bde2e28b9f5aef to your computer and use it in GitHub Desktop.
Read arp table using cgo on macos
package main
import (
"fmt"
"time"
)
/*
// Ideas and much code from:
// https://opensource.apple.com/source/network_cmds/network_cmds-457/arp.tproj/arp.c
//#include <net/route.h>
//#include <net/if_arp.h>
//#include <net/ethernet.h>
//#include <sys/sysctl.h>
//#include <sys/socket.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <nlist.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#ifndef SA_SIZE
#define SA_SIZE(sa) \
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
sizeof(uint32_t) : \
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
#endif
typedef void (action_fn)(struct sockaddr_dl *sdl,
struct sockaddr_inarp *s_in, struct rt_msghdr *rtm);
extern void pushARPEntry(char *, char *, char*);
static int arp_search(in_addr_t addr, action_fn *action)
{
int mib[6];
size_t needed;
char *lim, *buf, *newbuf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin2;
struct sockaddr_dl *sdl;
char ifname[IF_NAMESIZE];
int st, found_entry = 0;
// This is the mib entry for the "route info" for all protocols - it does not seem to have
// any text equivalent. (I tried to use Go's syscall.Sysctl() directly with no luck - all
// the possible name variations I could think of fail to be found.)
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if (needed == 0) // empty table
return 0;
buf = NULL;
for (;;) {
newbuf = realloc(buf, needed);
if (newbuf == NULL) {
if (buf != NULL)
free(buf);
errx(1, "could not reallocate memory");
}
buf = newbuf;
st = sysctl(mib, 6, buf, &needed, NULL, 0);
if (st == 0 || errno != ENOMEM)
break;
needed += needed / 8;
}
if (st == -1)
err(1, "actual retrieval of routing table");
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sin2 = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
//if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
// strcmp(ifname, rifname))
// continue;
if (addr) {
if (addr != sin2->sin_addr.s_addr)
continue;
found_entry = 1;
}
(*action)(sdl, sin2, rtm);
}
free(buf);
return (found_entry);
}
static char *arp_print_lladdr(struct sockaddr_dl *sdl)
{
static char buf[256];
char *cp;
int n, bufsize = sizeof (buf), p = 0;
bzero(buf, sizeof (buf));
cp = (char *)LLADDR(sdl);
if ((n = sdl->sdl_alen) > 0) {
while (--n >= 0)
p += snprintf(buf + p, bufsize - p, "%02x%s",
*cp++ & 0xff, n > 0 ? ":" : "");
}
return (buf);
}
static void arp_push_entry(struct sockaddr_dl *sdl, struct sockaddr_inarp *addr, struct rt_msghdr *rtm) {
static char ifname[IF_NAMESIZE];
char *ipaddr = inet_ntoa(addr->sin_addr);
char *macaddr = (char *)"";
if (sdl->sdl_alen) {
macaddr = arp_print_lladdr(sdl);
}
int useifname = 0;
useifname = if_indextoname(sdl->sdl_index, ifname) != NULL;
pushARPEntry(
ipaddr,
macaddr,
useifname ? ifname : "");
}
static void full_arp_search() {
arp_search(0, arp_push_entry);
}
*/
import "C"
type ARPEntry struct {
IPAddress string
MACAddress string
IFName string
}
var ARPTable []ARPEntry
//export pushARPEntry
func pushARPEntry(ipaddr *C.char, macaddr *C.char, ifname *C.char) {
ARPTable = append(ARPTable, ARPEntry{
IPAddress: C.GoString(ipaddr),
MACAddress: C.GoString(macaddr),
IFName: C.GoString(ifname),
})
}
func main() {
start := time.Now()
ARPTable = nil
C.full_arp_search()
fmt.Printf("%#v (%v)\n", ARPTable, time.Since(start))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment