9 static const char rcsid[] __attribute__((used)) =
"$Id: Interface.cpp 1653 2016-02-28 19:54:59Z sella $";
11 #include "Interface.h"
12 #include "../net/IPAddress.h"
13 #include "CommonMacro.h"
20 #include <sys/types.h>
21 #include <netpacket/packet.h>
26 #define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof(sa.sin_port)])
27 #define IFRSIZE ((int)(size * sizeof(struct ifreq)))
29 namespace sn = sella::net;
30 using namespace sella::util;
32 void Interface::setPromiscous(
const std::string &interface,
bool on)
throw (InterfaceException) {
35 size_t len = interface.size();
36 struct packet_mreq mr;
38 if (len <
sizeof(ifr.ifr_name)) {
39 memcpy(ifr.ifr_name, interface.c_str(), len);
40 ifr.ifr_name[len] = 0;
42 THROW(InterfaceException,
"Interface name '%s' is too long", interface.c_str());
45 if ((s = socket(AF_PACKET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
46 THROW2(InterfaceException,
"socket()");
49 if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
52 THROW2(InterfaceException,
"ioctl()");
55 memset(&mr, 0,
sizeof(mr));
56 mr.mr_ifindex = ifr.ifr_ifindex;
57 mr.mr_type = PACKET_MR_PROMISC;
59 if (setsockopt(s, SOL_PACKET, (on) ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, &mr,
sizeof(mr)) < 0) {
62 THROW2(InterfaceException,
"setsockopt()");
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;
71 std::string interface;
73 if (getifaddrs(&ifas) == -1) {
74 THROW(InterfaceException,
"Failed to retrieve interfaces");
77 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
78 if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
82 if (ifa->ifa_addr != NULL) {
83 family = ifa->ifa_addr->sa_family;
85 if (family == AF_INET || family == AF_INET6) {
88 if (address == addr) {
89 interface = ifa->ifa_name;
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;
108 if (getifaddrs(&ifas) == -1) {
109 THROW(InterfaceException,
"Failed to retrieve interfaces");
112 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
113 if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
117 if (ifa->ifa_addr != NULL) {
118 if (!interface.empty() && interface.compare(ifa->ifa_name)) {
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);
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);
143 sella::net::IPAddress Interface::getIPAddress(
const std::string &interface,
int family)
throw (InterfaceException) {
144 struct ifaddrs *ifas, *ifa = NULL;
147 if (getifaddrs(&ifas) == -1) {
148 THROW(InterfaceException,
"Failed to retrieve interfaces");
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)) {
157 if (ifa->ifa_addr->sa_family == family) {
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;
174 if (getifaddrs(&ifas) == -1) {
175 THROW2(InterfaceException,
"getifaddrs()");
178 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
179 if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
184 interfaces.push_back(ifa->ifa_name);
196 std::list<std::string> Interface::getInterfaceNames(
const unsigned int ifrFlagMatch,
const unsigned int ifrFlagReject)
throw (InterfaceException) {
197 return getNames(ifrFlagMatch, ifrFlagReject);
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;
206 if (getifaddrs(&ifas) == -1) {
207 THROW2(InterfaceException,
"getifaddrs()");
210 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
211 if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
213 }
else if (!isEthernet(ifa->ifa_name)) {
217 interfaces.push_back(ifa->ifa_name);
227 std::string Interface::getMAC(
const std::string &interface)
throw (InterfaceException) {
230 unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
233 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
234 THROW2(InterfaceException,
"socket()");
237 strcpy(ifr.ifr_name, interface.c_str());
239 if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
240 THROW2(InterfaceException,
"ioctl()");
243 if (memcmp(ifr.ifr_hwaddr.sa_data, none,
sizeof(none)) == 0) {
244 THROW(InterfaceException,
"Interface %s has no MAC", interface.c_str());
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]);
254 std::string Interface::getInterfaceMAC(
const std::string &interface)
throw (InterfaceException) {
255 return getMAC(interface);
259 std::list<std::string> Interface::getMACs(
const unsigned int ifrFlagMatch,
const unsigned int ifrFlagReject)
throw (InterfaceException) {
262 unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
264 std::list<std::string> macs;
265 auto interfaces = getNames(ifrFlagMatch, (ifrFlagReject | IFF_LOOPBACK));
267 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
268 THROW2(InterfaceException,
"socket()");
271 for (
auto it = interfaces.begin(); it != interfaces.end(); ++it) {
272 strcpy(ifr.ifr_name, it->c_str());
274 if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
275 THROW2(InterfaceException,
"ioctl()");
278 if (memcmp(ifr.ifr_hwaddr.sa_data, none,
sizeof(none)) == 0) {
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]);
295 std::list<std::string> Interface::getInterfaceMACs(
const unsigned int ifrFlagMatch,
const unsigned int ifrFlagReject)
throw (InterfaceException) {
296 return getMACs(ifrFlagMatch, ifrFlagReject);
299 void Interface::getInterfaceAddr(
const std::string &interface,
struct in_addr *ip)
throw (InterfaceException) {
300 getAddr(interface, ip);
305 struct in_addr* Interface::getAddr(
const std::string &interface,
struct in_addr *ip)
throw (InterfaceException) {
309 struct sockaddr_in sa;
312 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
313 THROW2(InterfaceException,
"socket()");
316 ifc.ifc_len = IFRSIZE;
322 if (NULL == (tmp = (
struct ifreq*) realloc(ifc.ifc_req, IFRSIZE))) {
323 SAFE_FREE(ifc.ifc_req);
326 THROW(InterfaceException,
"Failed to realloc");
330 ifc.ifc_len = IFRSIZE;
332 if (ioctl(s, SIOCGIFCONF, &ifc)) {
333 SAFE_FREE(ifc.ifc_req);
336 THROW2(InterfaceException,
"ioctl()");
338 }
while (IFRSIZE <= ifc.ifc_len);
341 for (;(
char *) ifr < (
char *) ifc.ifc_req + ifc.ifc_len; ++ifr) {
343 if (ifr->ifr_addr.sa_data == (ifr + 1)->ifr_addr.sa_data) {
347 if (ioctl(s, SIOCGIFFLAGS, ifr)) {
351 if (strncmp(ifr->ifr_name,
"lo", 2) && (interface.empty() || !strcmp(ifr->ifr_name, interface.c_str()))) {
358 u.c = ifr->ifr_addr.sa_data[
sizeof(sa.sin_port)];
361 *ip = inaddrr(ifr_addr.sa_data);
365 fprintf(stderr,
"Interface: %s\n", ifr->ifr_name);
366 fprintf(stderr,
"IP Address: %s\n", inet_ntoa(*ip));
373 SAFE_FREE(ifc.ifc_req);
379 unsigned int Interface::getIndex(
const std::string &interface)
throw (InterfaceException) {
380 #define USE_NAMETOINDEX
381 #ifdef USE_NAMETOINDEX
384 if ((index = if_nametoindex(interface.c_str())) > 0) {
388 THROW2(InterfaceException,
"if_nametoindex()");
392 size_t len = interface.size();
394 if (len <
sizeof(ifr.ifr_name)) {
395 memcpy(ifr.ifr_name, interface.c_str(), len);
396 ifr.ifr_name[len] = 0;
398 THROW(InterfaceException,
"Interface name '%s' is too long", interface.c_str());
401 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
402 THROW2(InterfaceException,
"socket()");
405 if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
408 THROW2(InterfaceException,
"ioctl()");
413 return ifr.ifr_ifindex;
417 std::string Interface::getName(
unsigned int index)
throw (InterfaceException) {
418 char buf[IF_NAMESIZE];
420 if (if_indextoname(index, buf) != NULL) {
421 return std::string(buf);
424 THROW2(InterfaceException,
"if_indextoname()");
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());
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) {
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) {
442 THROW(InterfaceException,
"Invalid MAC address '%s'", mac.c_str());
445 std::string& Interface::convertMAC(std::string &dst,
const unsigned char mac[6],
char delim)
throw (InterfaceException) {
448 if (delim > 0 && delim < 32 && delim > 127) {
449 THROW(InterfaceException,
"Invalid MAC delim");
454 for (
size_t i = 0; i < 6; i++) {
455 if (delim > 0 && i > 0) {
456 dst.push_back(delim);
459 snprintf(buf,
sizeof(buf),
"%02X", mac[i]);
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;
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]);
484 std::string& Interface::convertMAC(std::string &dst,
const uint64_t mac)
throw (InterfaceException) {
485 unsigned char addr[6];
487 convertMAC(addr, mac);
489 return convertMAC(dst, addr);
492 uint64_t& Interface::convertMAC(uint64_t &dst,
const std::string &mac)
throw (InterfaceException) {
493 unsigned char addr[6];
495 convertMAC(addr, mac);
497 return convertMAC(dst, addr);
500 bool Interface::isEthernet(
const std::string &interface)
throw (InterfaceException) {
503 unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
505 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
506 THROW2(InterfaceException,
"socket()");
509 strcpy(ifr.ifr_name, interface.c_str());
511 if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
512 THROW2(InterfaceException,
"ioctl()");
515 if (memcmp(ifr.ifr_hwaddr.sa_data, none,
sizeof(none)) == 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());
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) {
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) {
538 THROW(InterfaceException,
"Invalid MAC address '%s'", mac.c_str());
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);
545 std::list<std::string> Interface::interfaceNameList(
const unsigned int ifrFlagMatch,
const unsigned int ifrFlagReject)
throw (InterfaceException) {
546 return getNames(ifrFlagMatch, ifrFlagReject);
549 std::list<std::string> Interface::interfaceMACList(
const unsigned int ifrFlagMatch,
const unsigned int ifrFlagReject)
throw (InterfaceException) {
550 return getMACs(ifrFlagMatch, ifrFlagReject);
553 void Interface::source_ip(
char *interface,
struct in_addr *ip)
throw (InterfaceException) {
554 getAddr(interface, ip);