The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups 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  g_warning("pcap_lookupnet failed: [%s]", errbuf);
124  goto oopsie;
125  }
126 
127  if (NULL == (pcdescr = pcap_create(dev, errbuf))) {
128  g_warning("pcap_create failed: [%s]", errbuf);
129  goto oopsie;
130  }
131  //pcap_set_promisc(pcdescr, FALSE);
132  for (j = 0; j < DIMOF(filterinfo); ++j) {
133  if (listenmask & filterinfo[j].filterbit) {
134  const char * addrstring = filterinfo[j].mcastaddr;
135  if (addrstring && !_enable_mcast_address(addrstring, dev, TRUE)) {
136  need_promisc = TRUE;
137  }
138  }
139  }
140  pcap_set_promisc(pcdescr, need_promisc);
141 #ifdef HAVE_PCAP_SET_RFMON
142  pcap_set_rfmon(pcdescr, FALSE);
143 #endif
144  pcap_setdirection(pcdescr, PCAP_D_IN);
145  // Weird bug - returns -3 and doesn't show an error message...
146  // And pcap_getnonblock also returns -3... Neither should happen AFAIK...
147  if ((rc = pcap_setnonblock(pcdescr, !blocking, errbuf)) < 0 && errbuf[0] != '\0') {
148  g_warning("pcap_setnonblock(%d) failed: [%s] [rc=%d]", !blocking, errbuf, rc);
149  g_warning("Have no idea why this happens - current blocking state is: %d."
150  , pcap_getnonblock(pcdescr, errbuf));
151  }
152  pcap_set_snaplen(pcdescr, 1500);
154  if (blocking) {
155  pcap_set_timeout(pcdescr, 240*1000);
156  }else{
157  pcap_set_timeout(pcdescr, 1);
158  }
159  //pcap_set_buffer_size(pcdescr, 1500);
160 
161  if (pcap_activate(pcdescr) != 0) {
162  g_warning("pcap_activate failed: [%s]", pcap_geterr(pcdescr));
163  goto oopsie;
164  }
165  if (pcap_compile(pcdescr, prog, expr, FALSE, maskp) < 0) {
166  g_warning("pcap_compile of [%s] failed: [%s]", expr, pcap_geterr(pcdescr));
167  goto oopsie;
168  }
169  if (pcap_setfilter(pcdescr, prog) < 0) {
170  g_warning("pcap_setfilter on [%s] failed: [%s]", expr, pcap_geterr(pcdescr));
171  goto oopsie;
172  }
173  DEBUGMSG1("Compile of [%s] worked!\n", expr);
174  free(expr); expr = NULL;
175  return(pcdescr);
176 
177 oopsie: // Some kind of failure - free things up and return NULL
178 
179  if (expr) {
180  free(expr);
181  expr = NULL;
182  }
183  if (pcdescr) {
184  close_pcap_listener(pcdescr, dev, listenmask);
185  pcdescr = NULL;
186  }
187  return NULL;
188 }
189 
191 void
192 close_pcap_listener(pcap_t* pcapdev
193 , const char* dev
194 , unsigned listenmask)
195 {
196  unsigned j;
197  pcap_close(pcapdev);
198  for (j = 0; j < DIMOF(filterinfo); ++j) {
199  if (listenmask & filterinfo[j].filterbit && filterinfo[j].mcastaddr) {
200  _enable_mcast_address(filterinfo[j].mcastaddr, dev, FALSE);
201  }
202  }
203 }
204 
205 
209 FSTATIC gboolean
210 _enable_mcast_address(const char * addrstring
211 , const char * dev
212 , gboolean enable)
213 {
214  GSpawnFlags flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH;
215  gint exit_status;
216  const gchar* constargv [] =
217  {"ip", "maddress", (enable ? "add" : "delete"), addrstring, "dev", dev, NULL};
218  gchar* argv[DIMOF(constargv)];
219  unsigned j;
220 
221 
222  if (NULL == addrstring) {
223  return FALSE;
224  }
225 
226  // This is really stupid and annoying - they have the wrong function prototype for g_spawn_sync...
227  for (j=0; j < DIMOF(argv); ++j) {
228  argv[j] = g_strdup(constargv[j]);
229  }
230 
231  DEBUGMSG1("Running IP command %s %s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
232  if (!g_spawn_sync(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL, &exit_status, NULL)) {
233  exit_status = 300;
234  }
235  for (j=0; j < DIMOF(argv); ++j) {
236  g_free(argv[j]);
237  argv[j] = NULL;
238  }
239  DEBUGMSG1("Previous IP command returned %d", exit_status);
240  return exit_status == 0;
241 }
#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:192
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 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.
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:210