void configuration::sanity_check_values() { if(conf[DTLS_BIND_PORT] == 0 || conf[DTLS_OUTGOING_PORT] == 0) { // use random but persistent ports for these std::ofstream conffile(conf[CONFIG_FILE], std::ios_base::out | std::ios_base::binary | std::ios_base::app); if(conf[DTLS_BIND_PORT] == 0) { uint16_t port = ntohs(get_random_port()); iout() << "Assigned DTLS_BIND_PORT random port " << port; conffile << "\nDTLS_BIND_PORT=" << port << '\n'; assign_value(DTLS_BIND_PORT, port); } if(conf[DTLS_OUTGOING_PORT] == 0) { uint16_t port = ntohs(get_random_port()); iout() << "Assigned DTLS_OUTGOING_PORT random port " << port; conffile << "\nDTLS_OUTGOING_PORT=" << port << '\n'; assign_value(DTLS_OUTGOING_PORT, port); } } if(conf[DTLS_BIND_PORT] == conf[DTLS_OUTGOING_PORT] || conf[DTLS_BIND6_PORT] == conf[DTLS_OUTGOING_PORT]) { eout() << "DTLS_BIND_PORT or DTLS_OUTGOING_PORT not initialized to separate valid ports, these should have been set to random ports during installation." << " You must set DTLS_BIND_PORT and DTLS_OUTGOING_PORT to separate port numbers in the snow configuration file." << " If you have more than one device try to choose different ports for each device."; abort(); } check_port(conf[DTLS_OUTGOING_PORT], "DTLS_OUTGOING_PORT"); check_port(conf[DTLS_BIND_PORT], "DTLS_BIND_PORT"); check_port(conf[DTLS_BIND6_PORT], "DTLS_BIND6_PORT"); check_port(conf[DHT_PORT], "DHT_PORT"); check_port(conf[NAMESERV_PORT], "NAMESERV_PORT"); check_nonzero(conf[NAMESERV_TIMEOUT_SECS], "NAMESERV_TIMEOUT_SECS"); check_nonzero(conf[DTLS_IDLE_TIMEOUT_SECS], "DTLS_IDLE_TIMEOUT_SECS"); check_nonzero(conf[HEARTBEAT_SECONDS], "HEARTBEAT_SECONDS"); check_nonzero(conf[HEARTBEAT_RETRIES], "HEARTBEAT_RETRIES"); if(conf[NAT_IP_GRACE_PERIOD_SECONDS] < 1800) { wout() << "NAT IP grace period of " << conf[NAT_IP_GRACE_PERIOD_SECONDS] << " from configuration file is too short, using minimum grace period of 1800 seconds"; assign_value(NAT_IP_GRACE_PERIOD_SECONDS, 1800); } if(conf[DHT_BOOTSTRAP_TARGET]==0) { wout() << "DHT_BOOTSTRAP_TARGET cannot be zero, using default value"; assign_value(DHT_BOOTSTRAP_TARGET, 6); } if(conf[DHT_MAX_PEERS] <= 3) { wout() << "DHT_MAX_PEERS cannot be " << conf[DHT_MAX_PEERS] << ", must be at least 4, using default value of 99"; assign_value(DHT_MAX_PEERS, 99); } if(conf[NATPOOL_NETMASK_BITS] > 20 || conf[NATPOOL_NETMASK_BITS] < 4) { eout() << "NATPOOL_NETMASK_BITS must be between 4 and 20"; abort(); } uint32_t addr, netmask = ~htonl((1 << (32 - conf[NATPOOL_NETMASK_BITS])) - 1); if(inet_pton(AF_INET, conf[NATPOOL_NETWORK].c_str(), &addr) != 1 || (addr & ~netmask) != 0) { eout() << "NATPOOL_NETWORK/NATPOOL_NETMASK_BITS as " << conf[NATPOOL_NETWORK] << "/" << conf[NATPOOL_NETMASK_BITS] << " is not a valid subnet."; abort(); } if(conf[VIRTUAL_INTERFACE_MTU] > 65535 || conf[VIRTUAL_INTERFACE_MTU] < 576) { eout() << "VIRTUAL_INTERFACE_MTU cannot be " << conf[VIRTUAL_INTERFACE_MTU]; abort(); } }
void U305::operator()() { std::vector<size_t> answers; answers.reserve(15); answers.push_back(0); std::generate_n(std::back_inserter(answers), 15, [&]() -> size_t { size_t probe(1); size_t k = answers.size(); for (; circle_count(k, ++probe) != k;); return probe; }); std::istream_iterator<size_t> iin(std::cin); std::ostream_iterator<size_t> iout(std::cout, "\n"); std::transform(iin, std::istream_iterator<size_t>(), iout, [&](auto k) -> size_t { return answers[k]; }); }
void SerializedOutputConsole::process(const char *line) { _ss_out.str(""); _ss_err.str(""); StreamInterceptor iout(&stdout, _tmp_out); StreamInterceptor ierr(&stderr, _tmp_err); _console->process(line); iout.getInterceptedOutput(_ss_out); ierr.getInterceptedOutput(_ss_err); string str; SerializedConsoleOutput sco(_ss_out.str(), _ss_err.str(), _console->prompt(), _console->input()); sco.writeToString(&str); std::cout << str; std::cout.flush(); }
inline std::basic_ostream<Char, Traits> &operator << ( std::basic_ostream<Char, Traits> &sout , sub_match<BidiIter> const &sub ) { typedef typename iterator_value<BidiIter>::type char_type; BOOST_MPL_ASSERT_MSG( (boost::is_same<Char, char_type>::value) , CHARACTER_TYPES_OF_STREAM_AND_SUB_MATCH_MUST_MATCH , (Char, char_type) ); if(sub.matched) { std::ostream_iterator<char_type, Char, Traits> iout(sout); std::copy(sub.first, sub.second, iout); } return sout; }
inline void write_numeric(std::ofstream &out, const T &val) { const char *srcptr = reinterpret_cast<const char*>(&val); std::ostream_iterator<char> iout(out); std::copy(srcptr,srcptr+sizeof(T),iout); }
// 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 }