libutil++  1.9.3
 All Classes Functions Variables
Interface.cpp
1 /*
2 ** libutil++
3 ** $Id: Interface.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: Interface.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "Interface.h"
12 #include "../net/IPAddress.h"
13 #include "CommonMacro.h"
14 
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <ifaddrs.h>
19 #include <net/if.h>
20 #include <sys/types.h>
21 #include <netpacket/packet.h>
22 
23 
24 #include <string>
25 
26 #define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof(sa.sin_port)])
27 #define IFRSIZE ((int)(size * sizeof(struct ifreq)))
28 
29 namespace sn = sella::net;
30 using namespace sella::util;
31 
32 void Interface::setPromiscous(const std::string &interface, bool on) throw (InterfaceException) {
33  int s;
34  struct ifreq ifr;
35  size_t len = interface.size();
36  struct packet_mreq mr;
37 
38  if (len < sizeof(ifr.ifr_name)) {
39  memcpy(ifr.ifr_name, interface.c_str(), len);
40  ifr.ifr_name[len] = 0;
41  } else {
42  THROW(InterfaceException, "Interface name '%s' is too long", interface.c_str());
43  }
44 
45  if ((s = socket(AF_PACKET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
46  THROW2(InterfaceException, "socket()");
47  }
48 
49  if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
50  close(s);
51 
52  THROW2(InterfaceException, "ioctl()");
53  }
54 
55  memset(&mr, 0, sizeof(mr));
56  mr.mr_ifindex = ifr.ifr_ifindex;
57  mr.mr_type = PACKET_MR_PROMISC;
58 
59  if (setsockopt(s, SOL_PACKET, (on) ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0) {
60  close(s);
61 
62  THROW2(InterfaceException, "setsockopt()");
63  }
64 
65  close(s);
66 }
67 
68 std::string Interface::getInterface(const sella::net::IPAddress &address, const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
69  struct ifaddrs *ifas, *ifa = NULL;
70  int family;
71  std::string interface;
72 
73  if (getifaddrs(&ifas) == -1) {
74  THROW(InterfaceException, "Failed to retrieve interfaces");
75  }
76 
77  for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
78  if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
79  continue;
80  }
81 
82  if (ifa->ifa_addr != NULL) {
83  family = ifa->ifa_addr->sa_family;
84 
85  if (family == AF_INET || family == AF_INET6) {
86  sn::IPAddress addr(ifa->ifa_addr);
87 
88  if (address == addr) {
89  interface = ifa->ifa_name;
90 
91  break;
92  }
93  }
94  }
95  }
96 
97  freeifaddrs(ifas);
98 
99  return interface;
100 }
101 
102 sn::IPAddress::shared_list Interface::getIPAddresses(const std::string &interface, const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
103  struct ifaddrs *ifas, *ifa = NULL;
104  sn::IPAddress::shared_list addresses;
105  sn::IPAddress::shared address;
106  int family;
107 
108  if (getifaddrs(&ifas) == -1) {
109  THROW(InterfaceException, "Failed to retrieve interfaces");
110  }
111 
112  for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
113  if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
114  continue;
115  }
116 
117  if (ifa->ifa_addr != NULL) {
118  if (!interface.empty() && interface.compare(ifa->ifa_name)) {
119  continue;
120  }
121 
122  family = ifa->ifa_addr->sa_family;
123  if (family == AF_INET || family == AF_INET6) {
124  address = sn::IPAddress::shared_ptr(ifa->ifa_addr);
125  addresses.push_back(address);
126  }
127  }
128  }
129  freeifaddrs(ifas);
130 
131  addresses.sort();
132  addresses.unique();
133 
134  return addresses;
135 }
136 
137 #if 0
138 sn::IPAddress::shared_list Interface::getInterfaceIPAddresses(const std::string &interface, const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
139  return getIPAddresses(interface, ifrFlagMatch, ifrFlagReject);
140 }
141 #endif
142 
143 sella::net::IPAddress Interface::getIPAddress(const std::string &interface, int family) throw (InterfaceException) {
144  struct ifaddrs *ifas, *ifa = NULL;
145  sn::IPAddress address;
146 
147  if (getifaddrs(&ifas) == -1) {
148  THROW(InterfaceException, "Failed to retrieve interfaces");
149  }
150 
151  for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
152  if (ifa->ifa_addr != NULL) {
153  if (!interface.empty() && interface.compare(ifa->ifa_name)) {
154  continue;
155  }
156 
157  if (ifa->ifa_addr->sa_family == family) {
158  address = sn::IPAddress(ifa->ifa_addr);
159 
160  break;
161  }
162  }
163  }
164  freeifaddrs(ifas);
165 
166  return address;
167 }
168 
169 std::list<std::string> Interface::getNames(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
170  struct ifaddrs *ifas, *ifa = NULL;
171  std::list<std::string> interfaces;
172  std::list<std::string>::iterator it;
173 
174  if (getifaddrs(&ifas) == -1) {
175  THROW2(InterfaceException, "getifaddrs()");
176  }
177 
178  for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
179  if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
180  continue;
181  }
182 
183 // if (ifa->ifa_addr != NULL) {
184  interfaces.push_back(ifa->ifa_name);
185 // }
186  }
187  freeifaddrs(ifas);
188 
189  interfaces.sort();
190  interfaces.unique();
191 
192  return interfaces;
193 }
194 
195 #if 0
196 std::list<std::string> Interface::getInterfaceNames(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
197  return getNames(ifrFlagMatch, ifrFlagReject);
198 }
199 #endif
200 
201 std::list<std::string> Interface::getEthernetNames(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
202  struct ifaddrs *ifas, *ifa = NULL;
203  std::list<std::string> interfaces;
204  std::list<std::string>::iterator it;
205 
206  if (getifaddrs(&ifas) == -1) {
207  THROW2(InterfaceException, "getifaddrs()");
208  }
209 
210  for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
211  if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
212  continue;
213  } else if (!isEthernet(ifa->ifa_name)) {
214  continue;
215  }
216 
217  interfaces.push_back(ifa->ifa_name);
218  }
219  freeifaddrs(ifas);
220 
221  interfaces.sort();
222  interfaces.unique();
223 
224  return interfaces;
225 }
226 
227 std::string Interface::getMAC(const std::string &interface) throw (InterfaceException) {
228  int s;
229  struct ifreq ifr;
230  unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
231  char mac[19];
232 
233  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
234  THROW2(InterfaceException, "socket()");
235  }
236 
237  strcpy(ifr.ifr_name, interface.c_str());
238 
239  if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
240  THROW2(InterfaceException, "ioctl()");
241  }
242 
243  if (memcmp(ifr.ifr_hwaddr.sa_data, none, sizeof(none)) == 0) {
244  THROW(InterfaceException, "Interface %s has no MAC", interface.c_str());
245  }
246 
247  unsigned char *m = (unsigned char*) ifr.ifr_hwaddr.sa_data;
248  snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
249 
250  return mac;
251 }
252 
253 #if 0
254 std::string Interface::getInterfaceMAC(const std::string &interface) throw (InterfaceException) {
255  return getMAC(interface);
256 }
257 #endif
258 
259 std::list<std::string> Interface::getMACs(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
260  int s;
261  struct ifreq ifr;
262  unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
263  char mac[19];
264  std::list<std::string> macs;
265  auto interfaces = getNames(ifrFlagMatch, (ifrFlagReject | IFF_LOOPBACK));
266 
267  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
268  THROW2(InterfaceException, "socket()");
269  }
270 
271  for (auto it = interfaces.begin(); it != interfaces.end(); ++it) {
272  strcpy(ifr.ifr_name, it->c_str());
273 
274  if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
275  THROW2(InterfaceException, "ioctl()");
276  }
277 
278  if (memcmp(ifr.ifr_hwaddr.sa_data, none, sizeof(none)) == 0) {
279  continue;
280  }
281 
282  unsigned char *m = (unsigned char*) ifr.ifr_hwaddr.sa_data;
283  snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
284 
285  macs.push_back(mac);
286  }
287 
288  macs.sort();
289  macs.unique();
290 
291  return macs;
292 }
293 
294 #if 0
295 std::list<std::string> Interface::getInterfaceMACs(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
296  return getMACs(ifrFlagMatch, ifrFlagReject);
297 }
298 
299 void Interface::getInterfaceAddr(const std::string &interface, struct in_addr *ip) throw (InterfaceException) {
300  getAddr(interface, ip);
301 }
302 #endif
303 
304 // Adapted from newsgroup example by Floyd Davidson (floyd@ptialaska.net) on 2002-07-16 04:50:07 PST
305 struct in_addr* Interface::getAddr(const std::string &interface, struct in_addr *ip) throw (InterfaceException) {
306  int s, size = 1;
307  struct ifreq *ifr;
308  struct ifconf ifc;
309  struct sockaddr_in sa;
310  struct ifreq *tmp;
311 
312  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
313  THROW2(InterfaceException, "socket()");
314  }
315 
316  ifc.ifc_len = IFRSIZE;
317  ifc.ifc_req = NULL;
318 
319  do {
320  ++size;
321  /* realloc buffer size until no overflow occurs */
322  if (NULL == (tmp = (struct ifreq*) realloc(ifc.ifc_req, IFRSIZE))) {
323  SAFE_FREE(ifc.ifc_req); /* Free memory. */
324  close(s);
325 
326  THROW(InterfaceException, "Failed to realloc");
327  }
328 
329  ifc.ifc_req = tmp;
330  ifc.ifc_len = IFRSIZE;
331 
332  if (ioctl(s, SIOCGIFCONF, &ifc)) {
333  SAFE_FREE(ifc.ifc_req); /* Free memory. */
334  close(s);
335 
336  THROW2(InterfaceException, "ioctl()");
337  }
338  } while (IFRSIZE <= ifc.ifc_len);
339 
340  ifr = ifc.ifc_req;
341  for (;(char *) ifr < (char *) ifc.ifc_req + ifc.ifc_len; ++ifr) {
342 
343  if (ifr->ifr_addr.sa_data == (ifr + 1)->ifr_addr.sa_data) {
344  continue; /* duplicate, skip it */
345  }
346 
347  if (ioctl(s, SIOCGIFFLAGS, ifr)) {
348  continue; /* failed to get flags, skip it */
349  }
350 
351  if (strncmp(ifr->ifr_name, "lo", 2) && (interface.empty() || !strcmp(ifr->ifr_name, interface.c_str()))) {
352 #ifndef USE_ORIGINAL /* Work around for: "warning: dereferencing type-punned pointer will break strict-aliasing rules" */
353  union {
354  char c;
355  struct in_addr addr;
356  } u;
357 
358  u.c = ifr->ifr_addr.sa_data[sizeof(sa.sin_port)];
359  *ip = u.addr;
360 #else
361  *ip = inaddrr(ifr_addr.sa_data);
362 #endif
363 
364 #if 0
365  fprintf(stderr, "Interface: %s\n", ifr->ifr_name);
366  fprintf(stderr, "IP Address: %s\n", inet_ntoa(*ip));
367 #endif
368 
369  break;
370  }
371  }
372 
373  SAFE_FREE(ifc.ifc_req); /* Free memory. */
374  close(s);
375 
376  return ip;
377 }
378 
379 unsigned int Interface::getIndex(const std::string &interface) throw (InterfaceException) {
380 #define USE_NAMETOINDEX
381 #ifdef USE_NAMETOINDEX
382  unsigned int index;
383 
384  if ((index = if_nametoindex(interface.c_str())) > 0) {
385  return index;
386  }
387 
388  THROW2(InterfaceException, "if_nametoindex()");
389 #else
390  int s;
391  struct ifreq ifr;
392  size_t len = interface.size();
393 
394  if (len < sizeof(ifr.ifr_name)) {
395  memcpy(ifr.ifr_name, interface.c_str(), len);
396  ifr.ifr_name[len] = 0;
397  } else {
398  THROW(InterfaceException, "Interface name '%s' is too long", interface.c_str());
399  }
400 
401  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
402  THROW2(InterfaceException, "socket()");
403  }
404 
405  if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
406  close(s);
407 
408  THROW2(InterfaceException, "ioctl()");
409  }
410 
411  close(s);
412 
413  return ifr.ifr_ifindex;
414 #endif
415 }
416 
417 std::string Interface::getName(unsigned int index) throw (InterfaceException) {
418  char buf[IF_NAMESIZE];
419 
420  if (if_indextoname(index, buf) != NULL) {
421  return std::string(buf);
422  }
423 
424  THROW2(InterfaceException, "if_indextoname()");
425 }
426 
427 unsigned char* Interface::convertMAC(unsigned char dst[6], const std::string &mac) throw (InterfaceException) {
428  if (mac.size() == 17) {
429  if ((mac[2] != ':' && mac[2] != '-') || (mac[5] != ':' && mac[5] != '-') || (mac[8] != ':' && mac[8] != '-') || (mac[11] != ':' && mac[11] != '-') || (mac[14] != ':' && mac[14] != '-')) {
430  THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
431  }
432 
433  if (sscanf(mac.c_str(), "%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx", &dst[0], &dst[1], &dst[2], &dst[3], &dst[4], &dst[5]) == 6) {
434  return dst;
435  }
436  } else if (mac.size() == 12) {
437  if (sscanf(mac.c_str(), "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", &dst[0], &dst[1], &dst[2], &dst[3], &dst[4], &dst[5]) == 6) {
438  return dst;
439  }
440  }
441 
442  THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
443 }
444 
445 std::string& Interface::convertMAC(std::string &dst, const unsigned char mac[6], char delim) throw (InterfaceException) {
446  char buf[4];
447 
448  if (delim > 0 && delim < 32 && delim > 127) {
449  THROW(InterfaceException, "Invalid MAC delim");
450  }
451 
452  dst.clear();
453 
454  for (size_t i = 0; i < 6; i++) {
455  if (delim > 0 && i > 0) {
456  dst.push_back(delim);
457  }
458 
459  snprintf(buf, sizeof(buf), "%02X", mac[i]);
460 
461  dst += buf;
462  }
463 
464  return dst;
465 }
466 
467 unsigned char* Interface::convertMAC(unsigned char dst[6], const uint64_t mac) throw (InterfaceException) {
468  dst[0] = 0x000000ff & (mac >> 40);
469  dst[1] = 0x000000ff & (mac >> 32);
470  dst[2] = 0x000000ff & (mac >> 24);
471  dst[3] = 0x000000ff & (mac >> 16);
472  dst[4] = 0x000000ff & (mac >> 8);
473  dst[5] = 0x000000ff & mac;
474 
475  return dst;
476 }
477 
478 uint64_t& Interface::convertMAC(uint64_t &dst, const unsigned char mac[6]) throw (InterfaceException) {
479  dst = uint64_t(mac[0]) << 40 | uint64_t(mac[1]) << 32 | uint64_t(mac[2]) << 24 | uint64_t(mac[3]) << 16 | uint64_t(mac[4]) << 8 | uint64_t(mac[5]);
480 
481  return dst;
482 }
483 
484 std::string& Interface::convertMAC(std::string &dst, const uint64_t mac) throw (InterfaceException) {
485  unsigned char addr[6];
486 
487  convertMAC(addr, mac);
488 
489  return convertMAC(dst, addr);
490 }
491 
492 uint64_t& Interface::convertMAC(uint64_t &dst, const std::string &mac) throw (InterfaceException) {
493  unsigned char addr[6];
494 
495  convertMAC(addr, mac);
496 
497  return convertMAC(dst, addr);
498 }
499 
500 bool Interface::isEthernet(const std::string &interface) throw (InterfaceException) {
501  int s;
502  struct ifreq ifr;
503  unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
504 
505  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
506  THROW2(InterfaceException, "socket()");
507  }
508 
509  strcpy(ifr.ifr_name, interface.c_str());
510 
511  if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
512  THROW2(InterfaceException, "ioctl()");
513  }
514 
515  if (memcmp(ifr.ifr_hwaddr.sa_data, none, sizeof(none)) == 0) {
516  return false;
517  }
518 
519  return true;
520 }
521 
522 #if 0
523 unsigned char* Interface::parseMAC(const std::string &mac, unsigned char addr[6]) throw (InterfaceException) {
524  if (mac.size() == 17) {
525  if ((mac[2] != ':' && mac[2] != '-') || (mac[5] != ':' && mac[5] != '-') || (mac[8] != ':' && mac[8] != '-') || (mac[11] != ':' && mac[11] != '-') || (mac[14] != ':' && mac[14] != '-')) {
526  THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
527  }
528 
529  if (sscanf(mac.c_str(), "%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) == 6) {
530  return addr;
531  }
532  } else if (mac.size() == 12) {
533  if (sscanf(mac.c_str(), "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) == 6) {
534  return addr;
535  }
536  }
537 
538  THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
539 }
540 
541 sn::IPAddress::shared_list Interface::interfaceIPAddressList(const std::string &interface, const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
542  return getIPAddresses(interface, ifrFlagMatch, ifrFlagReject);
543 }
544 
545 std::list<std::string> Interface::interfaceNameList(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
546  return getNames(ifrFlagMatch, ifrFlagReject);
547 }
548 
549 std::list<std::string> Interface::interfaceMACList(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
550  return getMACs(ifrFlagMatch, ifrFlagReject);
551 }
552 
553 void Interface::source_ip(char *interface, struct in_addr *ip) throw (InterfaceException) {
554  getAddr(interface, ip);
555 }
556 #endif
557 
558 /*
559 ** vim: noet ts=3 sw=3
560 */