tcp::endpoint utp_socket_manager::local_endpoint(address const& remote, error_code& ec) const
	{
		tcp::endpoint socket_ep = m_sock.local_endpoint(ec);

		// first enumerate the routes in the routing table
		if (time_now() - m_last_route_update > seconds(60))
		{
			m_last_route_update = time_now();
			error_code ec;
			m_routes = enum_routes(m_sock.get_io_service(), ec);
			if (ec) return socket_ep;
		}

		if (m_routes.empty()) return socket_ep;
		// then find the best match
		ip_route* best = &m_routes[0];
		for (std::vector<ip_route>::iterator i = m_routes.begin()
			, end(m_routes.end()); i != end; ++i)
		{
			if (is_any(i->destination) && i->destination.is_v4() == remote.is_v4())
			{
				best = &*i;
				continue;
			}

			if (match_addr_mask(remote, i->destination, i->netmask))
			{
				best = &*i;
				continue;
			}
		}

		// best now tells us which interface we would send over
		// for this target. Now figure out what the local address
		// is for that interface

		if (time_now() - m_last_if_update > seconds(60))
		{
			m_last_if_update = time_now();
			error_code ec;
			m_interfaces = enum_net_interfaces(m_sock.get_io_service(), ec);
			if (ec) return socket_ep;
		}

		for (std::vector<ip_interface>::iterator i = m_interfaces.begin()
			, end(m_interfaces.end()); i != end; ++i)
		{
			if (i->interface_address.is_v4() != remote.is_v4())
				continue;

			if (strcmp(best->name, i->name) == 0)
				return tcp::endpoint(i->interface_address, socket_ep.port());
		}
		return socket_ep;
	}
	void utp_socket_manager::mtu_for_dest(address const& addr, int& link_mtu, int& utp_mtu)
	{

		int mtu = 0;
		if (is_teredo(addr)) mtu = TORRENT_TEREDO_MTU;
		else mtu = TORRENT_ETHERNET_MTU;

#if defined __APPLE__
		// apple has a very strange loopback. It appears you can't
		// send messages of the reported MTU size, and you don't get
		// EWOULDBLOCK either.
		if (is_loopback(addr))
		{
			if (is_teredo(addr)) mtu = TORRENT_TEREDO_MTU;
			else mtu = TORRENT_ETHERNET_MTU;
		}
#endif

		// clamp the MTU within reasonable bounds
		if (mtu < TORRENT_INET_MIN_MTU) mtu = TORRENT_INET_MIN_MTU;
		else if (mtu > TORRENT_INET_MAX_MTU) mtu = TORRENT_INET_MAX_MTU;

		link_mtu = mtu;

		mtu -= TORRENT_UDP_HEADER;

		if (m_sock.get_proxy_settings().type == settings_pack::socks5
			|| m_sock.get_proxy_settings().type == settings_pack::socks5_pw)
		{
			// this is for the IP layer
			address proxy_addr = m_sock.proxy_addr().address();
			if (proxy_addr.is_v4()) mtu -= TORRENT_IPV4_HEADER;
			else mtu -= TORRENT_IPV6_HEADER;

			// this is for the SOCKS layer
			mtu -= TORRENT_SOCKS5_HEADER;

			// the address field in the SOCKS header
			if (addr.is_v4()) mtu -= 4;
			else mtu -= 16;
		}
		else
		{
			if (addr.is_v4()) mtu -= TORRENT_IPV4_HEADER;
			else mtu -= TORRENT_IPV6_HEADER;
		}

		utp_mtu = (std::min)(mtu, restrict_mtu());
	}
Beispiel #3
0
	void ip_filter::add_rule(address first, address last, int flags)
	{
		if (first.is_v4())
		{
			assert(last.is_v4());
			m_filter4.add_rule(first.to_v4(), last.to_v4(), flags);
		}
		else if (first.is_v6())
		{
			assert(last.is_v6());
			m_filter6.add_rule(first.to_v6(), last.to_v6(), flags);
		}
		else
			assert(false);
	}
Beispiel #4
0
	int ip_filter::access(address const& addr) const
	{
		if (addr.is_v4())
			return m_filter4.access(addr.to_v4());
		assert(addr.is_v6());
		return m_filter6.access(addr.to_v6());
	}
