diff options
author | Thomas Winget <tewinget@gmail.com> | 2019-04-10 18:34:30 -0400 |
---|---|---|
committer | Thomas Winget <tewinget@gmail.com> | 2019-07-31 20:04:57 -0400 |
commit | 155475d9719694c838297cb3fbc94a2782329d46 (patch) | |
tree | 0a8ac9cfc80c123f456fc2416b60752a42ae4f9b /src/p2p/net_node.inl | |
parent | Merge pull request #5635 (diff) | |
download | monero-155475d9719694c838297cb3fbc94a2782329d46.tar.xz |
Add IPv6 support
new cli options (RPC ones also apply to wallet):
--p2p-bind-ipv6-address (default = "::")
--p2p-bind-port-ipv6 (default same as ipv4 port for given nettype)
--rpc-bind-ipv6-address (default = "::1")
--p2p-use-ipv6 (default false)
--rpc-use-ipv6 (default false)
--p2p-require-ipv4 (default true, if ipv4 bind fails and this is
true, will not continue even if ipv6 bind
successful)
--rpc-require-ipv4 (default true, description as above)
ipv6 addresses are to be specified as "[xx:xx:xx::xx:xx]:port" except
in the cases of the cli args for bind address. For those the square
braces can be omitted.
Diffstat (limited to 'src/p2p/net_node.inl')
-rw-r--r-- | src/p2p/net_node.inl | 192 |
1 files changed, 161 insertions, 31 deletions
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 98484fe78..426767365 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -93,7 +93,11 @@ namespace nodetool void node_server<t_payload_net_handler>::init_options(boost::program_options::options_description& desc) { command_line::add_arg(desc, arg_p2p_bind_ip); + command_line::add_arg(desc, arg_p2p_bind_ipv6_address); command_line::add_arg(desc, arg_p2p_bind_port, false); + command_line::add_arg(desc, arg_p2p_bind_port_ipv6, false); + command_line::add_arg(desc, arg_p2p_use_ipv6); + command_line::add_arg(desc, arg_p2p_require_ipv4); command_line::add_arg(desc, arg_p2p_external_port); command_line::add_arg(desc, arg_p2p_allow_local_ip); command_line::add_arg(desc, arg_p2p_add_peer); @@ -341,7 +345,9 @@ namespace nodetool network_zone& public_zone = m_network_zones[epee::net_utils::zone::public_]; public_zone.m_connect = &public_connect; public_zone.m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip); + public_zone.m_bind_ipv6_address = command_line::get_arg(vm, arg_p2p_bind_ipv6_address); public_zone.m_port = command_line::get_arg(vm, arg_p2p_bind_port); + public_zone.m_port_ipv6 = command_line::get_arg(vm, arg_p2p_bind_port_ipv6); public_zone.m_can_pingback = true; m_external_port = command_line::get_arg(vm, arg_p2p_external_port); m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip); @@ -375,6 +381,8 @@ namespace nodetool return false; } m_offline = command_line::get_arg(vm, cryptonote::arg_offline); + m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6); + m_require_ipv4 = command_line::get_arg(vm, arg_p2p_require_ipv4); if (command_line::has_arg(vm, arg_p2p_add_peer)) { @@ -518,12 +526,17 @@ namespace nodetool std::string host = addr; std::string port = std::to_string(default_port); - size_t pos = addr.find_last_of(':'); - if (std::string::npos != pos) + size_t colon_pos = addr.find_last_of(':'); + size_t dot_pos = addr.find_last_of('.'); + size_t square_brace_pos = addr.find('['); + + // IPv6 will have colons regardless. IPv6 and IPv4 address:port will have a colon but also either a . or a [ + // as IPv6 addresses specified as address:port are to be specified as "[addr:addr:...:addr]:port" + // One may also specify an IPv6 address as simply "[addr:addr:...:addr]" without the port; in that case + // the square braces will be stripped here. + if ((std::string::npos != colon_pos && std::string::npos != dot_pos) || std::string::npos != square_brace_pos) { - CHECK_AND_ASSERT_MES(addr.length() - 1 != pos && 0 != pos, false, "Failed to parse seed address from string: '" << addr << '\''); - host = addr.substr(0, pos); - port = addr.substr(pos + 1); + net::get_network_address_host_and_port(addr, host, port); } MINFO("Resolving node address: host=" << host << ", port=" << port); @@ -546,7 +559,9 @@ namespace nodetool } else { - MWARNING("IPv6 unsupported, skip '" << host << "' -> " << endpoint.address().to_v6().to_string(ec)); + epee::net_utils::network_address na{epee::net_utils::ipv6_network_address{endpoint.address().to_v6(), endpoint.port()}}; + seed_nodes.push_back(na); + MINFO("Added node: " << na.str()); } } return true; @@ -780,21 +795,40 @@ namespace nodetool if (!zone.second.m_bind_ip.empty()) { + std::string ipv6_addr = ""; + std::string ipv6_port = ""; zone.second.m_net_server.set_connection_filter(this); - MINFO("Binding on " << zone.second.m_bind_ip << ":" << zone.second.m_port); - res = zone.second.m_net_server.init_server(zone.second.m_port, zone.second.m_bind_ip, epee::net_utils::ssl_support_t::e_ssl_support_disabled); + MINFO("Binding (IPv4) on " << zone.second.m_bind_ip << ":" << zone.second.m_port); + if (!zone.second.m_bind_ipv6_address.empty() && m_use_ipv6) + { + ipv6_addr = zone.second.m_bind_ipv6_address; + ipv6_port = zone.second.m_port_ipv6; + MINFO("Binding (IPv6) on " << zone.second.m_bind_ipv6_address << ":" << zone.second.m_port_ipv6); + } + res = zone.second.m_net_server.init_server(zone.second.m_port, zone.second.m_bind_ip, ipv6_port, ipv6_addr, m_use_ipv6, m_require_ipv4, epee::net_utils::ssl_support_t::e_ssl_support_disabled); CHECK_AND_ASSERT_MES(res, false, "Failed to bind server"); } } m_listening_port = public_zone.m_net_server.get_binded_port(); - MLOG_GREEN(el::Level::Info, "Net service bound to " << public_zone.m_bind_ip << ":" << m_listening_port); + MLOG_GREEN(el::Level::Info, "Net service bound (IPv4) to " << public_zone.m_bind_ip << ":" << m_listening_port); + if (m_use_ipv6) + { + m_listening_port_ipv6 = public_zone.m_net_server.get_binded_port_ipv6(); + MLOG_GREEN(el::Level::Info, "Net service bound (IPv6) to " << public_zone.m_bind_ipv6_address << ":" << m_listening_port_ipv6); + } if(m_external_port) MDEBUG("External port defined as " << m_external_port); // add UPnP port mapping if(m_igd == igd) - add_upnp_port_mapping(m_listening_port); + { + add_upnp_port_mapping_v4(m_listening_port); + if (m_use_ipv6) + { + add_upnp_port_mapping_v6(m_listening_port_ipv6); + } + } return res; } @@ -1997,19 +2031,43 @@ namespace nodetool if(!node_data.my_port) return false; - CHECK_AND_ASSERT_MES(context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(), false, - "Only IPv4 addresses are supported here"); + bool address_ok = (context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id() || context.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()); + CHECK_AND_ASSERT_MES(address_ok, false, + "Only IPv4 or IPv6 addresses are supported here"); const epee::net_utils::network_address na = context.m_remote_address; - uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip(); + std::string ip; + uint32_t ipv4_addr; + boost::asio::ip::address_v6 ipv6_addr; + bool is_ipv4; + if (na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) + { + ipv4_addr = na.as<const epee::net_utils::ipv4_network_address>().ip(); + ip = epee::string_tools::get_ip_string_from_int32(ipv4_addr); + is_ipv4 = true; + } + else + { + ipv6_addr = na.as<const epee::net_utils::ipv6_network_address>().ip(); + ip = ipv6_addr.to_string(); + is_ipv4 = false; + } network_zone& zone = m_network_zones.at(na.get_zone()); if(!zone.m_peerlist.is_host_allowed(context.m_remote_address)) return false; - std::string ip = epee::string_tools::get_ip_string_from_int32(actual_ip); std::string port = epee::string_tools::num_to_string_fast(node_data.my_port); - epee::net_utils::network_address address{epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port)}; + + epee::net_utils::network_address address; + if (is_ipv4) + { + address = epee::net_utils::network_address{epee::net_utils::ipv4_network_address(ipv4_addr, node_data.my_port)}; + } + else + { + address = epee::net_utils::network_address{epee::net_utils::ipv6_network_address(ipv6_addr, node_data.my_port)}; + } peerid_type pr = node_data.peer_id; bool r = zone.m_net_server.connect_async(ip, port, zone.m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this]( const typename net_server::t_connection_context& ping_context, @@ -2193,12 +2251,19 @@ namespace nodetool //try ping to be sure that we can add this peer to peer_list try_ping(arg.node_data, context, [peer_id_l, port_l, context, this]() { - CHECK_AND_ASSERT_MES(context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(), void(), - "Only IPv4 addresses are supported here"); + CHECK_AND_ASSERT_MES((context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id() || context.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()), void(), + "Only IPv4 or IPv6 addresses are supported here"); //called only(!) if success pinged, update local peerlist peerlist_entry pe; const epee::net_utils::network_address na = context.m_remote_address; - pe.adr = epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l); + if (context.m_remote_address.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id()) + { + pe.adr = epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l); + } + else + { + pe.adr = epee::net_utils::ipv6_network_address(na.as<epee::net_utils::ipv6_network_address>().ip(), port_l); + } time_t last_seen; time(&last_seen); pe.last_seen = static_cast<int64_t>(last_seen); @@ -2565,16 +2630,19 @@ namespace nodetool } template<class t_payload_net_handler> - void node_server<t_payload_net_handler>::add_upnp_port_mapping(uint32_t port) + void node_server<t_payload_net_handler>::add_upnp_port_mapping_impl(uint32_t port, bool ipv6) // if ipv6 false, do ipv4 { - MDEBUG("Attempting to add IGD port mapping."); + std::string ipversion = ipv6 ? "(IPv6)" : "(IPv4)"; + MDEBUG("Attempting to add IGD port mapping " << ipversion << "."); int result; + const int ipv6_arg = ipv6 ? 1 : 0; + #if MINIUPNPC_API_VERSION > 13 // default according to miniupnpc.h unsigned char ttl = 2; - UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, ttl, &result); + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, ttl, &result); #else - UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result); + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, &result); #endif UPNPUrls urls; IGDdatas igdData; @@ -2611,16 +2679,38 @@ namespace nodetool } template<class t_payload_net_handler> - void node_server<t_payload_net_handler>::delete_upnp_port_mapping(uint32_t port) + void node_server<t_payload_net_handler>::add_upnp_port_mapping_v4(uint32_t port) + { + add_upnp_port_mapping_impl(port, false); + } + + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::add_upnp_port_mapping_v6(uint32_t port) + { + add_upnp_port_mapping_impl(port, true); + } + + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::add_upnp_port_mapping(uint32_t port, bool ipv4, bool ipv6) + { + if (ipv4) add_upnp_port_mapping_v4(port); + if (ipv6) add_upnp_port_mapping_v6(port); + } + + + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::delete_upnp_port_mapping_impl(uint32_t port, bool ipv6) { - MDEBUG("Attempting to delete IGD port mapping."); + std::string ipversion = ipv6 ? "(IPv6)" : "(IPv4)"; + MDEBUG("Attempting to delete IGD port mapping " << ipversion << "."); int result; + const int ipv6_arg = ipv6 ? 1 : 0; #if MINIUPNPC_API_VERSION > 13 // default according to miniupnpc.h unsigned char ttl = 2; - UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, ttl, &result); + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, ttl, &result); #else - UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result); + UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, ipv6_arg, &result); #endif UPNPUrls urls; IGDdatas igdData; @@ -2653,6 +2743,25 @@ namespace nodetool } } + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::delete_upnp_port_mapping_v4(uint32_t port) + { + delete_upnp_port_mapping_impl(port, false); + } + + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::delete_upnp_port_mapping_v6(uint32_t port) + { + delete_upnp_port_mapping_impl(port, true); + } + + template<class t_payload_net_handler> + void node_server<t_payload_net_handler>::delete_upnp_port_mapping(uint32_t port) + { + delete_upnp_port_mapping_v4(port); + delete_upnp_port_mapping_v6(port); + } + template<typename t_payload_net_handler> boost::optional<p2p_connection_context_t<typename t_payload_net_handler::connection_context>> node_server<t_payload_net_handler>::socks_connect(network_zone& zone, const epee::net_utils::network_address& remote, epee::net_utils::ssl_support_t ssl_support) @@ -2671,13 +2780,34 @@ namespace nodetool boost::optional<p2p_connection_context_t<typename t_payload_net_handler::connection_context>> node_server<t_payload_net_handler>::public_connect(network_zone& zone, epee::net_utils::network_address const& na, epee::net_utils::ssl_support_t ssl_support) { - CHECK_AND_ASSERT_MES(na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(), boost::none, - "Only IPv4 addresses are supported here"); - const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>(); + bool is_ipv4 = na.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id(); + bool is_ipv6 = na.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id(); + CHECK_AND_ASSERT_MES(is_ipv4 || is_ipv6, boost::none, + "Only IPv4 or IPv6 addresses are supported here"); + + std::string address; + std::string port; + + if (is_ipv4) + { + const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>(); + address = epee::string_tools::get_ip_string_from_int32(ipv4.ip()); + port = epee::string_tools::num_to_string_fast(ipv4.port()); + } + else if (is_ipv6) + { + const epee::net_utils::ipv6_network_address &ipv6 = na.as<const epee::net_utils::ipv6_network_address>(); + address = ipv6.ip().to_string(); + port = epee::string_tools::num_to_string_fast(ipv6.port()); + } + else + { + LOG_ERROR("Only IPv4 or IPv6 addresses are supported here"); + return boost::none; + } typename net_server::t_connection_context con{}; - const bool res = zone.m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()), - epee::string_tools::num_to_string_fast(ipv4.port()), + const bool res = zone.m_net_server.connect(address, port, zone.m_config.m_net_config.connection_timeout, con, "0.0.0.0", ssl_support); |