The Assimilation Project  based on Assimilation version 0.5.1441048221
 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  free(expr); expr = NULL;
178  return(pcdescr);
179 
180 oopsie: // Some kind of failure - free things up and return NULL
181 
182  g_warning("%s.%d: Could not set up PCAP on %s"
183  , __FUNCTION__, __LINE__, dev);
184  if (expr) {
185  free(expr);
186  expr = NULL;
187  }
188  if (pcdescr) {
189  close_pcap_listener(pcdescr, dev, listenmask);
190  pcdescr = NULL;
191  }
192  return NULL;
193 }
194 
196 void
197 close_pcap_listener(pcap_t* pcapdev
198 , const char* dev
199 , unsigned listenmask)
200 {
201  unsigned j;
202  pcap_close(pcapdev);
203  for (j = 0; j < DIMOF(filterinfo); ++j) {
204  if (listenmask & filterinfo[j].filterbit && filterinfo[j].mcastaddr) {
205  _enable_mcast_address(filterinfo[j].mcastaddr, dev, FALSE);
206  }
207  }
208 }
209 
210 
214 FSTATIC gboolean
215 _enable_mcast_address(const char * addrstring
216 , const char * dev
217 , gboolean enable)
218 {
219  GSpawnFlags flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH;
220  gint exit_status;
221  const gchar* constargv [] =
222  {"ip", "maddress", (enable ? "add" : "delete"), addrstring, "dev", dev, NULL};
223  gchar* argv[DIMOF(constargv)];
224  unsigned j;
225 
226 
227  if (NULL == addrstring) {
228  return FALSE;
229  }
230 
231  // This is really stupid and annoying - they have the wrong function prototype for g_spawn_sync...
232  for (j=0; j < DIMOF(argv); ++j) {
233  argv[j] = g_strdup(constargv[j]);
234  }
235 
236  DEBUGMSG1("Running IP command %s %s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
237  if (!g_spawn_sync(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL, &exit_status, NULL)) {
238  exit_status = 300;
239  }
240  for (j=0; j < DIMOF(argv); ++j) {
241  g_free(argv[j]);
242  argv[j] = NULL;
243  }
244  DEBUGMSG1("Previous IP command returned %d", exit_status);
245  return exit_status == 0;
246 }
#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:197
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:215