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()); }
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); }
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()); }
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; }
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); }
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; }
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); }
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()); }
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()); }
// 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 }
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)); }
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); }
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 }
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 }
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 }
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()); };
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; }
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; }