The Assimilation Project  based on Assimilation version 1.1.7.1474836767
arpdiscovery.c
Go to the documentation of this file.
1 
26 #include <stdio.h>
27 #include <projectcommon.h>
28 #include <memory.h>
29 #include <arpdiscovery.h>
30 #include <configcontext.h>
31 #include <netaddr.h>
32 #include <misc.h>
33 #include <tlvhelper.h>
34 #include <nanoprobe.h>
76 #define ARP_PKT_OFFSET 14
77 #define ARP_HRD_LEN 2
78 #define ARP_PRO_LEN 2
79 #define ARP_HLN_LEN 1
80 #define ARP_PLN_LEN 1
81 #define ARP_OP_LEN 2
82 #define ARP_HDR_LEN (ARP_HRD_LEN + ARP_PRO_LEN + ARP_HLN_LEN + ARP_PLN_LEN + ARP_OP_LEN)
84 
86 
89 FSTATIC gboolean _arpdiscovery_dispatch(GSource_pcap_t* gsource, pcap_t*, gconstpointer, gconstpointer,
90  const struct pcap_pkthdr*, const char *, gpointer selfptr);
92 FSTATIC gboolean _arpdiscovery_gsourcefunc(gpointer);
93 FSTATIC gboolean _arpdiscovery_first_discovery(gpointer);
94 
96 
102 
104 FSTATIC void
106 {
107  ArpDiscovery * self = CASTTOCLASS(ArpDiscovery, dself);
108  g_info("%-35s %8"G_GINT64_MODIFIER"d", "Count of ARP pkts received:"
109  , self->baseclass.discovercount);
110  if (self->source) {
111  g_source_unref(self->source);
112  g_source_destroy(self->source);
113  self->source = NULL;
114  }
115  if (self->timeout_source != 0) {
116  g_source_remove(self->timeout_source);
117  self->timeout_source = 0;
118  }
119  if (self->arpconfig) {
120  UNREF(self->arpconfig);
121  }
122 
123  UNREF(self->ArpMap);
124  self->ArpMapData = NULL; // Child object of ArpMap
125 
126  // Call base object finalization routine (which we saved away)
127  self->finalize(&self->baseclass.baseclass);
128 }
129 
131 FSTATIC gboolean
133 {
134  (void)self;
135  return FALSE;
136 }
137 
138 
140 FSTATIC gboolean
142 {
143  ArpDiscovery* self = CASTTOCLASS(ArpDiscovery, gself);
144  int interval = self->arpconfig->getint(self->arpconfig, CONFIGNAME_INTERVAL);
145  if (self->timeout_source > 0) {
146  g_source_remove(self->timeout_source);
147  self->timeout_source = 0;
148  }
149  self->timeout_source
150  = g_timeout_add_seconds_full
151  (G_PRIORITY_HIGH, interval, _arpdiscovery_gsourcefunc
152  , self, NULL);
153  DEBUGMSG3("Sender %p subsequent timeout source is: %d, interval is %d", self
154  , self->timeout_source, interval);
156  return FALSE;
157 }
158 
159 
161 FSTATIC gboolean
163 {
164  ArpDiscovery* self = CASTTOCLASS(ArpDiscovery, gself);
166  return TRUE;
167 }
168 
169 
176 FSTATIC gboolean
178  pcap_t* capstruct,
179  gconstpointer pkt,
180  gconstpointer pend,
181  const struct pcap_pkthdr* pkthdr,
182  const char * capturedev,
183  gpointer selfptr
184  )
185 {
186  ArpDiscovery* self = CASTTOCLASS(ArpDiscovery, selfptr);
187  Discovery* dself = &(self->baseclass);
189 
190  struct arppacket {
191  guint16 arp_hrd_type;
192  guint16 arp_protocol;
193  guint8 arp_hln;
194  guint8 arp_pln;
195  guint16 arp_op;
196  };
197  struct arppacket arppkt;
198  const guint8* pktstart = ((const guint8*)pkt) + ARP_PKT_OFFSET;
199  const guint8* arp_sha; // sender hardware address
200  const guint8* arp_spa; // sender protocol address
201  NetAddr* sha_netaddr; // sender hardware address
202  NetAddr* spa_netaddr; // sender protocol address
203  NetAddr* arp_spaIPv6; // sender protocol address in IPv6 format
204  const guint8* arp_tha; // target hardware address
205  const guint8* arp_tpa; // target protocol address
206  const guint8* lastbyte; // last byte of packet according to ARP
207  NetAddr* tha_netaddr; // target hardware address
208  NetAddr* tpa_netaddr; // target protocol address
209  NetAddr* theMAC;
210  char * v6string;
211  static const guint8 zeroes[4] = {0, 0, 0, 0};
212 
213  (void)gsource; (void)capstruct; (void)pkthdr; (void)capturedev;
214  DEBUGMSG3("** Got an incoming ARP packet! - dest is %p", dest);
215 
216  arppkt.arp_hrd_type = tlv_get_guint16(pktstart, pend);
217  arppkt.arp_protocol = tlv_get_guint16(pktstart+ARP_HRD_LEN, pend);
218  arppkt.arp_hln = tlv_get_guint8(pktstart+ARP_HRD_LEN+ARP_PRO_LEN, pend);
219  arppkt.arp_pln = tlv_get_guint8(pktstart+ARP_HRD_LEN+ARP_PRO_LEN+ARP_HLN_LEN, pend);
221  , pend);
222 
223  /*
224  fprintf(stderr, "ARP Hardware Type: %u\n", arppkt.arp_hrd_type);
225  fprintf(stderr, "ARP Protocol Type: %u\n", arppkt.arp_protocol);
226  fprintf(stderr, "ARP Hardware Address Length: %u\n", arppkt.arp_hln);
227  fprintf(stderr, "ARP Protocol Address Length: %u\n", arppkt.arp_pln);
228  fprintf(stderr, "ARP Protocol Opcode: %u\n", arppkt.arp_op);
229  */
230 
231  arp_sha = pktstart + ARP_HDR_LEN;
232  arp_spa = arp_sha + arppkt.arp_hln;
233  lastbyte = arp_sha + (2*arppkt.arp_pln) + (2*arppkt.arp_hln);
234  g_return_val_if_fail(lastbyte <= (const guint8*)pend, TRUE);
235  g_return_val_if_fail(arppkt.arp_hln == 6 || arppkt.arp_hln == 8, TRUE);
236  g_return_val_if_fail(arppkt.arp_pln == 4, TRUE);
237  if (memcmp(arp_spa, zeroes, arppkt.arp_pln) == 0) {
238  // Some glitchy device gave us a funky IP address...
239  return TRUE;
240  }
241  sha_netaddr = netaddr_macaddr_new(arp_sha, arppkt.arp_hln);
242  spa_netaddr = netaddr_ipv4_new(arp_spa, 0);
243  arp_spaIPv6 = spa_netaddr->toIPv6(spa_netaddr); // convert sender protocol address to IPv6 format
244  arp_tha = arp_spa + arppkt.arp_pln;
245  arp_tpa = arp_tha + arppkt.arp_hln;
246  tha_netaddr = netaddr_macaddr_new(arp_tha, arppkt.arp_hln);
247  tpa_netaddr = netaddr_ipv4_new(arp_tpa, 0);
248 
249  /*
250  fprintf(stderr, "ARP Sender Hardware Address: %s %p\n", arp_sha->baseclass.toString(&arp_sha->baseclass), arp_sha);
251  fprintf(stderr, "ARP Sender Protocol Address: %s %p\n", arp_spa->baseclass.toString(&arp_spa->baseclass), arp_spa);
252  fprintf(stderr, "ARP Sender Protocol Address as IPV6: %s %p\n", arp_spaIPv6->baseclass.toString(&arp_spaIPv6->baseclass), arp_spaIPv6);
253  fprintf(stderr, "ARP Target Hardware Address: %s %p\n", arp_tha->baseclass.toString(&arp_tha->baseclass), arp_tha);
254  fprintf(stderr, "ARP Target Protocol Address: %s %p\n", arp_tpa->baseclass.toString(&arp_tpa->baseclass), arp_tpa);
255  */
256 
257  ++ self->baseclass.discovercount;
258 
259  v6string = arp_spaIPv6->baseclass.toString(&arp_spaIPv6->baseclass);
260  theMAC = self->ArpMapData->getaddr(self->ArpMapData, v6string);
261  if (NULL == theMAC) {
262  // The IP address is not already there, so add it to the ConfigContext hash table.
263  DEBUGMSG3("IP Address NOT in ConfigContext table: %s", v6string);
264  self->ArpMapData->setaddr(self->ArpMapData, v6string, sha_netaddr);
265  } else {
266  // If the IP address is already there, see if the MAC address is the same.
267  // If so, then we do not need to add it again.
268  DEBUGMSG3("IP Address FOUND in ConfigContext table: %s", v6string);
269  if ( ! theMAC->equal(theMAC, sha_netaddr) ) {
270  DEBUGMSG3(" ... but MAC address is different: %s", v6string);
271  self->ArpMapData->setaddr(self->ArpMapData, v6string, sha_netaddr);
272  }
273  }
274  g_free(v6string);
275  UNREF(sha_netaddr);
276  UNREF(spa_netaddr);
277  UNREF(tha_netaddr);
278  UNREF(tpa_netaddr);
279  UNREF(arp_spaIPv6);
280 
281  return TRUE;
282 }
283 
287 , gint priority
288 , GMainContext* mcontext
289 , NetGSource* iosrc
291 , gsize objsize)
292 {
293  Discovery * dret;
294  ArpDiscovery* ret;
295  const char* dev;
296  const char* instance;
297  int firstinterval;
298  int interval;
299  char* sysname;
300 
302  g_return_val_if_fail(arpconfig != NULL, NULL);
303  dev = arpconfig->getstring(arpconfig, CONFIGNAME_DEVNAME);
304  g_return_val_if_fail(dev != NULL, NULL);
305  instance = arpconfig->getstring(arpconfig, CONFIGNAME_INSTANCE);
306  g_return_val_if_fail(instance != NULL, NULL);
307  if (objsize < sizeof(ArpDiscovery)) {
308  objsize = sizeof(ArpDiscovery);
309  }
310  dret = discovery_new(instance, iosrc, config, objsize);
311  g_return_val_if_fail(dret != NULL, NULL);
312  interval = arpconfig->getint(arpconfig, CONFIGNAME_INTERVAL);
313  if (interval <= 0) {
314  interval = DEFAULT_ARP_SENDINTERVAL;
315  arpconfig->setint(arpconfig, CONFIGNAME_INTERVAL, interval);
316  }
317  ret = NEWSUBCLASS(ArpDiscovery, dret);
318 
319  ret->arpconfig = arpconfig;
320  REF(arpconfig);
321  ret->finalize = dret->baseclass._finalize;
324  ret->source = g_source_pcap_new(dev, ENABLE_ARP, _arpdiscovery_dispatch, NULL, priority, FALSE, mcontext, 0, ret);
325 
326  ret->ArpMap = configcontext_new_JSON_string("{\"discovertype\": \"ARP\", \"description\": \"ARP map\", \"source\": \"arpcache\", \"data\":{}}");
327  // Need to set host, and discoveryname
328  sysname = proj_get_sysname();
329  ret->ArpMap->setstring(ret->ArpMap, "host", sysname);
330  g_free(sysname); sysname = NULL;
331  ret->ArpMap->setstring(ret->ArpMap, CONFIGNAME_INSTANCE, instance);
332  ret->ArpMap->setstring(ret->ArpMap, CONFIGNAME_DEVNAME, dev);
333 
334  ret->ArpMapData = ret->ArpMap->getconfig(ret->ArpMap, "data");
335 
336  // Set the timer for initially when to send to the CMA
337  // We do start this randomly to keep multiple reporters from flooding the CMA
338  // It's not a bad idea in general, but until we select who is reporting ARPs
339  // it's a really wonderful idea.
340  firstinterval = g_rand_int_range(nano_random, interval, 2*interval);
341  ret->timeout_source
342  = g_timeout_add_seconds_full
343  (G_PRIORITY_HIGH, firstinterval, _arpdiscovery_first_discovery, ret, NULL);
344  DEBUGMSG3("Sender %p initial timeout source is: %d, interval is %d", ret
345  , ret->timeout_source, interval);
346 
347  if (objsize == sizeof(ArpDiscovery)) {
348  // Subclass constructors need to register themselves, but we'll register ourselves.
349  DUMP3("Registering ARP discovery", &dret->baseclass, " and returning it");
350  discovery_register(dret);
351  }
352  return ret;
353 }
354 
355 
357 FSTATIC void
359 {
360  gchar* jsonout = NULL;
361  gsize jsonlen = 0;
362  jsonout = self->ArpMap->baseclass.toString(&self->ArpMap->baseclass);
363  jsonlen = strlen(jsonout);
364  if (jsonlen == 0) {
365  g_warning("JSON arp discovery produced no output.");
366  return;
367  }
368  DEBUGMSG3("Got %zd bytes of JSON TEXT: [%s]", jsonlen, jsonout);
369  if (DEBUG) {
371  if (jsobj == NULL) {
372  g_warning("JSON arp discovery [%zd bytes] produced bad JSON.", jsonlen);
373  FREE(jsonout); jsonout = NULL;
374  return;
375  }else{
376  // Good output!
377  UNREF(jsobj);
378  }
379  }
380  DEBUGMSG3("Passing off ARP packet to sendjson() - hurray!");
381  self->baseclass.sendjson(&self->baseclass, jsonout, jsonlen);
382 }
383 
ConfigContext * configcontext_new_JSON_string(const char *jsontext)
Construct a ConfigContext object from the given JSON string.
#define CONFIGNAME_CMADISCOVER
Address of where to send discovery reports.
#define CONFIGNAME_INTERVAL
How long to wait between events.
ConfigContext * ArpMapData
The actual address portion.
Definition: arpdiscovery.h:41
void discovery_register(Discovery *self)
Function for registering a discovery object with the discovery infrastructure.
Definition: discovery.c:174
gboolean(* discover)(Discovery *self)
Perform the discovery.
Definition: discovery.h:51
void(* finalize)(AssimObj *self)
Saved parent class destructor.
Definition: arpdiscovery.h:39
Defines miscellaneous interfaces.
GRand * nano_random
Definition: nanoprobe.c:112
#define DEFAULT_ARP_SENDINTERVAL
Definition: arpdiscovery.h:47
char * proj_get_sysname(void)
Return a malloced string of the system name.
guint8 tlv_get_guint8(const void *vitem, const void *bufend)
Retrieve an unsigned 8 bit integer from the given location with error checking.
Definition: tlvhelper.c:31
NetAddr * netaddr_macaddr_new(gconstpointer macbuf, guint16 maclen)
Create new NetAddr from a MAC address.
Definition: netaddr.c:1061
GSource * g_source_pcap_new(const char *dev, unsigned listenmask, gboolean(*dispatch)(GSource_pcap_t *gsource, pcap_t *capstruct, gconstpointer pkt, gconstpointer pend, const struct pcap_pkthdr *pkthdr, const char *capturedev, gpointer userdata), GDestroyNotify notify, gint priority, gboolean can_recurse, GMainContext *context, gsize objectsize, gpointer userdata)
Construct new GSource from a newly constructed pcap capture object.
Definition: pcap_GSource.c:86
void(* setint)(ConfigContext *, const char *name, gint value)
Set integer value.
Definition: configcontext.h:75
#define ARP_PLN_LEN
Number of bytes for the Protocol Address Length field.
Definition: arpdiscovery.c:80
AssimObj baseclass
Definition: netaddr.h:44
const char *(* getstring)(const ConfigContext *, const char *name)
Get String value.
Definition: configcontext.h:86
NetAddr * netaddr_ipv4_new(gconstpointer ipbuf, guint16 port)
Create new NetAddr from a IPv4 address.
Definition: netaddr.c:1084
NetAddr *(* toIPv6)(const NetAddr *)
Convert this NetAddr to the IPv6 equivalent.
Definition: netaddr.h:56
#define ARP_HLN_LEN
Number of bytes for the Hardware Address Length field.
Definition: arpdiscovery.c:79
ArpDiscovery * arpdiscovery_new(ConfigContext *arpconfig, gint priority, GMainContext *mcontext, NetGSource *iosrc, ConfigContext *config, gsize objsize)
ArpDiscovery constructor - good for listening to ARP packets via pcap.
Definition: arpdiscovery.c:286
#define FSTATIC
Definition: projectcommon.h:31
#define DEBUGMSG3(...)
Definition: proj_classes.h:91
FSTATIC void _arpdiscovery_sendarpcache(ArpDiscovery *self)
Function for sending the ARP info in JSON to the CMA.
Definition: arpdiscovery.c:358
Discovery * discovery_new(const char *instname, NetGSource *iosource, ConfigContext *context, gsize objsize)
Discovery constructor.
Definition: discovery.c:143
FSTATIC gboolean _arpdiscovery_first_discovery(gpointer)
A GSourceFunc to be called for the first (random) discovery only
Definition: arpdiscovery.c:141
FSTATIC gboolean _arpdiscovery_discover(Discovery *self)
Discover member function for timed discovery – not applicable – return FALSE.
Definition: arpdiscovery.c:132
#define ARP_PKT_OFFSET
Number of bytes before the ARP packet itself starts.
Definition: arpdiscovery.c:76
#define BINDDEBUG(Cclass)
BINDDEBUG is for telling the class system where the debug variable for this class is - put it in the ...
Definition: proj_classes.h:82
#define DEBUG
Definition: proj_classes.h:85
#define ENABLE_ARP
Enable ARP protocol.
Definition: pcap_min.h:46
#define DUMP3(prefix, obj, suffix)
Definition: proj_classes.h:97
FSTATIC void _arpdiscovery_finalize(AssimObj *self)
finalize a ArpDiscovery object
Definition: arpdiscovery.c:105
gint64(* getint)(const ConfigContext *, const char *name)
Get integer value.
Definition: configcontext.h:74
#define CONFIGNAME_DEVNAME
Name of NIC for discovery.
#define FREE(m)
Our interface to free.
Definition: projectcommon.h:29
#define REF(obj)
Definition: assimobj.h:39
FSTATIC gboolean _arpdiscovery_dispatch(GSource_pcap_t *gsource, pcap_t *, gconstpointer, gconstpointer, const struct pcap_pkthdr *, const char *, gpointer selfptr)
Internal pcap gsource dispatch routine - called when we get an ARP packet.
Definition: arpdiscovery.c:177
include file defining functions to be called by a main to instantiate a nanoprobe.
gchar *(* toString)(gconstpointer)
Produce malloc-ed string representation.
Definition: assimobj.h:58
Project common header file.
TLV helper interfaces definitions.
#define ARP_HRD_LEN
Number of bytes for the Hardware Type field.
Definition: arpdiscovery.c:77
ConfigContext *(* getconfig)(const ConfigContext *, const char *name)
Get ConfigContext value.
Definition: configcontext.h:95
ConfigContext * arpconfig
Our configuration data.
Definition: arpdiscovery.h:42
Implements Configuration Context class.
g_main_loop GSource object for creating events from libpcap (pcap_t) objects We manage this with our ...
Definition: pcap_GSource.h:38
Discovery class abstract C-class - it supports discovering "things" through subclasses for different ...
Definition: discovery.h:47
Class for discovering address resolution (IP to MAC address information) using the ARP protocol...
#define ARP_PRO_LEN
Number of bytes for the Protocol Type field.
Definition: arpdiscovery.c:78
The NetAddr class class represents a general network address - whether IP, MAC, or any other type of ...
Definition: netaddr.h:43
gboolean(* equal)(const NetAddr *, const NetAddr *)
Compare NetAddrs.
Definition: netaddr.h:53
struct _ArpDiscovery ArpDiscovery
Definition: arpdiscovery.h:34
Defines interfaces for the NetAddr (network address) object.
GSource * source
GSource for the pcap data.
Definition: arpdiscovery.h:38
#define g_info(...)
Definition: projectcommon.h:66
#define CONFIGNAME_INSTANCE
Instance name for discovery.
void(* setstring)(ConfigContext *, const char *name, const char *value)
Definition: configcontext.h:87
guint timeout_source
timeout source id
Definition: arpdiscovery.h:43
NetAddr *(* getaddr)(const ConfigContext *, const char *name)
Get NetAddr value.
Definition: configcontext.h:92
#define DEBUGDECLARATIONS
Definition: proj_classes.h:79
ConfigContext * ArpMap
Arp IP/MAC addresses hash table.
Definition: arpdiscovery.h:40
ArpDiscovery C-class - for discovering IP/MAC address resolution via the ARP protocol captured using ...
Definition: arpdiscovery.h:36
void(* _finalize)(AssimObj *)
Free object (private)
Definition: assimobj.h:55
ConfigContext * _config
Configuration Parameters - has address of CMA.
Definition: discovery.h:62
guint16 tlv_get_guint16(const void *vitem, const void *bufend)
Retrieve an unsigned 16 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:55
#define CASTTOCLASS(Cclass, obj)
Safely cast &#39;obj&#39; to C-class &#39;class&#39; - verifying that it was registerd as being of type class ...
Definition: proj_classes.h:66
#define UNREF(obj)
Definition: assimobj.h:35
FSTATIC gboolean _arpdiscovery_gsourcefunc(gpointer)
Function which periodically sends our ARP cache upstream.
Definition: arpdiscovery.c:162
AssimObj baseclass
Base object class.
Definition: discovery.h:48
The NetGSource class objects integrate NetIO class objects into the g_main_loop paradigm.
Definition: netgsource.h:43
#define NEWSUBCLASS(Cclass, obj)
Definition: proj_classes.h:67
#define ARP_HDR_LEN
Number of bytes for the ARP Packet header info (before addresses start)
Definition: arpdiscovery.c:83