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