Beispiel #5
0
    void broadcast_socket::open_multicast_socket(
        io_service& ios, address const& addr, bool loopback, error_code& ec)
    {
        using namespace asio::ip::multicast;

        boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
        s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
        if (ec) return;
        s->set_option(datagram_socket::reuse_address(true), ec);
        if (ec) return;
        s->bind(udp::endpoint(addr, m_multicast_endpoint.port()), ec);
        if (ec) return;
        s->set_option(join_group(m_multicast_endpoint.address()), ec);
        if (ec) return;
        s->set_option(hops(255), ec);
        if (ec) return;
        s->set_option(enable_loopback(loopback), ec);
        if (ec) return;
        m_sockets.push_back(socket_entry(s));
        socket_entry& se = m_sockets.back();
#if defined LIBED2K_ASIO_DEBUGGING
        add_outstanding_async("broadcast_socket::on_receive");
#endif
        s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer)),
                              se.remote, boost::bind(&broadcast_socket::on_receive, this, &se, _1, _2));
        ++m_outstanding_operations;
    }
Beispiel #6
0
inline T address_cast(const address& addr,
                      typename enable_if<is_same<T, address_v4>::value>::type* = 0)
{
    if (!addr.is_v4())
        throw bad_address_cast();
    return get_v4_helper(addr);
}
Beispiel #7
0
    void broadcast_socket::open_unicast_socket(
        io_service& ios, address const& addr, address_v4 const& mask)
    {
        using namespace asio::ip::multicast;
        error_code ec;
        boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
        s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
        if (ec) return;
        s->bind(udp::endpoint(addr, 0), ec);
        if (ec) return;

        m_unicast_sockets.push_back(socket_entry(s, mask));
        socket_entry& se = m_unicast_sockets.back();

        // allow sending broadcast messages
        asio::socket_base::broadcast option(true);
        s->set_option(option, ec);
        if (!ec) se.broadcast = true;

#if defined LIBED2K_ASIO_DEBUGGING
        add_outstanding_async("broadcast_socket::on_receive");
#endif
        s->async_receive_from(
            asio::buffer(se.buffer, sizeof(se.buffer)), se.remote, 
            boost::bind(&broadcast_socket::on_receive, this, &se, _1, _2));
        ++m_outstanding_operations;
    }
Beispiel #8
0
	void ip_filter::add_rule(address first, address last, boost::uint32_t flags)
	{
		if (first.is_v4())
		{
			TORRENT_ASSERT(last.is_v4());
			m_filter4.add_rule(first.to_v4().to_bytes(), last.to_v4().to_bytes(), flags);
		}
#if TORRENT_USE_IPV6
		else if (first.is_v6())
		{
			TORRENT_ASSERT(last.is_v6());
			m_filter6.add_rule(first.to_v6().to_bytes(), last.to_v6().to_bytes(), flags);
		}
#endif
		else
			TORRENT_ASSERT(false);
	}
Beispiel #9
0
	int ip_filter::access(address const& addr) const
	{
		if (addr.is_v4())
			return m_filter4.access(addr.to_v4().to_bytes());
#if TORRENT_USE_IPV6
		TORRENT_ASSERT(addr.is_v6());
		return m_filter6.access(addr.to_v6().to_bytes());
#else
		return 0;
#endif
	}
	// returns the number of bits in that differ from the right
	// between the addresses.
	int cidr_distance(address const& a1, address const& a2)
	{
		if (a1.is_v4() && a2.is_v4())
		{
			// both are v4
			address_v4::bytes_type b1 = a1.to_v4().to_bytes();
			address_v4::bytes_type b2 = a2.to_v4().to_bytes();
			return address_v4::bytes_type::static_size * 8
				- common_bits(b1.c_array(), b2.c_array(), b1.size());
		}
	
		address_v6::bytes_type b1;
		address_v6::bytes_type b2;
		if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
		else b1 = a1.to_v6().to_bytes();
		if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
		else b2 = a2.to_v6().to_bytes();
		return address_v6::bytes_type::static_size * 8
			- common_bits(b1.c_array(), b2.c_array(), b1.size());
	}
Beispiel #11
0
	bool in_subnet(address const& addr, ip_interface const& iface)
	{
		if (addr.is_v4() != iface.interface_address.is_v4()) return false;
		// since netmasks seems unreliable for IPv6 interfaces
		// (MacOS X returns AF_INET addresses as bitmasks) assume
		// that any IPv6 address belongs to the subnet of any
		// interface with an IPv6 address
		if (addr.is_v6()) return true;

		return (addr.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong())
			== (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong());
	}
Beispiel #12
0
    // returns the number of bits in that differ from the right
    // between the addresses. The larger number, the further apart
    // the IPs are
    int cidr_distance(address const& a1, address const& a2)
    {
#if LIBED2K_USE_IPV6
        if (a1.is_v4() && a2.is_v4())
        {
#endif
            // both are v4
            address_v4::bytes_type b1 = a1.to_v4().to_bytes();
            address_v4::bytes_type b2 = a2.to_v4().to_bytes();
            return address_v4::bytes_type().size() * 8 - common_bits(b1.data(), b2.data(), b1.size());
#if LIBED2K_USE_IPV6
        }

        address_v6::bytes_type b1;
        address_v6::bytes_type b2;
        if (a1.is_v4()) b1 = address_v6::v4_mapped(a1.to_v4()).to_bytes();
        else b1 = a1.to_v6().to_bytes();
        if (a2.is_v4()) b2 = address_v6::v4_mapped(a2.to_v4()).to_bytes();
        else b2 = a2.to_v6().to_bytes();
        return address_v6::bytes_type().size() * 8 - common_bits(b1.data(), b2.data(), b1.size());
#endif
    }
