/** * Disconnects all adapters */ static void disconnect_all_adapters() { adapter_object *a; while (adapters()->first) { a = adapters()->first->element; disconnect_adapter(a->path); } llist_destroy(adapters(), NULL); _adapters = NULL; }
/** * Remove adapter path from list */ static void remove_adapter(const char *path) { adapter_object *a = get_adapter(path); if (a) { g_free(a->path); g_object_unref(a->proxy); g_free(a); llist_remove(adapters(), a); } }
/** * Add adapter to list */ static void add_adapter(const char *path, DBusGProxy *proxy) { adapter_object *a; if (get_adapter(path)) remove_adapter(path); a = (adapter_object *) g_new(adapter_object, 1); a->path = g_strdup(path); a->proxy = proxy; llist_add(adapters(), a); }
QueryData genInterfaceAddresses(QueryContext& context) { QueryData results; DWORD buffSize = kWorkingBufferSize; auto alloc_attempts = 0; size_t alloc_result = 0; const auto addrFamily = AF_UNSPEC; const auto addrFlags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST; std::unique_ptr<IP_ADAPTER_ADDRESSES> adapters(nullptr); // Buffer size can change between the query and malloc (if adapters are // added/removed), so shenanigans are required do { adapters.reset(static_cast<PIP_ADAPTER_ADDRESSES>(malloc(buffSize))); if (adapters == nullptr) { return results; } alloc_result = GetAdaptersAddresses( addrFamily, addrFlags, nullptr, adapters.get(), &buffSize); alloc_attempts++; } while (alloc_result == ERROR_BUFFER_OVERFLOW && alloc_attempts < kMaxBufferAllocRetries); if (alloc_result != NO_ERROR) { return results; } const IP_ADAPTER_ADDRESSES* currAdapter = adapters.get(); while (currAdapter != nullptr) { std::wstring wsAdapterName = std::wstring(currAdapter->FriendlyName); auto adapterName = std::string(wsAdapterName.begin(), wsAdapterName.end()); const IP_ADAPTER_UNICAST_ADDRESS* ipaddr = currAdapter->FirstUnicastAddress; while (ipaddr != nullptr) { Row r; r["interface"] = SQL_TEXT(currAdapter->IfIndex); r["friendly_name"] = adapterName; genInterfaceAddress(ipaddr, r); ipaddr = ipaddr->Next; results.push_back(r); } currAdapter = currAdapter->Next; } return results; }
void GFXInit::init() { // init only once. static bool doneOnce = false; if(doneOnce) return; doneOnce = true; Con::printf( "GFX Init:" ); //find our adapters Vector<GFXAdapter*> adapters( __FILE__, __LINE__ ); GFXInit::enumerateAdapters(); GFXInit::getAdapters(&adapters); if(!adapters.size()) Con::errorf("Could not find a display adapter"); //loop through and tell the user what kind of adapters we found _GFXInitReportAdapters(adapters); Con::printf( "" ); }
QueryData genInterfaceDetails(QueryContext& context) { QueryData results; DWORD buffSize = kWorkingBufferSize; auto alloc_attempts = 0; size_t alloc_result = 0; const auto addrFamily = AF_UNSPEC; const auto addrFlags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST; std::unique_ptr<IP_ADAPTER_ADDRESSES> adapters(nullptr); // Buffer size can change between the query and malloc (if adapters are // added/removed), so shenanigans are required do { adapters.reset(static_cast<PIP_ADAPTER_ADDRESSES>(malloc(buffSize))); if (adapters == nullptr) { return results; } alloc_result = GetAdaptersAddresses( addrFamily, addrFlags, nullptr, adapters.get(), &buffSize); alloc_attempts++; } while (alloc_result == ERROR_BUFFER_OVERFLOW && alloc_attempts < kMaxBufferAllocRetries); if (alloc_result != NO_ERROR) { return results; } const IP_ADAPTER_ADDRESSES* currAdapter = adapters.get(); while (currAdapter != nullptr) { Row r; genInterfaceDetail(currAdapter, r); currAdapter = currAdapter->Next; results.push_back(r); } return results; }
/** * Fetch adapter struct from list */ static adapter_object *get_adapter(const char *path) { return (adapter_object *) llist_search_first(adapters(), (void *) path, cmp_adapter); }
// 1419 is the mtu using a 1500 byte ethernet mtu - ipv4 header - udp - dtls with default ciphersuite (I think) // TODO: read mtu from interface on each OS instead of hard coding 1419 (also have installer set sensible interface MTU) tuntap::tuntap() : mtu(1419) { // TODO: use configuration parameters for registry key names instead of hard coded values // TODO: package TAP-Windows and change component ID or otherwise figure out how to make it not collide with what OpenVPN uses // see comment in %PROGRAMFILES%\TAP-Windows\driver\OemWin2k.inf after installing OpenVPN TAP driver #ifdef WINDOWS sent_sync = true; // no async send in progress received_sync = 0; memset(&recv_overlapped, 0, sizeof(OVERLAPPED)); memset(&send_overlapped, 0, sizeof(OVERLAPPED)); recv_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); if(recv_event == INVALID_HANDLE_VALUE) throw check_err_exception("CreateEvent failed for tuntap recv_event"); recv_overlapped.hEvent = recv_event; // default callback emits error read_ready_cb = []() { eout() << "BUG: tuntap read ready callback called but not set"; }; if(RegisterWaitForSingleObject(&recv_wait, recv_event, &tuntap::read_event_cb, this, INFINITE, WT_EXECUTEINWAITTHREAD) == FALSE) throw check_err_exception("RegisterWaitForSingleObject on tuntap read event"); adapter_GUID = snow::conf[snow::VIRTUAL_INTERFACE]; if(adapter_GUID == "auto") { try { // open registry key for all network adapters registry_key adapters(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", KEY_READ); for(auto &it : adapters.subkeys()) { try { registry_key adapter = it.get(KEY_READ); // TODO: change ComponentId from "tap0901" to some other string to remove possible namespace collision with OpenVPN (this has to occur in the driver too) if(adapter.values().get_value_string("ComponentId") == "tap0901") { adapter_GUID = adapter.values().get_value_string("NetCfgInstanceId"); break; } } catch(const registry_exception &re) { dout() << "Failed to access registry subkey: " << re; } } } catch (const registry_exception &re) { eout() << "FATAL: Failed to open network adapters registry key, cannot determine TUN adapter to use: " << re; throw; } } dout() << "Adapter GUID: " << adapter_GUID; if(adapter_GUID == "auto") throw e_not_found("no usable tuntap interface"); // [at this point GUID is value of NetCfgInstanceId, although there could be more than one interface: check all against something else? (interface name?)] // TODO: probably the thing to do is: on install, create a TAP-Windows interface and set its name to 'snow tunnel interface' or so, // then set the GUID in the configuration file [or registry setting], and GUI config program can list interfaces by name and allow user to choose // then the configured GUID is the interface we use and all of this mess doesn't even need to go here -- it just goes once on install and in the config editor // what would then really be useful would be a way (other than changing the ComponentId) to tell other software (e.g. OpenVPN) not to use a particular interface // two possible solutions may be to either make sure that snow starts before the other service [somehow] and gets there first, // or setting permissions [somehow] so that only snow process has access std::string tap_filename("\\\\.\\Global\\"); tap_filename += adapter_GUID + ".tap"; fd = CreateFile(tap_filename.c_str(), GENERIC_READ | GENERIC_WRITE, 0/*no shared access*/, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, nullptr); if(fd == INVALID_HANDLE_VALUE) throw check_err_exception("Failed to open Windows TUN/TAP device"); // name of specific instance of adapter as shown in control panel can be found in: // "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\" + adapter_GUID + "\\Connection" // value is "Name" // set to TUN mode // TAP_WIN_IOCTL_CONFIG_TUN takes three args: interface IP addr, network addr and netmask if_info ifinfo = get_if_info(); uint32_t tun_addrs[3] = { ifinfo.if_addr, ifinfo.if_addr & ifinfo.netmask, ifinfo.netmask }; DWORD rsize; if(DeviceIoControl(fd, TAP_WINDOWS_IOCTL_CONFIG_TUN, tun_addrs, sizeof(tun_addrs), tun_addrs, sizeof(tun_addrs), &rsize, nullptr)) dout() << "TAP-Windows CONFIG_TUN success: " << ss_ipaddr(tun_addrs[0]) << " " << ss_ipaddr(tun_addrs[1]) << " " << ss_ipaddr(tun_addrs[2]); else eout() << "TAP-Windows CONFIG_TUN FAIL: " << ss_ipaddr(tun_addrs[0]) << " " << ss_ipaddr(tun_addrs[1]) << " " << ss_ipaddr(tun_addrs[2]); // set media status as connected ULONG connected = TRUE; if(DeviceIoControl(fd, TAP_WINDOWS_IOCTL_SET_MEDIA_STATUS, &connected, sizeof(connected), &connected, sizeof(connected), &rsize, nullptr) == FALSE) wout() << "Failed to set TAP-Windows media status to connected"; ULONG ifmtu; if(DeviceIoControl(fd, TAP_WINDOWS_IOCTL_GET_MTU, &ifmtu, sizeof(ifmtu), &ifmtu, sizeof(ifmtu), &rsize, nullptr)) { dout() << "Read mtu from TAP-Windows interface: " << ifmtu; if(ifmtu > MIN_PMTU) mtu = ifmtu; } else { wout() << "Failed to get Tap-Windows MTU, assuming default"; } // [flush ARP cache? -> probably unnecessary with tun, but maybe do it anyway? certainly don't want invalid ARP cache entries for pool addrs from before interface startup] // ... also (may) need to undo whatever configuration (remove addrs from if, routes, etc.) on destruction, CloseHandle on fd, set media status to disconnected, etc. #else check_err((fd = open(snow::conf[snow::CLONE_DEVICE].c_str(), O_RDWR)), "opening tun/tap clone device"); ifreq ifr; memset(&ifr, 0, sizeof(ifr)); // check size manually instead of using strncpy: strncpy fails silently and doesn't null terminate if there is insufficient space if(snow::conf[snow::VIRTUAL_INTERFACE].size() >= IFNAMSIZ) throw check_err_exception("VIRTUAL_INTERFACE name is too long", false); strcpy(ifr.ifr_name, snow::conf[snow::VIRTUAL_INTERFACE].c_str()); check_err(fcntl(fd, F_SETFL, O_NONBLOCK), "setting tuntap socket to non-blocking"); #ifdef __linux__ ifr.ifr_flags = IFF_TUN | IFF_NO_PI; check_err(ioctl(fd, TUNSETIFF, (void*) &ifr), "opening tun/tap interface"); #endif // note: Mac and BSD require a stupid hack to make tun behave properly because they insist on a single destination address being specified // solution is to exclude an address from the address pool and specify it as the destination when configuring the interface // then set a route specifying that address as the gateway for the entire snow subnet so OS will send them all to the tun interface // TODO: write code to do that programmatically for Mac/BSD // existing code seems to work on BSD if you set CLONE_DEVICE to e.g. /dev/tun0 and VIRTUAL_INTERFACE to e.g. tun0 and configure the tun interface manually, e.g.: // # ifconfig tun0 create 172.16.0.1 netmask 255.240.0.0 172.31.255.254 mtu 1419 // # route add -net 172.16.0.0 172.31.255.254 255.240.0.0 // (note: this must be done each time you start the daemon, when the daemon exits the interface remains but configuration is forgotten; same two commands w/o "create") // (note: 'ifconfig tun create' will create next tun# necessary, see if there is any simple way to replicate with API) // doing this programmatically requires call to ioctl passing SIOCSIFPHYADDR with in_aliasreq struct as follows: // ifra_name = "tun[#]" // ifra_addr as local interface addr // ifra_dstaddr as fake addr // ifra_mask as subnet mask // and then adding the route via some call to the BSD routing API csocket sock(AF_INET, SOCK_DGRAM); // need ordinary socket for SIOC[GS]*, can't use tun fd check_err(ioctl(sock.fd(), SIOCGIFFLAGS, (void*) &ifr), "getting tuntap interface flags"); if((ifr.ifr_flags & IFF_UP) == 0) { dout() << "tuntap interface was not up, trying to bring it up"; ifr.ifr_flags |= IFF_UP; // make sure interface is up check_err(ioctl(sock.fd(), SIOCSIFFLAGS, (void*) &ifr), "setting tuntap interface flags"); } else { dout() << "tuntap interface was up"; } // there are two possible ways of doing this which are both supported: either snow launches as root or with CAP_NET_ADMIN and sets these here, // or the interface is persistent and configured ahead of time, in which case only ownership of the interface is necessary // so what we do is check that everything is configured correctly and try to fix it if it isn't // that way everything is fine as long as the interface is correctly preconfigured -or- it isn't but we have rights to fix it in_addr addr, netmask; inet_pton(AF_INET, snow::conf[snow::NATPOOL_NETWORK].c_str(), &addr.s_addr); addr.s_addr = htonl(ntohl(addr.s_addr) + 1); netmask.s_addr = ~htonl((1 << (32 - snow::conf[snow::NATPOOL_NETMASK_BITS])) - 1); ifr.ifr_addr.sa_family = AF_INET; // EADDRNOTAVAIL is returned if no address is assigned which just means we have to assign the address, so then ifr_addr will be zero and not match addr int rv = ioctl(sock.fd(), SIOCGIFADDR, &ifr); if(rv < 0 && errno != EADDRNOTAVAIL) throw check_err_exception("getting tun/tap interface IP address"); sockaddrunion su; su.s = ifr.ifr_addr; dout() << "Got tuntap ifaddr " << ss_ipaddr(su.sa.sin_addr.s_addr); if(su.sa.sin_addr.s_addr != addr.s_addr) { dout() << "Virtual interface IP addr was " << ss_ipaddr(su.sa.sin_addr.s_addr) << ", should be " << ss_ipaddr(addr.s_addr) << ", trying to fix"; su.sa.sin_addr = addr; ifr.ifr_addr = su.s; check_err(ioctl(sock.fd(), SIOCSIFADDR, &ifr), "setting tun/tap interface IP address"); } check_err(ioctl(sock.fd(), SIOCGIFNETMASK, &ifr), "getting tun/tap interface netmask"); su.s = ifr.ifr_addr; dout() << "Got tuntap netmask " << ss_ipaddr(su.sa.sin_addr.s_addr); if(su.sa.sin_addr.s_addr != netmask.s_addr) { dout() << "Virtual interface netmask was " << ss_ipaddr(su.sa.sin_addr.s_addr) << ", should be " << ss_ipaddr(netmask.s_addr) << ", trying to fix"; su.sa.sin_addr = netmask; ifr.ifr_addr = su.s; check_err(ioctl(sock.fd(), SIOCSIFNETMASK, &ifr), "setting tun/tap interface netmask"); } mtu = snow::conf[snow::VIRTUAL_INTERFACE_MTU]; check_err(ioctl(sock.fd(), SIOCGIFMTU, (void*) &ifr), "getting tun/tap interface MTU"); dout() << "Existing tuntap interface MTU: " << ifr.ifr_mtu; if(ifr.ifr_mtu < MIN_PMTU || mtu != static_cast<unsigned>(ifr.ifr_mtu)) { dout() << "Virtual interface mtu was " << ifr.ifr_mtu << ", should be " << mtu << ", trying to fix"; ifr.ifr_mtu = mtu; check_err(ioctl(sock.fd(), SIOCSIFMTU, (void*) &ifr), "setting tun/tap interface MTU"); } iout() << "Virtual interface configured with network " << ss_ipaddr(addr.s_addr&netmask.s_addr) << " netmask " << ss_ipaddr(netmask.s_addr) << " address " << ss_ipaddr(addr.s_addr) << " MTU " << mtu; #endif }