00001
00002
00003
00004
00005
00006
00007
00008
00009 static const char rcsid[] __attribute__((used)) = "$Id: Interface.cpp 1230 2014-11-16 02:32:01Z sella $";
00010
00011 #include "Interface.h"
00012 #include "../net/IPAddress.h"
00013 #include "CommonMacro.h"
00014
00015 #include <string.h>
00016 #include <stdlib.h>
00017 #include <unistd.h>
00018 #include <ifaddrs.h>
00019 #include <net/if.h>
00020 #include <sys/types.h>
00021 #include <netpacket/packet.h>
00022
00023
00024 #include <string>
00025
00026 #define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof(sa.sin_port)])
00027 #define IFRSIZE ((int)(size * sizeof(struct ifreq)))
00028
00029 namespace sn = sella::net;
00030 using namespace sella::util;
00031
00032 void Interface::setPromiscous(const std::string &interface, bool on) throw (InterfaceException) {
00033 int s;
00034 struct ifreq ifr;
00035 size_t len = interface.size();
00036 struct packet_mreq mr;
00037
00038 if (len < sizeof(ifr.ifr_name)) {
00039 memcpy(ifr.ifr_name, interface.c_str(), len);
00040 ifr.ifr_name[len] = 0;
00041 } else {
00042 THROW(InterfaceException, "Interface name '%s' is too long", interface.c_str());
00043 }
00044
00045 if ((s = socket(AF_PACKET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
00046 THROW2(InterfaceException, "socket()");
00047 }
00048
00049 if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
00050 close(s);
00051
00052 THROW2(InterfaceException, "ioctl()");
00053 }
00054
00055 memset(&mr, 0, sizeof(mr));
00056 mr.mr_ifindex = ifr.ifr_ifindex;
00057 mr.mr_type = PACKET_MR_PROMISC;
00058
00059 if (setsockopt(s, SOL_PACKET, (on) ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0) {
00060 close(s);
00061
00062 THROW2(InterfaceException, "setsockopt()");
00063 }
00064
00065 close(s);
00066 }
00067
00068 sn::IPAddress::shared_list Interface::getIPAddresses(const std::string &interface, const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00069 struct ifaddrs *ifas, *ifa = NULL;
00070 sn::IPAddress::shared_list addresses;
00071 sn::IPAddress::shared address;
00072 int family;
00073
00074 if (getifaddrs(&ifas) == -1) {
00075 THROW(InterfaceException, "Failed to retrieve interfaces");
00076 }
00077
00078 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
00079 if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
00080 continue;
00081 }
00082
00083 if (ifa->ifa_addr != NULL) {
00084 if (!interface.empty() && interface.compare(ifa->ifa_name)) {
00085 continue;
00086 }
00087
00088 family = ifa->ifa_addr->sa_family;
00089 if (family == AF_INET || family == AF_INET6) {
00090 address = sn::IPAddress::shared_ptr(ifa->ifa_addr);
00091 addresses.push_back(address);
00092 }
00093 }
00094 }
00095 freeifaddrs(ifas);
00096
00097 addresses.sort();
00098 addresses.unique();
00099
00100 return addresses;
00101 }
00102
00103 sn::IPAddress::shared_list Interface::getInterfaceIPAddresses(const std::string &interface, const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00104 return getIPAddresses(interface, ifrFlagMatch, ifrFlagReject);
00105 }
00106
00107 sella::net::IPAddress Interface::getIPAddress(const std::string &interface, int family) throw (InterfaceException) {
00108 struct ifaddrs *ifas, *ifa = NULL;
00109 sn::IPAddress address;
00110
00111 if (getifaddrs(&ifas) == -1) {
00112 THROW(InterfaceException, "Failed to retrieve interfaces");
00113 }
00114
00115 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
00116 if (ifa->ifa_addr != NULL) {
00117 if (!interface.empty() && interface.compare(ifa->ifa_name)) {
00118 continue;
00119 }
00120
00121 if (ifa->ifa_addr->sa_family == family) {
00122 address = sn::IPAddress(ifa->ifa_addr);
00123
00124 break;
00125 }
00126 }
00127 }
00128 freeifaddrs(ifas);
00129
00130 return address;
00131 }
00132
00133 std::list<std::string> Interface::getNames(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00134 struct ifaddrs *ifas, *ifa = NULL;
00135 std::list<std::string> interfaces;
00136 std::list<std::string>::iterator it;
00137
00138 if (getifaddrs(&ifas) == -1) {
00139 THROW2(InterfaceException, "getifaddrs()");
00140 }
00141
00142 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
00143 if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
00144 continue;
00145 }
00146
00147
00148 interfaces.push_back(ifa->ifa_name);
00149
00150 }
00151 freeifaddrs(ifas);
00152
00153 interfaces.sort();
00154 interfaces.unique();
00155
00156 return interfaces;
00157 }
00158
00159 std::list<std::string> Interface::getInterfaceNames(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00160 return getNames(ifrFlagMatch, ifrFlagReject);
00161 }
00162
00163 std::list<std::string> Interface::getEthernetNames(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00164 struct ifaddrs *ifas, *ifa = NULL;
00165 std::list<std::string> interfaces;
00166 std::list<std::string>::iterator it;
00167
00168 if (getifaddrs(&ifas) == -1) {
00169 THROW2(InterfaceException, "getifaddrs()");
00170 }
00171
00172 for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
00173 if (((ifa->ifa_flags & ifrFlagMatch) == 0 && ifrFlagMatch != 0) || (ifa->ifa_flags & ifrFlagReject) != 0) {
00174 continue;
00175 } else if (!isEthernet(ifa->ifa_name)) {
00176 continue;
00177 }
00178
00179 interfaces.push_back(ifa->ifa_name);
00180 }
00181 freeifaddrs(ifas);
00182
00183 interfaces.sort();
00184 interfaces.unique();
00185
00186 return interfaces;
00187 }
00188
00189 std::string Interface::getMAC(const std::string &interface) throw (InterfaceException) {
00190 int s;
00191 struct ifreq ifr;
00192 unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
00193 char mac[19];
00194
00195 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
00196 THROW2(InterfaceException, "socket()");
00197 }
00198
00199 strcpy(ifr.ifr_name, interface.c_str());
00200
00201 if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
00202 THROW2(InterfaceException, "ioctl()");
00203 }
00204
00205 if (memcmp(ifr.ifr_hwaddr.sa_data, none, sizeof(none)) == 0) {
00206 THROW(InterfaceException, "Interface %s has no MAC", interface.c_str());
00207 }
00208
00209 unsigned char *m = (unsigned char*) ifr.ifr_hwaddr.sa_data;
00210 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
00211
00212 return mac;
00213 }
00214
00215 std::string Interface::getInterfaceMAC(const std::string &interface) throw (InterfaceException) {
00216 return getMAC(interface);
00217 }
00218
00219 std::list<std::string> Interface::getMACs(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00220 int s;
00221 struct ifreq ifr;
00222 unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
00223 char mac[19];
00224 std::list<std::string> macs;
00225 auto interfaces = getNames(ifrFlagMatch, (ifrFlagReject | IFF_LOOPBACK));
00226
00227 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
00228 THROW2(InterfaceException, "socket()");
00229 }
00230
00231 for (auto it = interfaces.begin(); it != interfaces.end(); ++it) {
00232 strcpy(ifr.ifr_name, it->c_str());
00233
00234 if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
00235 THROW2(InterfaceException, "ioctl()");
00236 }
00237
00238 if (memcmp(ifr.ifr_hwaddr.sa_data, none, sizeof(none)) == 0) {
00239 continue;
00240 }
00241
00242 unsigned char *m = (unsigned char*) ifr.ifr_hwaddr.sa_data;
00243 snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
00244
00245 macs.push_back(mac);
00246 }
00247
00248 macs.sort();
00249 macs.unique();
00250
00251 return macs;
00252 }
00253
00254 std::list<std::string> Interface::getInterfaceMACs(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00255 return getMACs(ifrFlagMatch, ifrFlagReject);
00256 }
00257
00258 void Interface::getInterfaceAddr(const std::string &interface, struct in_addr *ip) throw (InterfaceException) {
00259 getAddr(interface, ip);
00260 }
00261
00262
00263 struct in_addr* Interface::getAddr(const std::string &interface, struct in_addr *ip) throw (InterfaceException) {
00264 int s, size = 1;
00265 struct ifreq *ifr;
00266 struct ifconf ifc;
00267 struct sockaddr_in sa;
00268 struct ifreq *tmp;
00269
00270 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
00271 THROW2(InterfaceException, "socket()");
00272 }
00273
00274 ifc.ifc_len = IFRSIZE;
00275 ifc.ifc_req = NULL;
00276
00277 do {
00278 ++size;
00279
00280 if (NULL == (tmp = (struct ifreq*) realloc(ifc.ifc_req, IFRSIZE))) {
00281 SAFE_FREE(ifc.ifc_req);
00282 close(s);
00283
00284 THROW(InterfaceException, "Failed to realloc");
00285 }
00286
00287 ifc.ifc_req = tmp;
00288 ifc.ifc_len = IFRSIZE;
00289
00290 if (ioctl(s, SIOCGIFCONF, &ifc)) {
00291 SAFE_FREE(ifc.ifc_req);
00292 close(s);
00293
00294 THROW2(InterfaceException, "ioctl()");
00295 }
00296 } while (IFRSIZE <= ifc.ifc_len);
00297
00298 ifr = ifc.ifc_req;
00299 for (;(char *) ifr < (char *) ifc.ifc_req + ifc.ifc_len; ++ifr) {
00300
00301 if (ifr->ifr_addr.sa_data == (ifr + 1)->ifr_addr.sa_data) {
00302 continue;
00303 }
00304
00305 if (ioctl(s, SIOCGIFFLAGS, ifr)) {
00306 continue;
00307 }
00308
00309 if (strncmp(ifr->ifr_name, "lo", 2) && (interface.empty() || !strcmp(ifr->ifr_name, interface.c_str()))) {
00310 #ifndef USE_ORIGINAL
00311 union {
00312 char c;
00313 struct in_addr addr;
00314 } u;
00315
00316 u.c = ifr->ifr_addr.sa_data[sizeof(sa.sin_port)];
00317 *ip = u.addr;
00318 #else
00319 *ip = inaddrr(ifr_addr.sa_data);
00320 #endif
00321
00322 #if 0
00323 fprintf(stderr, "Interface: %s\n", ifr->ifr_name);
00324 fprintf(stderr, "IP Address: %s\n", inet_ntoa(*ip));
00325 #endif
00326
00327 break;
00328 }
00329 }
00330
00331 SAFE_FREE(ifc.ifc_req);
00332 close(s);
00333
00334 return ip;
00335 }
00336
00337 unsigned int Interface::getIndex(const std::string &interface) throw (InterfaceException) {
00338 #define USE_NAMETOINDEX
00339 #ifdef USE_NAMETOINDEX
00340 unsigned int index;
00341
00342 if ((index = if_nametoindex(interface.c_str())) > 0) {
00343 return index;
00344 }
00345
00346 THROW2(InterfaceException, "if_nametoindex()");
00347 #else
00348 int s;
00349 struct ifreq ifr;
00350 size_t len = interface.size();
00351
00352 if (len < sizeof(ifr.ifr_name)) {
00353 memcpy(ifr.ifr_name, interface.c_str(), len);
00354 ifr.ifr_name[len] = 0;
00355 } else {
00356 THROW(InterfaceException, "Interface name '%s' is too long", interface.c_str());
00357 }
00358
00359 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
00360 THROW2(InterfaceException, "socket()");
00361 }
00362
00363 if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
00364 close(s);
00365
00366 THROW2(InterfaceException, "ioctl()");
00367 }
00368
00369 close(s);
00370
00371 return ifr.ifr_ifindex;
00372 #endif
00373 }
00374
00375 std::string Interface::getName(unsigned int index) throw (InterfaceException) {
00376 char buf[IF_NAMESIZE];
00377
00378 if (if_indextoname(index, buf) != NULL) {
00379 return std::string(buf);
00380 }
00381
00382 THROW2(InterfaceException, "if_indextoname()");
00383 }
00384
00385 unsigned char* Interface::convertMAC(unsigned char dst[6], const std::string &mac) throw (InterfaceException) {
00386 if (mac.size() == 17) {
00387 if ((mac[2] != ':' && mac[2] != '-') || (mac[5] != ':' && mac[5] != '-') || (mac[8] != ':' && mac[8] != '-') || (mac[11] != ':' && mac[11] != '-') || (mac[14] != ':' && mac[14] != '-')) {
00388 THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
00389 }
00390
00391 if (sscanf(mac.c_str(), "%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx", &dst[0], &dst[1], &dst[2], &dst[3], &dst[4], &dst[5]) == 6) {
00392 return dst;
00393 }
00394 } else if (mac.size() == 12) {
00395 if (sscanf(mac.c_str(), "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", &dst[0], &dst[1], &dst[2], &dst[3], &dst[4], &dst[5]) == 6) {
00396 return dst;
00397 }
00398 }
00399
00400 THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
00401 }
00402
00403 std::string& Interface::convertMAC(std::string &dst, const unsigned char mac[6], char delim) throw (InterfaceException) {
00404 char buf[4];
00405
00406 if (delim > 0 && delim < 32 && delim > 127) {
00407 THROW(InterfaceException, "Invalid MAC delim");
00408 }
00409
00410 dst.clear();
00411
00412 for (size_t i = 0; i < 6; i++) {
00413 if (delim > 0 && i > 0) {
00414 dst.push_back(delim);
00415 }
00416
00417 snprintf(buf, sizeof(buf), "%02X", mac[i]);
00418
00419 dst += buf;
00420 }
00421
00422 return dst;
00423 }
00424
00425 unsigned char* Interface::convertMAC(unsigned char dst[6], const uint64_t mac) throw (InterfaceException) {
00426 dst[0] = 0x000000ff & (mac >> 40);
00427 dst[1] = 0x000000ff & (mac >> 32);
00428 dst[2] = 0x000000ff & (mac >> 24);
00429 dst[3] = 0x000000ff & (mac >> 16);
00430 dst[4] = 0x000000ff & (mac >> 8);
00431 dst[5] = 0x000000ff & mac;
00432
00433 return dst;
00434 }
00435
00436 uint64_t& Interface::convertMAC(uint64_t &dst, const unsigned char mac[6]) throw (InterfaceException) {
00437 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]);
00438
00439 return dst;
00440 }
00441
00442 std::string& Interface::convertMAC(std::string &dst, const uint64_t mac) throw (InterfaceException) {
00443 unsigned char addr[6];
00444
00445 convertMAC(addr, mac);
00446
00447 return convertMAC(dst, addr);
00448 }
00449
00450 uint64_t& Interface::convertMAC(uint64_t &dst, const std::string &mac) throw (InterfaceException) {
00451 unsigned char addr[6];
00452
00453 convertMAC(addr, mac);
00454
00455 return convertMAC(dst, addr);
00456 }
00457
00458 bool Interface::isEthernet(const std::string &interface) throw (InterfaceException) {
00459 int s;
00460 struct ifreq ifr;
00461 unsigned char none[6] = { 0, 0, 0, 0, 0, 0 };
00462
00463 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
00464 THROW2(InterfaceException, "socket()");
00465 }
00466
00467 strcpy(ifr.ifr_name, interface.c_str());
00468
00469 if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) {
00470 THROW2(InterfaceException, "ioctl()");
00471 }
00472
00473 if (memcmp(ifr.ifr_hwaddr.sa_data, none, sizeof(none)) == 0) {
00474 return false;
00475 }
00476
00477 return true;
00478 }
00479
00480 unsigned char* Interface::parseMAC(const std::string &mac, unsigned char addr[6]) throw (InterfaceException) {
00481 if (mac.size() == 17) {
00482 if ((mac[2] != ':' && mac[2] != '-') || (mac[5] != ':' && mac[5] != '-') || (mac[8] != ':' && mac[8] != '-') || (mac[11] != ':' && mac[11] != '-') || (mac[14] != ':' && mac[14] != '-')) {
00483 THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
00484 }
00485
00486 if (sscanf(mac.c_str(), "%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx%*[-:]%2hhx", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) == 6) {
00487 return addr;
00488 }
00489 } else if (mac.size() == 12) {
00490 if (sscanf(mac.c_str(), "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) == 6) {
00491 return addr;
00492 }
00493 }
00494
00495 THROW(InterfaceException, "Invalid MAC address '%s'", mac.c_str());
00496 }
00497
00498 sn::IPAddress::shared_list Interface::interfaceIPAddressList(const std::string &interface, const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00499 return getIPAddresses(interface, ifrFlagMatch, ifrFlagReject);
00500 }
00501
00502 std::list<std::string> Interface::interfaceNameList(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00503 return getNames(ifrFlagMatch, ifrFlagReject);
00504 }
00505
00506 std::list<std::string> Interface::interfaceMACList(const unsigned int ifrFlagMatch, const unsigned int ifrFlagReject) throw (InterfaceException) {
00507 return getMACs(ifrFlagMatch, ifrFlagReject);
00508 }
00509
00510 void Interface::source_ip(char *interface, struct in_addr *ip) throw (InterfaceException) {
00511 getAddr(interface, ip);
00512 }
00513
00514
00515
00516