Beispiel #13
0
		void write_address(address const& a, OutIt& out)
		{
			if (a.is_v4())
			{
				write_uint32(a.to_v4().to_ulong(), out);
			}
			else if (a.is_v6())
			{
				address_v6::bytes_type bytes
					= a.to_v6().to_bytes();
				std::copy(bytes.begin(), bytes.end(), out);
			}
		}
	void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
	{
		using namespace asio::ip::multicast;
		error_code ec;
		boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
		s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
		if (ec) return;
		s->bind(udp::endpoint(addr, 0), ec);
		if (ec) return;
		m_unicast_sockets.push_back(socket_entry(s));
		socket_entry& se = m_unicast_sockets.back();
		s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
			, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
	}
Beispiel #15
0
address mask_address(const address& addrIn, uint8_t prefixLen) {
    if (addrIn.is_v4()) {
        prefixLen = std::min<uint8_t>(prefixLen, 32);
        uint32_t mask = get_subnet_mask_v4(prefixLen);
        return address_v4(addrIn.to_v4().to_ulong() & mask);
    }
    struct in6_addr mask;
    struct in6_addr addr6;
    prefixLen = std::min<uint8_t>(prefixLen, 128);
    compute_ipv6_subnet(addrIn.to_v6(), prefixLen, &mask, &addr6);
    address_v6::bytes_type data;
    std::memcpy(data.data(), &addr6, sizeof(addr6));
    return address_v6(data);
}
Beispiel #16
0
		void write_address(address const& a, OutIt&& out)
		{
#if TORRENT_USE_IPV6
			if (a.is_v4())
			{
#endif
				write_uint32(a.to_v4().to_ulong(), out);
#if TORRENT_USE_IPV6
			}
			else if (a.is_v6())
			{
				for (auto b : a.to_v6().to_bytes())
					write_uint8(b, out);
			}
#endif
		}
Beispiel #17
0
		void write_address(address const& a, OutIt& out)
		{
#if TORRENT_USE_IPV6
			if (a.is_v4())
			{
#endif
				write_uint32(a.to_v4().to_ulong(), out);
#if TORRENT_USE_IPV6
			}
			else if (a.is_v6())
			{
				address_v6::bytes_type bytes
					= a.to_v6().to_bytes();
				std::copy(bytes.begin(), bytes.end(), out);
			}
#endif
		}
Beispiel #18
0
		void write_address(address const& a, OutIt& out)
		{
#if TORRENT_USE_IPV6
			if (a.is_v4())
			{
#endif
				write_uint32(a.to_v4().to_ulong(), out);
#if TORRENT_USE_IPV6
			}
			else if (a.is_v6())
			{
				typedef address_v6::bytes_type bytes_t;
				bytes_t bytes = a.to_v6().to_bytes();
				for (bytes_t::iterator i = bytes.begin()
					, end(bytes.end()); i != end; ++i)
					write_uint8(*i, out);
			}
#endif
		}
