The Assimilation Monitoring 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 proto 0x2000 and ether dst 01:00:0c:cc:cc:cc)", "01:00:0c:cc:cc:cc"},
52 
53 };
54 
56 FSTATIC gboolean _enable_mcast_address(const char * addrstring, const char * dev, gboolean enable);
57 
63 pcap_t*
64 create_pcap_listener(const char * dev
65 , gboolean blocking
66 , unsigned listenmask
67 
68 , struct bpf_program*prog)
69 {
70  pcap_t* pcdescr = NULL;
71  bpf_u_int32 maskp;
72  bpf_u_int32 netp;
73  char errbuf[PCAP_ERRBUF_SIZE];
74  char * expr = NULL;
75  int filterlen = 1;
76  unsigned j;
77  int cnt=0;
78  int rc;
79  const char ORWORD [] = " or ";
80  gboolean need_promisc = FALSE;
81 
82  BINDDEBUG(pcap_t);
83 // setbuf(stdout, NULL);
84  setvbuf(stdout, NULL, _IONBF, 0);
85  errbuf[0] = '\0';
86 
87  // Search the list of valid bits so we can construct the libpcap filter
88  // for the given set of protocols on the fly...
89  // On this pass we just compute the amount of memory we'll need...
90  for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) {
91  if (listenmask & filterinfo[j].filterbit) {
92  ++cnt;
93  if (cnt > 1) {
94  filterlen += sizeof(ORWORD);
95  }
96  filterlen += strlen(filterinfo[j].filter);
97  }
98  }
99 
100  if (filterlen < 2) {
101  g_warning("Constructed filter is too short - invalid mask argument.");
102  return NULL;
103  }
104  if (NULL == (expr = malloc(filterlen))) {
105  g_error("Out of memory!");
106  return NULL;
107  }
108  // Same song, different verse...
109  // This time around, we construct the filter
110  expr[0] = '\0';
111  for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) {
112  if (listenmask & filterinfo[j].filterbit) {
113  ++cnt;
114  if (cnt > 1) {
115  g_strlcat(expr, ORWORD, filterlen);
116  }
117  g_strlcat(expr, filterinfo[j].filter, filterlen);
118  }
119  }
120  if (pcap_lookupnet(dev, &netp, &maskp, errbuf) != 0) {
121  g_warning("pcap_lookupnet failed: [%s]", errbuf);
122  goto oopsie;
123  }
124 
125  if (NULL == (pcdescr = pcap_create(dev, errbuf))) {
126  g_warning("pcap_create failed: [%s]", errbuf);
127  goto oopsie;
128  }
129  //pcap_set_promisc(pcdescr, FALSE);
130  for (j = 0; j < DIMOF(filterinfo); ++j) {
131  if (listenmask & filterinfo[j].filterbit) {
132  const char * addrstring = filterinfo[j].mcastaddr;
133  if (addrstring && !_enable_mcast_address(addrstring, dev, TRUE)) {
134  need_promisc = TRUE;
135  }
136  }
137  }
138  pcap_set_promisc(pcdescr, need_promisc);
139 #ifdef HAVE_PCAP_SET_RFMON
140  pcap_set_rfmon(pcdescr, FALSE);
141 #endif
142  pcap_setdirection(pcdescr, PCAP_D_IN);
143  // Weird bug - returns -3 and doesn't show an error message...
144  // And pcap_getnonblock also returns -3... Neither should happen AFAIK...
145  if ((rc = pcap_setnonblock(pcdescr, !blocking, errbuf)) < 0 && errbuf[0] != '\0') {
146  g_warning("pcap_setnonblock(%d) failed: [%s] [rc=%d]", !blocking, errbuf, rc);
147  g_warning("Have no idea why this happens - current blocking state is: %d."
148  , pcap_getnonblock(pcdescr, errbuf));
149  }
150  pcap_set_snaplen(pcdescr, 1500);
152  if (blocking) {
153  pcap_set_timeout(pcdescr, 240*1000);
154  }else{
155  pcap_set_timeout(pcdescr, 1);
156  }
157  //pcap_set_buffer_size(pcdescr, 1500);
158 
159  if (pcap_activate(pcdescr) != 0) {
160  g_warning("pcap_activate failed: [%s]", pcap_geterr(pcdescr));
161  goto oopsie;
162  }
163  if (pcap_compile(pcdescr, prog, expr, FALSE, maskp) < 0) {
164  g_warning("pcap_compile of [%s] failed: [%s]", expr, pcap_geterr(pcdescr));
165  goto oopsie;
166  }
167  if (pcap_setfilter(pcdescr, prog) < 0) {
168  g_warning("pcap_setfilter on [%s] failed: [%s]", expr, pcap_geterr(pcdescr));
169  goto oopsie;
170  }
171  DEBUGMSG1("Compile of [%s] worked!\n", expr);
172  free(expr); expr = NULL;
173  return(pcdescr);
174 
175 oopsie: // Some kind of failure - free things up and return NULL
176 
177  if (expr) {
178  free(expr);
179  expr = NULL;
180  }
181  if (pcdescr) {
182  close_pcap_listener(pcdescr, dev, listenmask);
183  pcdescr = NULL;
184  }
185  return NULL;
186 }
187 
189 void
190 close_pcap_listener(pcap_t* pcapdev
191 , const char* dev
192 , unsigned listenmask)
193 {
194  unsigned j;
195  pcap_close(pcapdev);
196  for (j = 0; j < DIMOF(filterinfo); ++j) {
197  if (listenmask & filterinfo[j].filterbit && filterinfo[j].mcastaddr) {
198  _enable_mcast_address(filterinfo[j].mcastaddr, dev, FALSE);
199  }
200  }
201 }
202 
203 
207 FSTATIC gboolean
208 _enable_mcast_address(const char * addrstring
209 , const char * dev
210 , gboolean enable)
211 {
212  GSpawnFlags flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH;
213  gint exit_status;
214  const gchar* constargv [] =
215  {"ip", "maddress", (enable ? "add" : "delete"), addrstring, "dev", dev, NULL};
216  gchar* argv[DIMOF(constargv)];
217  unsigned j;
218 
219 
220  if (NULL == addrstring) {
221  return FALSE;
222  }
223 
224  // This is really stupid and annoying - they have the wrong function prototype for g_spawn_sync...
225  for (j=0; j < DIMOF(argv); ++j) {
226  argv[j] = g_strdup(constargv[j]);
227  }
228 
229  DEBUGMSG1("Running IP command %s %s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
230  if (!g_spawn_sync(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL, &exit_status, NULL)) {
231  exit_status = 300;
232  }
233  for (j=0; j < DIMOF(argv); ++j) {
234  g_free(argv[j]);
235  argv[j] = NULL;
236  }
237  DEBUGMSG1("Previous IP command returned %d", exit_status);
238  return exit_status == 0;
239 }