The Assimilation Project  based on Assimilation version 0.5.1435592714
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
pcap_min.c
Go to the documentation of this file.
1 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <projectcommon.h>
35 #include <cdp.h>
36 #include <lldp.h>
37 #include <pcap_min.h>
38 #include <addrframe.h>
39 #include <proj_classes.h>
40 
41 #define DIMOF(a) (sizeof(a)/sizeof(a[0]))
42 
43 
45 static struct pcap_filter_info {
46  const unsigned filterbit;
47  const char * filter;
48  const char * mcastaddr;
49 }filterinfo[] = {
50  {ENABLE_LLDP, "(ether proto 0x88cc and ether dst 01:80:c2:00:00:0e)", "01:80:c2:00:00:0e"},
51  //{ENABLE_CDP, "(ether dst 01:00:0c:cc:cc:cc and ether[20:2] == 0x2000)", "01:00:0c:cc:cc:cc"},
52  {ENABLE_CDP, "(ether dst 01:00:0c:cc:cc:cc)", "01:00:0c:cc:cc:cc"},
53  {ENABLE_ARP, "(arp)", NULL},
54 
55 };
56 
58 FSTATIC gboolean _enable_mcast_address(const char * addrstring, const char * dev, gboolean enable);
59 
65 pcap_t*
66 create_pcap_listener(const char * dev
67 , gboolean blocking
68 , unsigned listenmask
69 , struct bpf_program*prog)
71 {
72  pcap_t* pcdescr = NULL;
73  bpf_u_int32 maskp = 0;
74  bpf_u_int32 netp = 0;
75  char errbuf[PCAP_ERRBUF_SIZE];
76  char * expr = NULL;
77  int filterlen = 1;
78  unsigned j;
79  int cnt=0;
80  int rc;
81  const char ORWORD [] = " or ";
82  gboolean need_promisc = FALSE;
83 
84  BINDDEBUG(pcap_t);
85 // setbuf(stdout, NULL);
86  setvbuf(stdout, NULL, _IONBF, 0);
87  errbuf[0] = '\0';
88 
89  // Search the list of valid bits so we can construct the libpcap filter
90  // for the given set of protocols on the fly...
91  // On this pass we just compute the amount of memory we'll need...
92  for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) {
93  if (listenmask & filterinfo[j].filterbit) {
94  ++cnt;
95  if (cnt > 1) {
96  filterlen += sizeof(ORWORD);
97  }
98  filterlen += strlen(filterinfo[j].filter);
99  }
100  }
101 
102  if (filterlen < 2) {
103  g_warning("Constructed filter is too short - invalid mask argument.");
104  return NULL;
105  }
106  if (NULL == (expr = malloc(filterlen))) {
107  g_error("Out of memory!");
108  return NULL;
109  }
110  // Same song, different verse...
111  // This time around, we construct the filter
112  expr[0] = '\0';
113  for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) {
114  if (listenmask & filterinfo[j].filterbit) {
115  ++cnt;
116  if (cnt > 1) {
117  g_strlcat(expr, ORWORD, filterlen);
118  }
119  g_strlcat(expr, filterinfo[j].filter, filterlen);
120  }
121  }
122  if (pcap_lookupnet(dev, &netp, &maskp, errbuf) != 0) {
123  // This is not a problem for non-IPv4 protocols...
124  // It just looks up the ipv4 address - which we mostly don't care about.
125  g_info("%s.%d: pcap_lookupnet(\"%s\") failed: [%s]"
126  , __FUNCTION__, __LINE__, dev, errbuf);
127  }
128 
129  if (NULL == (pcdescr = pcap_create(dev, errbuf))) {
130  g_warning("pcap_create failed: [%s]", errbuf);
131  goto oopsie;
132  }
133  //pcap_set_promisc(pcdescr, FALSE);
134  for (j = 0; j < DIMOF(filterinfo); ++j) {
135  if (listenmask & filterinfo[j].filterbit) {
136  const char * addrstring = filterinfo[j].mcastaddr;
137  if (addrstring && !_enable_mcast_address(addrstring, dev, TRUE)) {
138  need_promisc = TRUE;
139  }
140  }
141  }
142  pcap_set_promisc(pcdescr, need_promisc);
143 #ifdef HAVE_PCAP_SET_RFMON
144  pcap_set_rfmon(pcdescr, FALSE);
145 #endif
146  pcap_setdirection(pcdescr, PCAP_D_IN);
147  // Weird bug - returns -3 and doesn't show an error message...
148  // And pcap_getnonblock also returns -3... Neither should happen AFAIK...
149  errbuf[0] = '\0';
150  if ((rc = pcap_setnonblock(pcdescr, !blocking, errbuf)) < 0 && errbuf[0] != '\0') {
151  g_warning("pcap_setnonblock(%d) failed: [%s] [rc=%d]", !blocking, errbuf, rc);
152  g_warning("Have no idea why this happens - current blocking state is: %d."
153  , pcap_getnonblock(pcdescr, errbuf));
154  }
155  pcap_set_snaplen(pcdescr, 1500);
157  if (blocking) {
158  pcap_set_timeout(pcdescr, 240*1000);
159  }else{
160  pcap_set_timeout(pcdescr, 1);
161  }
162  //pcap_set_buffer_size(pcdescr, 1500);
163 
164  if (pcap_activate(pcdescr) != 0) {
165  g_warning("pcap_activate failed: [%s]", pcap_geterr(pcdescr));
166  goto oopsie;
167  }
168  if (pcap_compile(pcdescr, prog, expr, FALSE, maskp) < 0) {
169  g_warning("pcap_compile of [%s] failed: [%s]", expr, pcap_geterr(pcdescr));
170  goto oopsie;
171  }
172  if (pcap_setfilter(pcdescr, prog) < 0) {
173  g_warning("pcap_setfilter on [%s] failed: [%s]", expr, pcap_geterr(pcdescr));
174  goto oopsie;
175  }
176  DEBUGMSG1("Compile of [%s] worked!", expr);
177  g_info("Compile of [%s] worked! Returning %p", expr, pcdescr);
178  free(expr); expr = NULL;
179  return(pcdescr);
180 
181 oopsie: // Some kind of failure - free things up and return NULL
182 
183  g_warning("%s.%d: Could not set up PCAP on %s"
184  , __FUNCTION__, __LINE__, dev);
185  if (expr) {
186  free(expr);
187  expr = NULL;
188  }
189  if (pcdescr) {
190  close_pcap_listener(pcdescr, dev, listenmask);
191  pcdescr = NULL;
192  }
193  return NULL;
194 }
195 
197 void
198 close_pcap_listener(pcap_t* pcapdev
199 , const char* dev
200 , unsigned listenmask)
201 {
202  unsigned j;
203  pcap_close(pcapdev);
204  for (j = 0; j < DIMOF(filterinfo); ++j) {
205  if (listenmask & filterinfo[j].filterbit && filterinfo[j].mcastaddr) {
206  _enable_mcast_address(filterinfo[j].mcastaddr, dev, FALSE);
207  }
208  }
209 }
210 
211 
215 FSTATIC gboolean
216 _enable_mcast_address(const char * addrstring
217 , const char * dev
218 , gboolean enable)
219 {
220  GSpawnFlags flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH;
221  gint exit_status;
222  const gchar* constargv [] =
223  {"ip", "maddress", (enable ? "add" : "delete"), addrstring, "dev", dev, NULL};
224  gchar* argv[DIMOF(constargv)];
225  unsigned j;
226 
227 
228  if (NULL == addrstring) {
229  return FALSE;
230  }
231 
232  // This is really stupid and annoying - they have the wrong function prototype for g_spawn_sync...
233  for (j=0; j < DIMOF(argv); ++j) {
234  argv[j] = g_strdup(constargv[j]);
235  }
236 
237  DEBUGMSG1("Running IP command %s %s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
238  if (!g_spawn_sync(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL, &exit_status, NULL)) {
239  exit_status = 300;
240  }
241  for (j=0; j < DIMOF(argv); ++j) {
242  g_free(argv[j]);
243  argv[j] = NULL;
244  }
245  DEBUGMSG1("Previous IP command returned %d", exit_status);
246  return exit_status == 0;
247 }
#define ENABLE_CDP
Enable CDP protocol.
Definition: pcap_min.h:42
#define DIMOF(a)
Definition: pcap_min.c:41
#define DEBUGMSG1(...)
Definition: proj_classes.h:89
#define ENABLE_LLDP
Enable LLDP protocol.
Definition: pcap_min.h:40
void close_pcap_listener(pcap_t *pcapdev, const char *dev, unsigned listenmask)
Close this pcap_listener, and undo listens for multicast addresses.
Definition: pcap_min.c:198
Simple libpcap interface definitions.
#define FSTATIC
Definition: projectcommon.h:31
#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 __FUNCTION__
#define ENABLE_ARP
Enable ARP protocol.
Definition: pcap_min.h:44
Provides basic Link Layer Discovery Protocol (LLDP) definitions and accessor functions for LLPD packe...
Project common header file.
pcap_t * create_pcap_listener(const char *dev, gboolean blocking, unsigned listenmask, struct bpf_program *prog)
Set up pcap listener for the given interfaces and protocols.
Definition: pcap_min.c:66
Header file for various basic CDP (Cisco Discovery Protocol definitions and accessor functions...
Describes interfaces to Address Frame (AddrFrame) C-Class.
#define g_info(...)
Definition: projectcommon.h:66
Defines interfaces a project Class system for class hierarchies in 'C'.
#define DEBUGDECLARATIONS
Definition: proj_classes.h:79
DEBUGDECLARATIONS FSTATIC gboolean _enable_mcast_address(const char *addrstring, const char *dev, gboolean enable)
Function to enable listening to a particular ethernet multicast address.
Definition: pcap_min.c:216