Beispiel #19
0
void natpmp::rebind(address const& listen_interface) try
{
	address_v4 local = address_v4::any();
	if (listen_interface.is_v4() && listen_interface != address_v4::any())
	{
		local = listen_interface.to_v4();
	}
	else
	{
		local = guess_local_address(m_socket.io_service());

		if (local == address_v4::any())
		{
			throw std::runtime_error("local host is probably not on a NATed "
				"network. disabling NAT-PMP");
		}
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " local ip: " << local.to_string() << std::endl;
#endif

	if (!is_local(local))
	{
		// the local address seems to be an external
		// internet address. Assume it is not behind a NAT
		throw std::runtime_error("local IP is not on a local network");
	}

	m_disabled = false;

	// assume the router is located on the local
	// network as x.x.x.1
	udp::endpoint nat_endpoint(
		address_v4((local.to_ulong() & 0xffffff00) | 1), 5351);

	if (nat_endpoint == m_nat_endpoint) return;

	// TODO: find a better way to figure out the router IP
	m_nat_endpoint = nat_endpoint;

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl;
#endif

	m_socket.open(udp::v4());
	m_socket.bind(udp::endpoint(address_v4::any(), 0));

	for (int i = 0; i < num_mappings; ++i)
	{
		if (m_mappings[i].local_port == 0)
			continue;
		refresh_mapping(i);
	}
}
catch (std::exception& e)
{
	m_disabled = true;
	std::stringstream msg;
	msg << "NAT-PMP disabled: " << e.what();
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << msg.str() << std::endl;
#endif
	m_callback(0, 0, msg.str());
};
Beispiel #20
0
	void utp_socket_manager::mtu_for_dest(address const& addr, int& link_mtu, int& utp_mtu)
	{
		if (time_now() - m_last_route_update > seconds(60))
		{
			m_last_route_update = time_now();
			error_code ec;
			m_routes = enum_routes(m_sock.get_io_service(), ec);
		}

		int mtu = 0;
		if (!m_routes.empty())
		{
			for (std::vector<ip_route>::iterator i = m_routes.begin()
				, end(m_routes.end()); i != end; ++i)
			{
				if (!match_addr_mask(addr, i->destination, i->netmask)) continue;

				// assume that we'll actually use the route with the largest
				// MTU (seems like a reasonable assumption).
				// this could however be improved by using the route metrics
				// and the prefix length of the netmask to order the matches
				if (mtu < i->mtu) mtu = i->mtu;
			}
		}

		if (mtu == 0)
		{
			if (is_teredo(addr)) mtu = TORRENT_TEREDO_MTU;
			else mtu = TORRENT_ETHERNET_MTU;
		}

		// clamp the MTU within reasonable bounds
		if (mtu < TORRENT_INET_MIN_MTU) mtu = TORRENT_INET_MIN_MTU;
		else if (mtu > TORRENT_INET_MAX_MTU) mtu = TORRENT_INET_MAX_MTU;

		link_mtu = mtu;

		mtu -= TORRENT_UDP_HEADER;

		if (m_sock.get_proxy_settings().type == proxy_settings::socks5
			|| m_sock.get_proxy_settings().type == proxy_settings::socks5_pw)
		{
			// this is for the IP layer
			address proxy_addr = m_sock.proxy_addr().address();
			if (proxy_addr.is_v4()) mtu -= TORRENT_IPV4_HEADER;
			else mtu -= TORRENT_IPV6_HEADER;

			// this is for the SOCKS layer
			mtu -= TORRENT_SOCKS5_HEADER;

			// the address field in the SOCKS header
			if (addr.is_v4()) mtu -= 4;
			else mtu -= 16;

		}
		else
		{
			if (addr.is_v4()) mtu -= TORRENT_IPV4_HEADER;
			else mtu -= TORRENT_IPV6_HEADER;
		}

		utp_mtu = mtu;
	}
Beispiel #21
0
	bool ip_voter::cast_vote(address const& ip
		, int source_type, address const& source)
	{
		if (is_any(ip)) return false;
		if (is_local(ip)) return false;
		if (is_loopback(ip)) return false;

		// don't trust source that aren't connected to us
		// on a different address family than the external
		// IP they claim we have
		if (ip.is_v4() != source.is_v4()) return false;

		// this is the key to use for the bloom filters
		// it represents the identity of the voter
		sha1_hash k;
		hash_address(source, k);

		// do we already have an entry for this external IP?
		std::vector<external_ip_t>::iterator i = std::find_if(m_external_addresses.begin()
			, m_external_addresses.end(), boost::bind(&external_ip_t::addr, _1) == ip);

		if (i == m_external_addresses.end())
		{
			// each IP only gets to add a new IP once
			if (m_external_address_voters.find(k)) return maybe_rotate();
		
			if (m_external_addresses.size() > 40)
			{
				if (random() % 100 < 50)
					return maybe_rotate();

				// use stable sort here to maintain the fifo-order
				// of the entries with the same number of votes
				// this will sort in ascending order, i.e. the lowest
				// votes first. Also, the oldest are first, so this
				// is a sort of weighted LRU.
				std::stable_sort(m_external_addresses.begin(), m_external_addresses.end());

				// erase the last element, since it is one of the
				// ones with the fewest votes
				m_external_addresses.erase(m_external_addresses.end() - 1);
			}
			m_external_addresses.push_back(external_ip_t());
			i = m_external_addresses.end() - 1;
			i->addr = ip;
		}
		// add one more vote to this external IP
		if (!i->add_vote(k, source_type)) return maybe_rotate();
		++m_total_votes;
		
		if (m_valid_external) return maybe_rotate();

		i = std::min_element(m_external_addresses.begin(), m_external_addresses.end());
		TORRENT_ASSERT(i != m_external_addresses.end());

		if (i->addr == m_external_address) return maybe_rotate();

		if (m_external_address != address_v4())
		{
			// we have a temporary external address. As soon as we have
			// more than 25 votes, consider deciding which one to settle for
			return (m_total_votes >= 25) ? maybe_rotate() : false;
		}

		m_external_address = i->addr;

		return true;
	}