// Ethernet device list by BPF API TOKEN_LIST *GetEthListBpf() { struct ifaddrs *ifadrs; struct sockaddr_dl *sockadr; LIST *o; TOKEN_LIST *t; int i; o = NewListFast(CompareStr); // Enumerate network devices if(getifaddrs( &ifadrs ) == 0) { struct ifaddrs *ifadr = ifadrs; while(ifadr) { sockadr = (struct sockaddr_dl*)ifadr->ifa_addr; if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER) { // Is this Ethernet device? if(!IsInListStr(o,ifadr->ifa_name)) { // Ignore the foregoing device (for device which have multiple MAC address) Add(o, CopyStr(ifadr->ifa_name)); } } ifadr = ifadr -> ifa_next; } freeifaddrs(ifadrs); } Sort(o); t = ZeroMalloc(sizeof(TOKEN_LIST)); t->NumTokens = LIST_NUM(o); t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens); for (i = 0;i < LIST_NUM(o);i++) { t->Token[i] = LIST_DATA(o, i); } ReleaseList(o); return t; }
// アダプタ一覧を取得 (BPF) TOKEN_LIST *GetEthListBpf() { struct ifaddrs *ifadrs; struct sockaddr_dl *sockadr; LIST *o; TOKEN_LIST *t; int i; o = NewListFast(CompareStr); // ネットワークデバイスの一覧を取得 if(getifaddrs( &ifadrs ) == 0) { struct ifaddrs *ifadr = ifadrs; while(ifadr) { sockadr = (struct sockaddr_dl*)ifadr->ifa_addr; if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER) { // Ethernet デバイスか? if(!IsInListStr(o,ifadr->ifa_name)) { // 既存でなければ追加(複数のMACアドレスを持つインターフェースへの対策) Add(o, CopyStr(ifadr->ifa_name)); } } ifadr = ifadr -> ifa_next; } freeifaddrs(ifadrs); } Sort(o); t = ZeroMalloc(sizeof(TOKEN_LIST)); t->NumTokens = LIST_NUM(o); t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens); for (i = 0;i < LIST_NUM(o);i++) { t->Token[i] = LIST_DATA(o, i); } ReleaseList(o); return t; }
// Get Ethernet device list on Linux TOKEN_LIST *GetEthListLinux() { struct ifreq ifr; TOKEN_LIST *t; UINT i, n; int s; LIST *o; char name[MAX_SIZE]; o = NewListFast(CompareStr); s = UnixEthOpenRawSocket(); if (s != INVALID_SOCKET) { n = 0; for (i = 0;;i++) { Zero(&ifr, sizeof(ifr)); ifr.ifr_ifindex = i; if (ioctl(s, SIOCGIFNAME, &ifr) >= 0) { n = 0; StrCpy(name, sizeof(name), ifr.ifr_name); Zero(&ifr, sizeof(ifr)); StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name); if (ioctl(s, SIOCGIFHWADDR, &ifr) >= 0) { UINT type = ifr.ifr_hwaddr.sa_family; if (type == 1 || type == 2 || type == 6 || type == 800 || type == 801) { if (IsInListStr(o, name) == false) { if (StartWith(name, "tap_") == false) { Add(o, CopyStr(name)); } } } } } else { n++; if (n >= 64) { break; } } } closesocket(s); } Sort(o); t = ZeroMalloc(sizeof(TOKEN_LIST)); t->NumTokens = LIST_NUM(o); t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens); for (i = 0;i < LIST_NUM(o);i++) { char *name = LIST_DATA(o, i); t->Token[i] = name; } ReleaseList(o); return t; }
// Open Ethernet device (Linux) ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr) { ETH *e; struct ifreq ifr; struct sockaddr_ll addr; int s; int index; bool aux_ok = false; CANCEL *c; // Validate arguments if (name == NULL) { return NULL; } if (tapmode) { #ifndef NO_VLAN // In tap mode VLAN *v = NewTap(name, tapaddr); if (v == NULL) { return NULL; } e = ZeroMalloc(sizeof(ETH)); e->Name = CopyStr(name); e->Title = CopyStr(name); e->Cancel = VLanGetCancel(v); e->IfIndex = 0; e->Socket = INVALID_SOCKET; e->Tap = v; return e; #else // NO_VLAN return NULL; #endif // NO_VLAN } s = UnixEthOpenRawSocket(); if (s == INVALID_SOCKET) { return NULL; } Zero(&ifr, sizeof(ifr)); StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { closesocket(s); return NULL; } index = ifr.ifr_ifindex; Zero(&addr, sizeof(addr)); addr.sll_family = PF_PACKET; addr.sll_protocol = htons(ETH_P_ALL); addr.sll_ifindex = index; if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { closesocket(s); return NULL; } if (local == false) { // Enable promiscious mode Zero(&ifr, sizeof(ifr)); StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name); if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { // Failed closesocket(s); return NULL; } ifr.ifr_flags |= IFF_PROMISC; if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) { // Failed closesocket(s); return NULL; } } if (true) { int val = 1; int ss_ret = setsockopt(s, SOL_PACKET, MY_PACKET_AUXDATA, &val, sizeof(val)); if (ss_ret < 0) { Debug("eth(%s): setsockopt: PACKET_AUXDATA failed.\n", name); } else { Debug("eth(%s): setsockopt: PACKET_AUXDATA ok.\n", name); aux_ok = true; } } e = ZeroMalloc(sizeof(ETH)); e->Name = CopyStr(name); e->Title = CopyStr(name); e->IfIndex = index; e->Socket = s; e->Linux_IsAuxDataSupported = aux_ok; c = NewCancel(); UnixDeletePipe(c->pipe_read, c->pipe_write); c->pipe_read = c->pipe_write = -1; UnixSetSocketNonBlockingMode(s, true); c->SpecialFlag = true; c->pipe_read = s; e->Cancel = c; // Get MTU e->InitialMtu = EthGetMtu(e); if (tapmode == false) { if (GetGlobalServerFlag(GSF_LOCALBRIDGE_NO_DISABLE_OFFLOAD) == false) { bool b = false; LockList(eth_offload_list); { if (IsInListStr(eth_offload_list, name) == false) { b = true; Add(eth_offload_list, CopyStr(name)); } } UnlockList(eth_offload_list); if (b) { // Disable hardware offloading UnixDisableInterfaceOffload(name); } } } return e; }