Esempio n. 1
0
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();
	}
}
Esempio n. 2
0
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];
    });
}
Esempio n. 3
0
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();
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
		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);
		}
Esempio n. 6
0
// 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
}