diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 2af45bed3..7c4775131 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -65,9 +65,11 @@ set(LIB_PLATFORM_SRC ev/pipe.cpp metrics/metrictank_publisher.cpp metrics/publishers.cpp + net/ip.cpp net/net.cpp net/net_addr.cpp net/net_inaddr.cpp + net/net_int.cpp # for android shim ${ANDROID_PLATFORM_SRC} # process isolation implementation @@ -194,8 +196,6 @@ set(LIB_SRC messages/transfer_traffic.cpp net/address_info.cpp net/exit_info.cpp - net/ip.cpp - net/net_int.cpp nodedb.cpp path/path.cpp path/path_types.cpp diff --git a/llarp/dns/message.cpp b/llarp/dns/message.cpp index eb169b6c0..2514dec44 100644 --- a/llarp/dns/message.cpp +++ b/llarp/dns/message.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -165,7 +166,7 @@ namespace llarp } void - Message::AddINReply(llarp::huint32_t ip, bool isV6, RR_TTL_t ttl) + Message::AddINReply(llarp::huint128_t ip, bool isV6, RR_TTL_t ttl) { if(questions.size()) { @@ -182,9 +183,10 @@ namespace llarp } else { - rec.rr_type = qTypeA; + const auto addr = net::IPPacket::TruncateV6(ip); + rec.rr_type = qTypeA; rec.rData.resize(4); - htobe32buf(rec.rData.data(), ip.h); + htobe32buf(rec.rData.data(), addr.h); } answers.emplace_back(std::move(rec)); } diff --git a/llarp/dns/message.hpp b/llarp/dns/message.hpp index f42216d33..108a437ab 100644 --- a/llarp/dns/message.hpp +++ b/llarp/dns/message.hpp @@ -64,7 +64,7 @@ namespace llarp AddCNAMEReply(std::string name, RR_TTL_t ttl = 1); void - AddINReply(llarp::huint32_t addr, bool isV6, RR_TTL_t ttl = 1); + AddINReply(llarp::huint128_t addr, bool isV6, RR_TTL_t ttl = 1); void AddAReply(std::string name, RR_TTL_t ttl = 1); diff --git a/llarp/ev/ev.cpp b/llarp/ev/ev.cpp index 8b2fb96d2..dd0c0c50b 100644 --- a/llarp/ev/ev.cpp +++ b/llarp/ev/ev.cpp @@ -154,9 +154,9 @@ llarp_ev_add_tun(struct llarp_ev_loop *loop, struct llarp_tun_io *tun) dev->setup(); return dev->add_ev(); // start up tun and add to event queue } -#endif llarp::LogWarn("Loop could not create tun"); return false; +#endif } bool diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index 5d7b6412c..bb34fd4bd 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -613,6 +613,7 @@ namespace libuv m_CloseFuncs.emplace_back(std::bind(&tun_glue ::Close, glue)); return true; } + delete glue; return false; } diff --git a/llarp/exit/endpoint.cpp b/llarp/exit/endpoint.cpp index 68fdf5d77..78fb8b44a 100644 --- a/llarp/exit/endpoint.cpp +++ b/llarp/exit/endpoint.cpp @@ -8,7 +8,7 @@ namespace llarp { Endpoint::Endpoint(const llarp::PubKey& remoteIdent, const llarp::PathID_t& beginPath, bool rewriteIP, - huint32_t ip, llarp::handlers::ExitEndpoint* parent) + huint128_t ip, llarp::handlers::ExitEndpoint* parent) : createdAt(parent->Now()) , m_Parent(parent) , m_remoteSignKey(remoteIdent) @@ -108,16 +108,16 @@ namespace llarp if(m_UpstreamQueue.size() > MaxUpstreamQueueSize) return false; - llarp::net::IPv4Packet pkt; + llarp::net::IPPacket pkt; if(!pkt.Load(buf.underlying)) return false; huint32_t dst; if(m_RewriteSource) - dst = m_Parent->GetIfAddr(); + dst = net::IPPacket::TruncateV6(m_Parent->GetIfAddr()); else - dst = pkt.dst(); - pkt.UpdateIPv4PacketOnDst(m_IP, dst); + dst = pkt.dstv4(); + pkt.UpdateV4Address(net::IPPacket::TruncateV6(m_IP), dst); m_UpstreamQueue.emplace(pkt, counter); m_TxRate += buf.underlying.sz; m_LastActive = m_Parent->Now(); @@ -127,16 +127,16 @@ namespace llarp bool Endpoint::QueueInboundTraffic(ManagedBuffer buf) { - llarp::net::IPv4Packet pkt; + llarp::net::IPPacket pkt; if(!pkt.Load(buf.underlying)) return false; - huint32_t src; + huint128_t src; if(m_RewriteSource) src = m_Parent->GetIfAddr(); else - src = pkt.src(); - pkt.UpdateIPv4PacketOnDst(src, m_IP); + src = pkt.srcv6(); + pkt.UpdateV6Address(src, m_IP); const llarp_buffer_t& pktbuf = pkt.Buffer(); // life time extension const uint8_t queue_idx = pktbuf.sz / llarp::routing::ExitPadSize; if(m_DownstreamQueues.find(queue_idx) == m_DownstreamQueues.end()) diff --git a/llarp/exit/endpoint.hpp b/llarp/exit/endpoint.hpp index 309d0da96..d72da1ea6 100644 --- a/llarp/exit/endpoint.hpp +++ b/llarp/exit/endpoint.hpp @@ -24,7 +24,7 @@ namespace llarp static constexpr size_t MaxUpstreamQueueSize = 256; Endpoint(const llarp::PubKey& remoteIdent, - const llarp::PathID_t& beginPath, bool rewriteIP, huint32_t ip, + const llarp::PathID_t& beginPath, bool rewriteIP, huint128_t ip, llarp::handlers::ExitEndpoint* parent); ~Endpoint(); @@ -97,7 +97,7 @@ namespace llarp return m_RxRate; } - huint32_t + huint128_t LocalIP() const { return m_IP; @@ -109,7 +109,7 @@ namespace llarp llarp::handlers::ExitEndpoint* m_Parent; llarp::PubKey m_remoteSignKey; llarp::PathID_t m_CurrentPath; - llarp::huint32_t m_IP; + llarp::huint128_t m_IP; uint64_t m_TxRate, m_RxRate; llarp_time_t m_LastActive; bool m_RewriteSource; @@ -121,12 +121,12 @@ namespace llarp struct UpstreamBuffer { - UpstreamBuffer(const llarp::net::IPv4Packet& p, uint64_t c) + UpstreamBuffer(const llarp::net::IPPacket& p, uint64_t c) : pkt(p), counter(c) { } - llarp::net::IPv4Packet pkt; + llarp::net::IPPacket pkt; uint64_t counter; bool diff --git a/llarp/exit/session.cpp b/llarp/exit/session.cpp index 6c532baad..821ce14a5 100644 --- a/llarp/exit/session.cpp +++ b/llarp/exit/session.cpp @@ -199,7 +199,7 @@ namespace llarp { if(m_WritePacket) { - llarp::net::IPv4Packet pkt; + llarp::net::IPPacket pkt; if(!pkt.Load(buf)) return false; m_Downstream.emplace(counter, pkt); @@ -221,8 +221,7 @@ namespace llarp } bool - BaseSession::QueueUpstreamTraffic(llarp::net::IPv4Packet pkt, - const size_t N) + BaseSession::QueueUpstreamTraffic(llarp::net::IPPacket pkt, const size_t N) { const llarp_buffer_t& buf = pkt.Buffer(); auto& queue = m_Upstream[buf.sz / N]; diff --git a/llarp/exit/session.hpp b/llarp/exit/session.hpp index c24f9d55d..f37998604 100644 --- a/llarp/exit/session.hpp +++ b/llarp/exit/session.hpp @@ -74,7 +74,7 @@ namespace llarp HandlePathBuilt(llarp::path::Path_ptr p) override; bool - QueueUpstreamTraffic(llarp::net::IPv4Packet pkt, const size_t packSize); + QueueUpstreamTraffic(llarp::net::IPPacket pkt, const size_t packSize); /// flush upstream to exit via paths bool @@ -139,7 +139,7 @@ namespace llarp using TieredQueue_t = std::map< uint8_t, UpstreamTrafficQueue_t >; TieredQueue_t m_Upstream; - using DownstreamPkt = std::pair< uint64_t, llarp::net::IPv4Packet >; + using DownstreamPkt = std::pair< uint64_t, llarp::net::IPPacket >; struct DownstreamPktSorter { diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 394f74187..371b88930 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -68,7 +68,7 @@ namespace llarp huint32_t ip; if(!dns::DecodePTR(msg.questions[0].qname, ip)) return false; - return m_OurRange.Contains(ip); + return m_OurRange.ContainsV4(ip); } else if(msg.questions[0].qtype == dns::qTypeA || msg.questions[0].qtype == dns::qTypeCNAME @@ -91,14 +91,15 @@ namespace llarp huint32_t ip; if(!dns::DecodePTR(msg.questions[0].qname, ip)) return false; - if(ip == m_IfAddr) + huint128_t ipv6 = net::IPPacket::ExpandV4(ip); + if(ipv6 == m_IfAddr) { RouterID us = GetRouter()->pubkey(); msg.AddAReply(us.ToString(), 300); } else { - auto itr = m_IPToKey.find(ip); + auto itr = m_IPToKey.find(ipv6); if(itr != m_IPToKey.end() && m_SNodeKeys.find(itr->second) != m_SNodeKeys.end()) { @@ -155,7 +156,7 @@ namespace llarp RouterID r; if(r.FromString(msg.questions[0].Name())) { - huint32_t ip; + huint128_t ip; PubKey pubKey(r); if(m_SNodeKeys.find(pubKey) == m_SNodeKeys.end()) { @@ -212,11 +213,12 @@ namespace llarp m_InetToNetwork.Process([&](Pkt_t &pkt) { PubKey pk; { - auto itr = m_IPToKey.find(pkt.dst()); + auto itr = m_IPToKey.find(pkt.dstv6()); if(itr == m_IPToKey.end()) { // drop - LogWarn(Name(), " dropping packet, has no session at ", pkt.dst()); + LogWarn(Name(), " dropping packet, has no session at ", + pkt.dstv4()); return; } pk = itr->second; @@ -285,10 +287,10 @@ namespace llarp { // map our address const PubKey us(m_Router->pubkey()); - const huint32_t ip = GetIfAddr(); - m_KeyToIP[us] = ip; - m_IPToKey[ip] = us; - m_IPActivity[ip] = std::numeric_limits< llarp_time_t >::max(); + const huint128_t ip = GetIfAddr(); + m_KeyToIP[us] = ip; + m_IPToKey[ip] = us; + m_IPActivity[ip] = std::numeric_limits< llarp_time_t >::max(); m_SNodeKeys.insert(us); if(m_ShouldInitTun) { @@ -311,7 +313,7 @@ namespace llarp return m_Router; } - huint32_t + huint128_t ExitEndpoint::GetIfAddr() const { return m_IfAddr; @@ -340,10 +342,10 @@ namespace llarp return m_KeyToIP.find(pk) != m_KeyToIP.end(); } - huint32_t + huint128_t ExitEndpoint::GetIPForIdent(const PubKey pk) { - huint32_t found = {0}; + huint128_t found = {0}; if(!HasLocalMappedAddrFor(pk)) { // allocate and map @@ -372,14 +374,14 @@ namespace llarp return found; } - huint32_t + huint128_t ExitEndpoint::AllocateNewAddress() { if(m_NextAddr < m_HigestAddr) return ++m_NextAddr; // find oldest activity ip address - huint32_t found = {0}; + huint128_t found = {0}; llarp_time_t min = std::numeric_limits< llarp_time_t >::max(); auto itr = m_IPActivity.begin(); while(itr != m_IPActivity.end()) @@ -409,7 +411,7 @@ namespace llarp ExitEndpoint::KickIdentOffExit(const PubKey &pk) { LogInfo(Name(), " kicking ", pk, " off exit"); - huint32_t ip = m_KeyToIP[pk]; + huint128_t ip = m_KeyToIP[pk]; m_KeyToIP.erase(pk); m_IPToKey.erase(ip); auto range = m_ActiveExits.equal_range(pk); @@ -419,7 +421,7 @@ namespace llarp } void - ExitEndpoint::MarkIPActive(huint32_t ip) + ExitEndpoint::MarkIPActive(huint128_t ip) { m_IPActivity[ip] = GetRouter()->Now(); } @@ -432,13 +434,13 @@ namespace llarp } bool - ExitEndpoint::QueueSNodePacket(const llarp_buffer_t &buf, huint32_t from) + ExitEndpoint::QueueSNodePacket(const llarp_buffer_t &buf, huint128_t from) { - net::IPv4Packet pkt; + net::IPPacket pkt; if(!pkt.Load(buf)) return false; // rewrite ip - pkt.UpdateIPv4PacketOnDst(from, m_IfAddr); + pkt.UpdateV6Address(from, m_IfAddr); return llarp_ev_tun_async_write(&m_Tun, pkt.Buffer()); } @@ -529,12 +531,19 @@ namespace llarp strncpy(m_Tun.ifaddr, host_str.c_str(), sizeof(m_Tun.ifaddr) - 1); m_Tun.netmask = std::atoi(nmask_str.c_str()); - Addr ifaddr(host_str); - m_IfAddr = ifaddr.xtohl(); - m_OurRange.netmask_bits = netmask_ipv4_bits(m_Tun.netmask); - m_OurRange.addr = m_IfAddr; - m_NextAddr = m_IfAddr; - m_HigestAddr = m_IfAddr | (~m_OurRange.netmask_bits); + huint32_t ip; + if(ip.FromString(host_str)) + { + m_IfAddr = net::IPPacket::ExpandV4(ip); + m_OurRange.netmask_bits = netmask_ipv6_bits(m_Tun.netmask + 96); + } + else if(m_IfAddr.FromString(host_str)) + { + m_OurRange.netmask_bits = netmask_ipv6_bits(m_Tun.netmask); + } + m_OurRange.addr = m_IfAddr; + m_NextAddr = m_IfAddr; + m_HigestAddr = m_IfAddr | (~m_OurRange.netmask_bits); LogInfo(Name(), " set ifaddr range to ", m_Tun.ifaddr, "/", m_Tun.netmask, " lo=", m_IfAddr, " hi=", m_HigestAddr); } @@ -564,7 +573,7 @@ namespace llarp return true; } - huint32_t + huint128_t ExitEndpoint::ObtainServiceNodeIP(const RouterID &other) { const PubKey pubKey(other); @@ -573,7 +582,7 @@ namespace llarp if(pubKey == us) return m_IfAddr; - huint32_t ip = GetIPForIdent(pubKey); + huint128_t ip = GetIPForIdent(pubKey); if(m_SNodeKeys.emplace(pubKey).second) { auto session = std::make_shared< exit::SNodeSession >( @@ -593,7 +602,7 @@ namespace llarp { if(wantInternet && !m_PermitExit) return false; - huint32_t ip = GetIPForIdent(pk); + auto ip = GetIPForIdent(pk); if(GetRouter()->pathContext().TransitHopPreviousIsRouter(path, pk.as_array())) { diff --git a/llarp/handlers/exit.hpp b/llarp/handlers/exit.hpp index 90e320515..461a406aa 100644 --- a/llarp/handlers/exit.hpp +++ b/llarp/handlers/exit.hpp @@ -99,29 +99,29 @@ namespace llarp bool HasLocalMappedAddrFor(const PubKey& pk) const; - huint32_t + huint128_t GetIfAddr() const; void Flush(); private: - huint32_t + huint128_t GetIPForIdent(const PubKey pk); - huint32_t + huint128_t AllocateNewAddress(); /// obtain ip for service node session, creates a new session if one does /// not existing already - huint32_t + huint128_t ObtainServiceNodeIP(const RouterID& router); bool - QueueSNodePacket(const llarp_buffer_t& buf, huint32_t from); + QueueSNodePacket(const llarp_buffer_t& buf, huint128_t from); void - MarkIPActive(huint32_t ip); + MarkIPActive(huint128_t ip); void KickIdentOffExit(const PubKey& pk); @@ -139,7 +139,7 @@ namespace llarp PubKey::Hash > m_ActiveExits; - using KeyMap_t = std::unordered_map< PubKey, huint32_t, PubKey::Hash >; + using KeyMap_t = std::unordered_map< PubKey, huint128_t, PubKey::Hash >; KeyMap_t m_KeyToIP; @@ -153,14 +153,15 @@ namespace llarp /// snode sessions we are talking to directly SNodeSessions_t m_SNodeSessions; - std::unordered_map< huint32_t, PubKey, huint32_t::Hash > m_IPToKey; + std::unordered_map< huint128_t, PubKey, huint128_t::Hash > m_IPToKey; - huint32_t m_IfAddr; - huint32_t m_HigestAddr; - huint32_t m_NextAddr; + huint128_t m_IfAddr; + huint128_t m_HigestAddr; + + huint128_t m_NextAddr; IPRange m_OurRange; - std::unordered_map< huint32_t, llarp_time_t, huint32_t::Hash > + std::unordered_map< huint128_t, llarp_time_t, huint128_t::Hash > m_IPActivity; llarp_tun_io m_Tun; @@ -168,7 +169,7 @@ namespace llarp Addr m_LocalResolverAddr; std::vector< Addr > m_UpstreamResolvers; - using Pkt_t = net::IPv4Packet; + using Pkt_t = net::IPPacket; using PacketQueue_t = util::CoDelQueue< Pkt_t, Pkt_t::GetTime, Pkt_t::PutTime, Pkt_t::CompareOrder, Pkt_t::GetNow, util::NullMutex, diff --git a/llarp/handlers/null.hpp b/llarp/handlers/null.hpp index 98cbf00e4..fb71eea3a 100644 --- a/llarp/handlers/null.hpp +++ b/llarp/handlers/null.hpp @@ -19,7 +19,7 @@ namespace llarp bool HandleWriteIPPacket(const llarp_buffer_t &, - std::function< huint32_t(void) >) override + std::function< huint128_t(void) >) override { return true; } @@ -30,7 +30,13 @@ namespace llarp return shared_from_this(); } - huint32_t + bool + SupportsV6() const override + { + return false; + } + + huint128_t ObtainIPForAddr(const AlignedBuffer< 32 > &, bool) override { return {0}; diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index a70b6117b..c63392269 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -200,13 +200,22 @@ namespace llarp return false; } auto ip_str = v.substr(pos + 1); - in_addr ip; - if(inet_pton(AF_INET, ip_str.c_str(), &ip) != 1) + huint32_t ip; + huint128_t ipv6; + if(ip.FromString(ip_str)) { - llarp::LogError("cannot map to invalid ip ", ip_str); + ipv6 = net::IPPacket::ExpandV4(ip); + } + else if(ipv6.FromString(ip_str)) + { + } + else + { + llarp::LogError(Name(), "failed to map ", ip_str, + " failed to parse IP"); return false; } - return MapAddress(addr, huint32_t{ntohl(ip.s_addr)}, false); + return MapAddress(addr, ipv6, false); } if(k == "ifname") { @@ -222,6 +231,7 @@ namespace llarp if(k == "ifaddr") { std::string addr; + m_UseV6 = addr.find(":") != std::string::npos; auto pos = v.find("/"); if(pos != std::string::npos) { @@ -245,8 +255,11 @@ namespace llarp } else { - tunif.netmask = 32; - addr = v; + if(m_UseV6) + tunif.netmask = 128; + else + tunif.netmask = 32; + addr = v; } llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ", tunif.netmask); @@ -257,17 +270,16 @@ namespace llarp } bool - TunEndpoint::HasLocalIP(const huint32_t &ip) const + TunEndpoint::HasLocalIP(const huint128_t &ip) const { return m_IPToAddr.find(ip) != m_IPToAddr.end(); } bool - TunEndpoint::QueueOutboundTraffic(llarp::net::IPv4Packet &&pkt) + TunEndpoint::QueueOutboundTraffic(llarp::net::IPPacket &&pkt) { return m_NetworkToUserPktQueue.EmplaceIf( - [](llarp::net::IPv4Packet &) -> bool { return true; }, - std::move(pkt)); + [](llarp::net::IPPacket &) -> bool { return true; }, std::move(pkt)); } void @@ -354,7 +366,8 @@ namespace llarp else if(msg.questions[0].qtype == dns::qTypeA || msg.questions[0].qtype == dns::qTypeAAAA) { - const bool isV6 = msg.questions[0].qtype == dns::qTypeAAAA; + const bool isV6 = msg.questions[0].qtype == dns::qTypeAAAA && SupportsV6(); + const bool isV4 = msg.questions[0].qtype == dns::qTypeA; llarp::service::Address addr; // on MacOS this is a typeA query if(is_random_snode(msg)) @@ -371,7 +384,7 @@ namespace llarp context->ForEachService( [&](const std::string &, const std::shared_ptr< service::Endpoint > &service) -> bool { - huint32_t ip = service->GetIfAddr(); + huint128_t ip = service->GetIfAddr(); if(ip.h) { msg.AddINReply(ip, isV6); @@ -384,10 +397,14 @@ namespace llarp } else if(addr.FromString(qname, ".loki")) { - if(HasAddress(addr)) + if(isV4 && SupportsV6()) { - huint32_t ip = ObtainIPForAddr(addr, false); - msg.AddINReply(ip, isV6); + msg.AddNXReply(); + } + else if(HasAddress(addr)) + { + huint128_t ip = ObtainIPForAddr(addr, false); + msg.AddINReply(ip, isV6); } else { @@ -397,7 +414,7 @@ namespace llarp return EnsurePathToService( addr, [=](const Address &, OutboundContext *ctx) { - SendDNSReply(addr, ctx, replyMsg, reply, false, isV6); + SendDNSReply(addr, ctx, replyMsg, reply, false, isV6 || !isV4); }, 2000); } @@ -419,22 +436,24 @@ namespace llarp else if(msg.questions[0].qtype == dns::qTypePTR) { // reverse dns - huint32_t ip = {0}; + huint128_t ipv6 = {0}; + huint32_t ip = {0}; if(!dns::DecodePTR(msg.questions[0].qname, ip)) { msg.AddNXReply(); reply(msg); return true; } + ipv6 = net::IPPacket::ExpandV4(ip); llarp::service::Address addr( - ObtainAddrForIP< llarp::service::Address >(ip, true)); + ObtainAddrForIP< llarp::service::Address >(ipv6, true)); if(!addr.IsZero()) { msg.AddAReply(addr.ToString(".snode")); reply(msg); return true; } - addr = ObtainAddrForIP< llarp::service::Address >(ip, false); + addr = ObtainAddrForIP< llarp::service::Address >(ipv6, false); if(!addr.IsZero()) { msg.AddAReply(addr.ToString(".loki")); @@ -461,6 +480,12 @@ namespace llarp m_Exit->ResetInternalState(); } + bool + TunEndpoint::SupportsV6() const + { + return m_UseV6; + } + // FIXME: pass in which question it should be addressing bool TunEndpoint::ShouldHookDNSMessage(const dns::Message &msg) const @@ -480,20 +505,19 @@ namespace llarp huint32_t ip = {0}; if(!dns::DecodePTR(msg.questions[0].qname, ip)) return false; - return m_OurRange.Contains(ip); + return m_OurRange.ContainsV4(ip); } } return false; } bool - TunEndpoint::MapAddress(const service::Address &addr, huint32_t ip, + TunEndpoint::MapAddress(const service::Address &addr, huint128_t ip, bool SNode) { auto itr = m_IPToAddr.find(ip); if(itr != m_IPToAddr.end()) { - // XXX is calling inet_ntoa safe in this context? it's MP-unsafe llarp::LogWarn(ip, " already mapped to ", service::Address(itr->second.as_array()).ToString()); return false; @@ -572,31 +596,44 @@ namespace llarp */ if(res->ai_family == AF_INET6) { - llarp::LogError(Name(), - " failed to set up tun interface, we don't support " - "IPv6 format"); - return false; + m_UseV6 = true; } - freeaddrinfo(res); - struct in_addr addr; // network byte order - if(inet_aton(tunif.ifaddr, &addr) == 0) + freeaddrinfo(res); + if(m_UseV6) { - llarp::LogError(Name(), " failed to set up tun interface, cant parse ", - tunif.ifaddr); - return false; + llarp::LogInfo(Name(), " using IPV6"); + } + else + { + struct in_addr addr; // network byte order + if(inet_aton(tunif.ifaddr, &addr) == 0) + { + llarp::LogError(Name(), + " failed to set up tun interface, cant parse ", + tunif.ifaddr); + return false; + } + } + huint32_t ip; + if(ip.FromString(tunif.ifaddr)) + { + m_OurIP = net::IPPacket::ExpandV4(ip); + m_OurRange.netmask_bits = netmask_ipv6_bits(tunif.netmask + 96); + } + else if(m_OurIP.FromString(tunif.ifaddr)) + { + m_OurRange.netmask_bits = netmask_ipv6_bits(tunif.netmask); } - llarp::Addr lAddr(tunif.ifaddr); - - m_OurIP = lAddr.xtohl(); - m_NextIP = m_OurIP; - m_OurRange.netmask_bits = netmask_ipv4_bits(tunif.netmask); - m_OurRange.addr = m_OurIP; - m_MaxIP = m_OurIP | (~m_OurRange.netmask_bits); - llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ", lAddr); + m_NextIP = m_OurIP; + m_OurRange.addr = m_OurIP; + m_MaxIP = m_OurIP | (~m_OurRange.netmask_bits); + llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ", + m_OurIP); llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ", m_OurRange); + MapAddress(m_Identity.pub.Addr(), m_OurIP, IsSNode()); if(m_OnUp) { @@ -661,20 +698,30 @@ namespace llarp void TunEndpoint::FlushSend() { - m_UserToNetworkPktQueue.Process([&](net::IPv4Packet &pkt) { + m_UserToNetworkPktQueue.Process([&](net::IPPacket &pkt) { std::function< bool(const llarp_buffer_t &) > sendFunc; - auto itr = m_IPToAddr.find(pkt.dst()); + + huint128_t dst; + if(pkt.IsV4()) + dst = net::IPPacket::ExpandV4(pkt.dstv4()); + else + dst = pkt.dstv6(); + + auto itr = m_IPToAddr.find(dst); if(itr == m_IPToAddr.end()) { - if(m_Exit && !llarp::IsIPv4Bogon(pkt.dst())) + if(m_Exit && pkt.IsV4() && !llarp::IsIPv4Bogon(pkt.dstv4())) { - pkt.UpdateIPv4PacketOnDst({0}, pkt.dst()); + pkt.UpdateV4Address({0}, pkt.dstv4()); m_Exit->QueueUpstreamTraffic(std::move(pkt), llarp::routing::ExitPadSize); } else - llarp::LogWarn(Name(), " has no endpoint for ", pkt.dst()); - return true; + { + llarp::LogWarn(Name(), " has no endpoint for ", dst); + llarp::DumpBuffer(pkt.ConstBuffer()); + } + return; } if(m_SNodes.at(itr->second)) @@ -684,25 +731,26 @@ namespace llarp } else { - sendFunc = - std::bind(&TunEndpoint::SendToServiceOrQueue, this, - service::Address(itr->second.as_array()), - std::placeholders::_1, service::eProtocolTraffic); + sendFunc = std::bind(&TunEndpoint::SendToServiceOrQueue, this, + service::Address(itr->second.as_array()), + std::placeholders::_1, pkt.ServiceProtocol()); } // prepare packet for insertion into network // this includes clearing IP addresses, recalculating checksums, etc - pkt.UpdateIPv4PacketOnSrc(); + if(pkt.IsV4()) + pkt.UpdateV4Address({0}, {0}); + else + pkt.UpdateV6Address({0}, {0}); if(sendFunc && sendFunc(pkt.Buffer())) - return true; + return; llarp::LogWarn(Name(), " did not flush packets"); - return true; }); } bool - TunEndpoint::HandleWriteIPPacket(const llarp_buffer_t &b, - std::function< huint32_t(void) > getFromIP) + TunEndpoint::HandleWriteIPPacket( + const llarp_buffer_t &b, std::function< huint128_t(void) > getFromIP) { // llarp::LogInfo("got packet from ", msg->sender.Addr()); auto themIP = getFromIP(); @@ -710,7 +758,7 @@ namespace llarp auto usIP = m_OurIP; ManagedBuffer buf(b); return m_NetworkToUserPktQueue.EmplaceIf( - [buf, themIP, usIP](net::IPv4Packet &pkt) -> bool { + [buf, themIP, usIP](net::IPPacket &pkt) -> bool { // load if(!pkt.Load(buf)) return false; @@ -720,32 +768,39 @@ namespace llarp // - packets with weird src/dst addresses // (0.0.0.0/8 but not 0.0.0.0) // - packets with 0 src but non-0 dst and oposite - auto hdr = pkt.Header(); - if(pkt.sz < sizeof(*hdr) || hdr->version != 4 - || (hdr->saddr != 0 && *(byte_t *)&(hdr->saddr) == 0) - || (hdr->daddr != 0 && *(byte_t *)&(hdr->daddr) == 0) - || ((hdr->saddr == 0) != (hdr->daddr == 0))) + if(pkt.IsV4()) { - return false; + auto hdr = pkt.Header(); + if(pkt.sz < sizeof(*hdr) + || (hdr->saddr != 0 && *(byte_t *)&(hdr->saddr) == 0) + || (hdr->daddr != 0 && *(byte_t *)&(hdr->daddr) == 0) + || ((hdr->saddr == 0) != (hdr->daddr == 0))) + { + return false; + } + pkt.UpdateV4Address(net::IPPacket::TruncateV6(themIP), net::IPPacket::TruncateV6(usIP)); + } + else if(pkt.IsV6()) + { + if(pkt.srcv6() != huint128_t{0} || pkt.dstv6() != huint128_t{0}) + return false; + pkt.UpdateV6Address(themIP, usIP); } - - // update packet to use proper addresses, recalc checksums - pkt.UpdateIPv4PacketOnDst(themIP, usIP); return true; }); } - huint32_t + huint128_t TunEndpoint::GetIfAddr() const { return m_OurIP; } - huint32_t + huint128_t TunEndpoint::ObtainIPForAddr(const AlignedBuffer< 32 > &addr, bool snode) { - llarp_time_t now = Now(); - huint32_t nextIP = {0}; + llarp_time_t now = Now(); + huint128_t nextIP = {0}; AlignedBuffer< 32 > ident(addr); { // previously allocated address @@ -779,7 +834,7 @@ namespace llarp // we are full // expire least active ip // TODO: prevent DoS - std::pair< huint32_t, llarp_time_t > oldest = {huint32_t{0}, 0}; + std::pair< huint128_t, llarp_time_t > oldest = {huint128_t{0}, 0}; // find oldest entry auto itr = m_IPActivity.begin(); @@ -808,19 +863,20 @@ namespace llarp } bool - TunEndpoint::HasRemoteForIP(huint32_t ip) const + TunEndpoint::HasRemoteForIP(huint128_t ip) const { return m_IPToAddr.find(ip) != m_IPToAddr.end(); } void - TunEndpoint::MarkIPActive(huint32_t ip) + TunEndpoint::MarkIPActive(huint128_t ip) { + llarp::LogDebug(Name(), " address " , ip, " is active"); m_IPActivity[ip] = std::max(Now(), m_IPActivity[ip]); } void - TunEndpoint::MarkIPActiveForever(huint32_t ip) + TunEndpoint::MarkIPActiveForever(huint128_t ip) { m_IPActivity[ip] = std::numeric_limits< uint64_t >::max(); } @@ -844,7 +900,7 @@ namespace llarp self->m_Exit->FlushDownstream(); } // flush network to user - self->m_NetworkToUserPktQueue.Process([tun](net::IPv4Packet &pkt) { + self->m_NetworkToUserPktQueue.Process([tun](net::IPPacket &pkt) { if(!llarp_ev_tun_async_write(tun, pkt.Buffer())) llarp::LogWarn("packet dropped"); }); @@ -857,9 +913,7 @@ namespace llarp TunEndpoint *self = static_cast< TunEndpoint * >(tun->user); ManagedBuffer buf(b); if(!self->m_UserToNetworkPktQueue.EmplaceIf( - [buf](net::IPv4Packet &pkt) -> bool { - return pkt.Load(buf) && pkt.Header()->version == 4; - })) + [buf](net::IPPacket &pkt) -> bool { return pkt.Load(buf); })) { #if defined(DEBUG) || !defined(RELEASE_MOTTO) llarp::LogInfo("invalid pkt"); diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp index c81abb537..48d462b50 100644 --- a/llarp/handlers/tun.hpp +++ b/llarp/handlers/tun.hpp @@ -46,6 +46,9 @@ namespace llarp std::unordered_map< std::string, std::string > NotifyParams() const override; + bool + SupportsV6() const override; + bool ShouldHookDNSMessage(const dns::Message& msg) const override; @@ -58,7 +61,7 @@ namespace llarp TickTun(llarp_time_t now); bool - MapAddress(const service::Address& remote, huint32_t ip, bool SNode); + MapAddress(const service::Address& remote, huint128_t ip, bool SNode); bool Start() override; @@ -81,11 +84,11 @@ namespace llarp /// handle inbound traffic bool HandleWriteIPPacket(const llarp_buffer_t& buf, - std::function< huint32_t(void) > getFromIP) override; + std::function< huint128_t(void) > getFromIP) override; /// queue outbound packet to the world bool - QueueOutboundTraffic(llarp::net::IPv4Packet&& pkt); + QueueOutboundTraffic(llarp::net::IPPacket&& pkt); /// we have a resolvable ip address bool @@ -95,11 +98,11 @@ namespace llarp } /// get the local interface's address - huint32_t + huint128_t GetIfAddr() const override; bool - HasLocalIP(const huint32_t& ip) const; + HasLocalIP(const huint128_t& ip) const; llarp_tun_io tunif; std::unique_ptr< llarp_fd_promise > Promise; @@ -124,7 +127,7 @@ namespace llarp /// get a key for ip address template < typename Addr > Addr - ObtainAddrForIP(huint32_t ip, bool isSNode) + ObtainAddrForIP(huint128_t ip, bool isSNode) { auto itr = m_IPToAddr.find(ip); if(itr == m_IPToAddr.end() || m_SNodes[itr->second] != isSNode) @@ -145,7 +148,7 @@ namespace llarp } /// get ip address for key unconditionally - huint32_t + huint128_t ObtainIPForAddr(const AlignedBuffer< 32 >& addr, bool serviceNode) override; @@ -158,33 +161,33 @@ namespace llarp protected: using PacketQueue_t = llarp::util::CoDelQueue< - net::IPv4Packet, net::IPv4Packet::GetTime, net::IPv4Packet::PutTime, - net::IPv4Packet::CompareOrder, net::IPv4Packet::GetNow >; + net::IPPacket, net::IPPacket::GetTime, net::IPPacket::PutTime, + net::IPPacket::CompareOrder, net::IPPacket::GetNow >; /// queue for sending packets over the network from us PacketQueue_t m_UserToNetworkPktQueue; /// queue for sending packets to user from network PacketQueue_t m_NetworkToUserPktQueue; /// return true if we have a remote loki address for this ip address bool - HasRemoteForIP(huint32_t ipv4) const; + HasRemoteForIP(huint128_t ipv4) const; /// mark this address as active void - MarkIPActive(huint32_t ip); + MarkIPActive(huint128_t ip); /// mark this address as active forever void - MarkIPActiveForever(huint32_t ip); + MarkIPActiveForever(huint128_t ip); /// flush ip packets virtual void FlushSend(); /// maps ip to key (host byte order) - std::unordered_map< huint32_t, AlignedBuffer< 32 >, huint32_t::Hash > + std::unordered_map< huint128_t, AlignedBuffer< 32 >, huint128_t::Hash > m_IPToAddr; /// maps key to ip (host byte order) - std::unordered_map< AlignedBuffer< 32 >, huint32_t, + std::unordered_map< AlignedBuffer< 32 >, huint128_t, AlignedBuffer< 32 >::Hash > m_AddrToIP; @@ -199,10 +202,29 @@ namespace llarp { ManagedBuffer copy{buf}; return m_NetworkToUserPktQueue.EmplaceIf( - [&](llarp::net::IPv4Packet& pkt) -> bool { + [&](llarp::net::IPPacket& pkt) -> bool { if(!pkt.Load(copy.underlying)) return false; - pkt.UpdateIPv4PacketOnDst(pkt.src(), m_OurIP); + if(SupportsV6()) + { + if(pkt.IsV4()) + { + pkt.UpdateV6Address(net::IPPacket::ExpandV4(pkt.srcv4()), + m_OurIP); + } + else + { + pkt.UpdateV6Address(pkt.srcv6(), m_OurIP); + } + } + else + { + if(pkt.IsV4()) + pkt.UpdateV4Address(pkt.srcv4(), + net::IPPacket::TruncateV6(m_OurIP)); + else + return false; + } return true; }); } @@ -215,7 +237,7 @@ namespace llarp { if(ctx) { - huint32_t ip = ObtainIPForAddr(addr, snode); + huint128_t ip = ObtainIPForAddr(addr, snode); query->AddINReply(ip, sendIPv6); } else @@ -233,14 +255,14 @@ namespace llarp std::shared_ptr< dns::Proxy > m_Resolver; /// maps ip address to timestamp last active - std::unordered_map< huint32_t, llarp_time_t, huint32_t::Hash > + std::unordered_map< huint128_t, llarp_time_t, huint128_t::Hash > m_IPActivity; /// our ip address (host byte order) - huint32_t m_OurIP; + huint128_t m_OurIP; /// next ip address to allocate (host byte order) - huint32_t m_NextIP; + huint128_t m_NextIP; /// highest ip address to allocate (host byte order) - huint32_t m_MaxIP; + huint128_t m_MaxIP; /// our ip range we are using llarp::IPRange m_OurRange; /// upstream dns resolver list @@ -249,6 +271,8 @@ namespace llarp llarp::Addr m_LocalResolverAddr; /// list of strict connect addresses for hooks std::vector< llarp::Addr > m_StrictConnectAddrs; + /// use v6? + bool m_UseV6; }; } // namespace handlers } // namespace llarp diff --git a/llarp/net/ip.cpp b/llarp/net/ip.cpp index 3f1fc1d92..06a17579e 100644 --- a/llarp/net/ip.cpp +++ b/llarp/net/ip.cpp @@ -15,8 +15,61 @@ namespace llarp { namespace net { + huint128_t + IPPacket::In6ToHUInt(in6_addr addr) + { +#if __BYTE_ORDER == __BIG_ENDIAN + return huint128_t{addr.s6_addr32[0]} + | (huint128_t{addr.s6_addr32[1]} << 32) + | (huint128_t{addr.s6_addr32[2]} << 64) + | (huint128_t{addr.s6_addr32[3]} << 96); +#else + return huint128_t{ntohl(addr.s6_addr32[3])} + | (huint128_t{ntohl(addr.s6_addr32[2])} << 32) + | (huint128_t{ntohl(addr.s6_addr32[1])} << 64) + | (huint128_t{ntohl(addr.s6_addr32[0])} << 96); +#endif + } + + in6_addr + IPPacket::HUIntToIn6(huint128_t x) + { + in6_addr addr; + auto i = ntoh128(x.h); + memcpy(&addr, &i, 16); + return addr; + } + + huint128_t + IPPacket::ExpandV4(huint32_t i) + { + huint128_t ff = {0xff}; + huint128_t expanded{i.h}; + return (ff << 40) | (ff << 32) | expanded; + } + + huint32_t + IPPacket::TruncateV6(huint128_t i) + { + huint32_t ret = {0}; + ret.h = (uint32_t)(i.h & (0x00000000ffffffffUL)); + return ret; + } + + huint128_t + IPPacket::srcv6() const + { + return In6ToHUInt(HeaderV6()->srcaddr); + } + + huint128_t + IPPacket::dstv6() const + { + return In6ToHUInt(HeaderV6()->dstaddr); + } + bool - IPv4Packet::Load(const llarp_buffer_t &pkt) + IPPacket::Load(const llarp_buffer_t &pkt) { if(pkt.sz > sizeof(buf)) return false; @@ -26,17 +79,37 @@ namespace llarp } llarp_buffer_t - IPv4Packet::ConstBuffer() const + IPPacket::ConstBuffer() const { return {buf, sz}; } llarp_buffer_t - IPv4Packet::Buffer() + IPPacket::Buffer() { return {buf, sz}; } + huint32_t + IPPacket::srcv4() const + { + return huint32_t{ntohl(Header()->saddr)}; + } + + huint32_t + IPPacket::dstv4() const + { + return huint32_t{ntohl(Header()->daddr)}; + } + + void + IPPacket::UpdateV6Address(huint128_t src, huint128_t dst) + { + auto hdr = HeaderV6(); + hdr->srcaddr = HUIntToIn6(src); + hdr->dstaddr = HUIntToIn6(dst); + } + #if 0 static uint32_t ipchksum_pseudoIPv4(nuint32_t src_ip, nuint32_t dst_ip, uint8_t proto, @@ -140,8 +213,9 @@ namespace llarp } void - IPv4Packet::UpdateIPv4PacketOnDst(huint32_t newSrcIP, huint32_t newDstIP) + IPPacket::UpdateV4Address(huint32_t newSrcIP, huint32_t newDstIP) { + llarp::LogDebug("set src=", newSrcIP, " dst=", newDstIP); auto hdr = Header(); auto oSrcIP = nuint32_t{hdr->saddr}; @@ -227,9 +301,9 @@ namespace llarp // if(check->n == 0x0000) // check->n = 0xFFff; } - + /* void - IPv4Packet::UpdateIPv4PacketOnSrc() + IPacket::UpdateIPv4PacketOnSrc() { auto hdr = Header(); @@ -269,5 +343,6 @@ namespace llarp hdr->saddr = 0; hdr->daddr = 0; } + */ } // namespace net } // namespace llarp diff --git a/llarp/net/ip.hpp b/llarp/net/ip.hpp index 270019f77..ed830a34d 100644 --- a/llarp/net/ip.hpp +++ b/llarp/net/ip.hpp @@ -74,7 +74,17 @@ typedef struct ip_hdr #endif +struct ipv6_header +{ + unsigned char version : 4; + unsigned char pad_small : 4; + uint8_t pad [7]; + in6_addr srcaddr; + in6_addr dstaddr; +}; + #include +#include struct llarp_ev_loop; @@ -82,28 +92,21 @@ namespace llarp { namespace net { - /// a network layer packet - struct NetPacket + /// an Packet + struct IPPacket { - virtual ~NetPacket(){}; + static huint128_t + In6ToHUInt(in6_addr addr); - virtual byte_t - Version() const = 0; + static in6_addr + HUIntToIn6(huint128_t x); - virtual byte_t - IPProto() const = 0; + static huint128_t + ExpandV4(huint32_t x); - virtual llarp_buffer_t - Buffer() = 0; - - virtual llarp_buffer_t - ConstBuffer() const = 0; - }; + static huint32_t + TruncateV6(huint128_t x); - /// an IPv4 Packet - /// TODO: make it implement NetPacket - struct IPv4Packet - { static constexpr size_t MaxSize = 1500; llarp_time_t timestamp; size_t sz; @@ -121,7 +124,7 @@ namespace llarp struct GetTime { llarp_time_t - operator()(const IPv4Packet& pkt) const + operator()(const IPPacket& pkt) const { return pkt.timestamp; } @@ -134,7 +137,7 @@ namespace llarp { } void - operator()(IPv4Packet& pkt) const + operator()(IPPacket& pkt) const { pkt.timestamp = llarp_ev_loop_time_now_ms(loop); } @@ -156,7 +159,7 @@ namespace llarp struct CompareSize { bool - operator()(const IPv4Packet& left, const IPv4Packet& right) + operator()(const IPPacket& left, const IPPacket& right) { return left.sz < right.sz; } @@ -165,7 +168,7 @@ namespace llarp struct CompareOrder { bool - operator()(const IPv4Packet& left, const IPv4Packet& right) + operator()(const IPPacket& left, const IPPacket& right) { return left.timestamp < right.timestamp; } @@ -183,37 +186,70 @@ namespace llarp return (ip_header*)&buf[0]; } - inline huint32_t - src() + inline ipv6_header* + HeaderV6() + { + return (ipv6_header*)&buf[0]; + } + + inline const ipv6_header* + HeaderV6() const { - return huint32_t{ntohl(Header()->saddr)}; + return (ipv6_header*)&buf[0]; } - inline huint32_t - dst() + inline int + Version() const { - return huint32_t{ntohl(Header()->daddr)}; + return Header()->version; } - inline void - src(huint32_t ip) + inline bool + IsV4() const { - Header()->saddr = htonl(ip.h); + return Version() == 4; } - inline void - dst(huint32_t ip) + inline bool + IsV6() const { - Header()->daddr = htonl(ip.h); + return Version() == 6; } - // update ip packet (after packet gets out of network) + inline service::ProtocolType + ServiceProtocol() const + { + if(IsV4()) + return service::eProtocolTrafficV4; + else if(IsV6()) + return service::eProtocolTrafficV6; + else + return service::eProtocolControl; + } + + huint128_t + srcv6() const; + + huint128_t + dstv6() const; + + huint32_t + srcv4() const; + + huint32_t + dstv4() const; + + huint128_t + src4to6() const; + + huint128_t + dst4to6() const; + void - UpdateIPv4PacketOnDst(huint32_t newSrcIP, huint32_t newDstIP); + UpdateV4Address(huint32_t src, huint32_t dst); - // update ip packet (before packet gets inserted into network) void - UpdateIPv4PacketOnSrc(); + UpdateV6Address(huint128_t src, huint128_t dst); }; } // namespace net diff --git a/llarp/net/net.cpp b/llarp/net/net.cpp index fd8792f3c..e03e40c12 100644 --- a/llarp/net/net.cpp +++ b/llarp/net/net.cpp @@ -13,6 +13,7 @@ #endif #include +#include #include #include @@ -1010,6 +1011,37 @@ namespace llarp return IsBogon(host); } + bool + IPRange::ContainsV4(const huint32_t& ip) const + { + return Contains(net::IPPacket::ExpandV4(ip)); + } + + std::string + IPRange::ToString() const + { + char buf[INET6_ADDRSTRLEN + 1] = {0}; + std::string str; + in6_addr inaddr; + size_t numset = 0; + absl::uint128 bits = netmask_bits.h; + while(bits) + { + if(bits & 1) + numset++; + bits >>= 1; + } + str += inet_ntop(AF_INET6, &inaddr, buf, sizeof(buf)); + return str + "/" + std::to_string(numset); + } + + IPRange + iprange_ipv4(byte_t a, byte_t b, byte_t c, byte_t d, byte_t mask) + { + return IPRange{net::IPPacket::ExpandV4(ipaddr_ipv4_bits(a, b, c, d)), + netmask_ipv6_bits(mask + 96)}; + } + bool IsIPv4Bogon(const huint32_t& addr) { @@ -1024,7 +1056,7 @@ namespace llarp iprange_ipv4(224, 0, 0, 0, 4), iprange_ipv4(240, 0, 0, 0, 4)}; for(const auto& bogon : bogonRanges) { - if(bogon.Contains(addr)) + if(bogon.ContainsV4(addr)) { #if defined(TESTNET) return false; diff --git a/llarp/net/net.hpp b/llarp/net/net.hpp index 20185dae5..b648c56fa 100644 --- a/llarp/net/net.hpp +++ b/llarp/net/net.hpp @@ -1,6 +1,7 @@ #ifndef LLARP_NET_HPP #define LLARP_NET_HPP +#include #include #include #include @@ -59,16 +60,19 @@ namespace llarp { struct IPRange { - huint32_t addr; - huint32_t netmask_bits; + huint128_t addr; + huint128_t netmask_bits; /// return true if ip is contained in this ip range bool - Contains(const huint32_t& ip) const + Contains(const huint128_t& ip) const { return (addr & netmask_bits) == (ip & netmask_bits); } + bool + ContainsV4(const huint32_t& ip) const; + friend std::ostream& operator<<(std::ostream& out, const IPRange& a) { @@ -76,13 +80,27 @@ namespace llarp } std::string - ToString() const - { - return addr.ToString() + "/" - + std::to_string(llarp::bits::count_bits(netmask_bits.h)); - } + ToString() const; }; + huint128_t + ExpandV4(huint32_t x); + + /// get a netmask with the higest numset bits set + constexpr huint128_t + __netmask_ipv6_bits(uint32_t numset) + { + return (128 - numset) + ? (huint128_t{1} << numset) | __netmask_ipv6_bits(numset + 1) + : huint128_t{0}; + } + + constexpr huint128_t + netmask_ipv6_bits(uint32_t numset) + { + return __netmask_ipv6_bits(128 - numset); + } + /// get a netmask with the higest numset bits set constexpr uint32_t __netmask_ipv4_bits(uint32_t numset) @@ -90,7 +108,7 @@ namespace llarp return (32 - numset) ? (1 << numset) | __netmask_ipv4_bits(numset + 1) : 0; } - /// get an ipv4 netmask given some /N range + /// get a netmask given some /N range constexpr huint32_t netmask_ipv4_bits(uint32_t num) { @@ -107,11 +125,8 @@ namespace llarp #endif } - constexpr IPRange - iprange_ipv4(byte_t a, byte_t b, byte_t c, byte_t d, byte_t mask) - { - return IPRange{ipaddr_ipv4_bits(a, b, c, d), netmask_ipv4_bits(mask)}; - } + IPRange + iprange_ipv4(byte_t a, byte_t b, byte_t c, byte_t d, byte_t mask); bool IsIPv4Bogon(const huint32_t& addr); diff --git a/llarp/net/net_int.cpp b/llarp/net/net_int.cpp index 478213f71..14ef2df1f 100644 --- a/llarp/net/net_int.cpp +++ b/llarp/net/net_int.cpp @@ -1,5 +1,5 @@ #include - +#include #include namespace llarp @@ -15,6 +15,15 @@ namespace llarp c[10] = 0xff; } + template <> + void + huint128_t::ToV6(V6Container& c) + { + c.resize(16); + const in6_addr addr = net::IPPacket::HUIntToIn6(*this); + std::copy_n(addr.s6_addr, 16, c.begin()); + } + template <> std::string huint32_t::ToString() const @@ -25,6 +34,40 @@ namespace llarp return ""; return tmp; } + + template <> + std::string + huint128_t::ToString() const + { + absl::uint128 addr = ntoh128(h); + char tmp[INET6_ADDRSTRLEN] = {0}; + if(!inet_ntop(AF_INET6, (void*)&addr, tmp, sizeof(tmp))) + return ""; + return tmp; + } + + template <> + bool + huint32_t::FromString(const std::string& str) + { + uint32_t n; + if(!inet_pton(AF_INET, str.c_str(), &n)) + return false; + h = ntohl(n); + return true; + } + + template <> + bool + huint128_t::FromString(const std::string& str) + { + absl::uint128 i; + if(!inet_pton(AF_INET6, str.c_str(), &i)) + return false; + h = ntoh128(i); + return true; + } + template <> std::string nuint32_t::ToString() const diff --git a/llarp/net/net_int.hpp b/llarp/net/net_int.hpp index deefc094a..fec386de1 100644 --- a/llarp/net/net_int.hpp +++ b/llarp/net/net_int.hpp @@ -19,6 +19,9 @@ #include #include +#include +#include + namespace llarp { template < typename UInt_t > @@ -28,25 +31,33 @@ namespace llarp constexpr huint_t operator&(huint_t x) const { - return huint_t{UInt_t(h & x.h)}; + return huint_t{UInt_t{h & x.h}}; } constexpr huint_t operator|(huint_t x) const { - return huint_t{UInt_t(h | x.h)}; + return huint_t{UInt_t{h | x.h}}; } constexpr huint_t operator^(huint_t x) const { - return huint_t{UInt_t(h ^ x.h)}; + return huint_t{UInt_t{h ^ x.h}}; } constexpr huint_t operator~() const { - return huint_t{UInt_t(~h)}; + return huint_t{UInt_t{~h}}; + } + + constexpr huint_t + operator<<(int n) const + { + UInt_t v{h}; + v <<= n; + return huint_t{v}; } inline huint_t @@ -69,20 +80,26 @@ namespace llarp return h < x.h; } + constexpr bool + operator!=(huint_t x) const + { + return h != x.h; + } + constexpr bool operator==(huint_t x) const { return h == x.h; } - struct Hash + using Hash = absl::Hash< huint_t< UInt_t > >; + + template < typename H > + friend H + AbslHashValue(H h, const huint_t< UInt_t >& i) { - inline size_t - operator()(huint_t x) const - { - return std::hash< UInt_t >{}(x.h); - } - }; + return H::combine(std::move(h), i.h); + } using V6Container = std::vector< uint8_t >; void @@ -91,6 +108,9 @@ namespace llarp std::string ToString() const; + bool + FromString(const std::string&); + friend std::ostream& operator<<(std::ostream& out, const huint_t& i) { @@ -98,8 +118,9 @@ namespace llarp } }; - using huint32_t = huint_t< uint32_t >; - using huint16_t = huint_t< uint16_t >; + using huint32_t = huint_t< uint32_t >; + using huint16_t = huint_t< uint16_t >; + using huint128_t = huint_t< absl::uint128 >; template < typename UInt_t > struct nuint_t @@ -177,8 +198,9 @@ namespace llarp } }; - using nuint32_t = nuint_t< uint32_t >; - using nuint16_t = nuint_t< uint16_t >; + using nuint32_t = nuint_t< uint32_t >; + using nuint16_t = nuint_t< uint16_t >; + using nuint128_t = nuint_t< absl::uint128 >; static inline nuint32_t xhtonl(huint32_t x) diff --git a/llarp/service/async_key_exchange.cpp b/llarp/service/async_key_exchange.cpp index 559064d27..c59b498aa 100644 --- a/llarp/service/async_key_exchange.cpp +++ b/llarp/service/async_key_exchange.cpp @@ -14,7 +14,8 @@ namespace llarp const Identity& localident, const PQPubKey& introsetPubKey, const Introduction& remote, - IDataHandler* h, const ConvoTag& t) + IDataHandler* h, const ConvoTag& t, + ProtocolType proto) : logic(l) , remote(r) , m_LocalIdentity(localident) @@ -23,6 +24,7 @@ namespace llarp , handler(h) , tag(t) { + msg.proto = proto; } void @@ -69,8 +71,6 @@ namespace llarp self->msg.sender = self->m_LocalIdentity.pub; // set version self->msg.version = LLARP_PROTO_VERSION; - // set protocol - self->msg.proto = eProtocolTraffic; // encrypt and sign if(self->frame.EncryptAndSign(self->msg, K, self->m_LocalIdentity)) self->logic->queue_job({self, &Result}); diff --git a/llarp/service/async_key_exchange.hpp b/llarp/service/async_key_exchange.hpp index 88138fa23..77d3d3e49 100644 --- a/llarp/service/async_key_exchange.hpp +++ b/llarp/service/async_key_exchange.hpp @@ -30,7 +30,7 @@ namespace llarp const Identity& localident, const PQPubKey& introsetPubKey, const Introduction& remote, IDataHandler* h, - const ConvoTag& t); + const ConvoTag& t, ProtocolType proto); static void Result(void* user); diff --git a/llarp/service/context.cpp b/llarp/service/context.cpp index 3c0d00a66..c595faef0 100644 --- a/llarp/service/context.cpp +++ b/llarp/service/context.cpp @@ -154,7 +154,7 @@ namespace llarp bool Context::FindBestAddressFor(const AlignedBuffer< 32 > &addr, bool isSNode, - huint32_t &ip) + huint128_t &ip) { auto itr = m_Endpoints.begin(); while(itr != m_Endpoints.end()) diff --git a/llarp/service/context.hpp b/llarp/service/context.hpp index 505649281..2c9ac57a9 100644 --- a/llarp/service/context.hpp +++ b/llarp/service/context.hpp @@ -33,7 +33,7 @@ namespace llarp bool FindBestAddressFor(const AlignedBuffer< 32 > &addr, bool isSNode, - huint32_t &); + huint128_t &); /// function visitor returns false to prematurely break iteration void diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index e8bb26f64..c55642a45 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -856,7 +856,7 @@ namespace llarp bool Endpoint::ProcessDataMessage(std::shared_ptr< ProtocolMessage > msg) { - if(msg->proto == eProtocolTraffic) + if(msg->proto == eProtocolTrafficV4 || msg->proto == eProtocolTrafficV6) { util::Lock l(&m_InboundTrafficQueueMutex); m_InboundTrafficQueue.emplace(msg); @@ -1009,7 +1009,7 @@ namespace llarp auto session = std::make_shared< exit::SNodeSession >( snode, std::bind(&Endpoint::HandleWriteIPPacket, this, _1, - [themIP]() -> huint32_t { return themIP; }), + [themIP]() -> huint128_t { return themIP; }), m_Router, m_NumPaths, numHops, false, ShouldBundleRC()); m_SNodeSessions.emplace(snode, session); } @@ -1033,7 +1033,7 @@ namespace llarp Endpoint::SendToSNodeOrQueue(const RouterID& addr, const llarp_buffer_t& buf) { - auto pkt = std::make_shared< net::IPv4Packet >(); + auto pkt = std::make_shared< net::IPPacket >(); if(!pkt->Load(buf)) return false; EnsurePathToSNode(addr, [pkt](RouterID, exit::BaseSession_ptr s) { @@ -1055,7 +1055,7 @@ namespace llarp { const auto& msg = m_InboundTrafficQueue.top(); llarp_buffer_t buf(msg->payload); - HandleWriteIPPacket(buf, [&]() -> huint32_t { + HandleWriteIPPacket(buf, [&]() -> huint128_t { return ObtainIPForAddr(msg->sender.Addr(), false); }); m_InboundTrafficQueue.pop(); diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 4416fb0d9..ca757e791 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -81,10 +81,10 @@ namespace llarp } /// get our ifaddr if it is set - virtual huint32_t + virtual huint128_t GetIfAddr() const { - return huint32_t{0}; + return huint128_t{0}; } virtual void @@ -151,7 +151,7 @@ namespace llarp HandleHiddenServiceFrame(path::Path_ptr p, const service::ProtocolFrame& msg); - virtual huint32_t + virtual huint128_t ObtainIPForAddr(const AlignedBuffer< 32 >& addr, bool serviceNode) = 0; virtual bool @@ -173,7 +173,7 @@ namespace llarp virtual bool HandleWriteIPPacket(const llarp_buffer_t& pkt, - std::function< huint32_t(void) > getFromIP) = 0; + std::function< huint128_t(void) > getFromIP) = 0; bool ProcessDataMessage(std::shared_ptr< ProtocolMessage > msg); @@ -313,6 +313,9 @@ namespace llarp /// parent context that owns this endpoint Context* const context; + virtual bool + SupportsV6() const = 0; + void RegenAndPublishIntroSet(llarp_time_t now, bool forceRebuild = false); diff --git a/llarp/service/outbound_context.cpp b/llarp/service/outbound_context.cpp index 49d4e2659..c9300073a 100644 --- a/llarp/service/outbound_context.cpp +++ b/llarp/service/outbound_context.cpp @@ -160,13 +160,12 @@ namespace llarp currentConvoTag.Randomize(); AsyncKeyExchange* ex = new AsyncKeyExchange( m_Endpoint->RouterLogic(), remoteIdent, m_Endpoint->GetIdentity(), - currentIntroSet.K, remoteIntro, m_DataHandler, currentConvoTag); + currentIntroSet.K, remoteIntro, m_DataHandler, currentConvoTag, t); ex->hook = std::bind(&OutboundContext::Send, this, std::placeholders::_1, path); ex->msg.PutBuffer(payload); - ex->msg.proto = t; ex->msg.introReply = path->intro; ex->frame.F = ex->msg.introReply.pathID; llarp_threadpool_queue_job(m_Endpoint->CryptoWorker(), diff --git a/llarp/service/protocol.hpp b/llarp/service/protocol.hpp index a150fd741..f7083b839 100644 --- a/llarp/service/protocol.hpp +++ b/llarp/service/protocol.hpp @@ -33,8 +33,9 @@ namespace llarp using ProtocolType = uint64_t; - constexpr ProtocolType eProtocolControl = 0UL; - constexpr ProtocolType eProtocolTraffic = 1UL; + constexpr ProtocolType eProtocolControl = 0UL; + constexpr ProtocolType eProtocolTrafficV4 = 1UL; + constexpr ProtocolType eProtocolTrafficV6 = 2UL; /// inner message struct ProtocolMessage @@ -42,7 +43,7 @@ namespace llarp ProtocolMessage(const ConvoTag& tag); ProtocolMessage(); ~ProtocolMessage(); - ProtocolType proto = eProtocolTraffic; + ProtocolType proto = eProtocolTrafficV4; llarp_time_t queued = 0; std::vector< byte_t > payload; Introduction introReply; diff --git a/llarp/util/bits.hpp b/llarp/util/bits.hpp index 876e9e79b..310650e23 100644 --- a/llarp/util/bits.hpp +++ b/llarp/util/bits.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace llarp { diff --git a/llarp/util/endian.hpp b/llarp/util/endian.hpp index fd859828a..39c86cd30 100644 --- a/llarp/util/endian.hpp +++ b/llarp/util/endian.hpp @@ -5,6 +5,7 @@ #include #include +#include #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include @@ -189,4 +190,19 @@ htole64buf(void *buf, uint64_t big64) htobuf64(buf, htole64(big64)); } +inline absl::uint128 +ntoh128(absl::uint128 i) +{ +#if __BYTE_ORDER == __BIG_ENDIAN + return i; +#else + uint64_t *ptr = (uint64_t *)&i; + absl::uint128 ret; + uint64_t *retptr = (uint64_t *)&ret; + htobe64buf(retptr, ptr[1]); + htobe64buf(retptr + 1, ptr[0]); + return ret; +#endif +} + #endif diff --git a/test/net/test_llarp_net.cpp b/test/net/test_llarp_net.cpp index fc54fcbc6..564ae524c 100644 --- a/test/net/test_llarp_net.cpp +++ b/test/net/test_llarp_net.cpp @@ -2,27 +2,63 @@ #include #include +#include +#include struct TestNet : public ::testing::Test { }; + +TEST_F(TestNet, TestIn6AddrFromString) +{ + llarp::huint128_t ip; + ASSERT_TRUE(ip.FromString("fc00::1")); +} + +TEST_F(TestNet, TestIn6AddrFromStringFail) +{ + llarp::huint128_t ip; + ASSERT_FALSE(ip.FromString("10.1.1.1")); +} + +TEST_F(TestNet, TestIn6AddrToHUIntLoopback) +{ + llarp::huint128_t loopback = {0}; + ASSERT_TRUE(loopback.FromString("::1")); + in6_addr addr = IN6ADDR_LOOPBACK_INIT; + auto huint = llarp::net::IPPacket::In6ToHUInt(addr); + ASSERT_EQ(huint, loopback); +} + +TEST_F(TestNet, TestIn6AddrToHUInt) +{ + llarp::huint128_t huint_parsed = {0}; + ASSERT_TRUE(huint_parsed.FromString("fd00::1")); + in6_addr addr = { { { 0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; + auto huint = llarp::net::IPPacket::In6ToHUInt(addr); + ASSERT_EQ(huint, huint_parsed); + huint_parsed.h ++; + ASSERT_NE(huint, huint_parsed); +} + + TEST_F(TestNet, TestRangeContains8) { ASSERT_TRUE(llarp::iprange_ipv4(10, 0, 0, 1, 8) - .Contains(llarp::ipaddr_ipv4_bits(10, 40, 11, 6))); + .ContainsV4(llarp::ipaddr_ipv4_bits(10, 40, 11, 6))); } TEST_F(TestNet, TestRangeContains24) { ASSERT_TRUE(llarp::iprange_ipv4(10, 200, 0, 1, 24) - .Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253))); + .ContainsV4(llarp::ipaddr_ipv4_bits(10, 200, 0, 253))); } TEST_F(TestNet, TestRangeContainsFail) { ASSERT_TRUE(!llarp::iprange_ipv4(192, 168, 0, 1, 24) - .Contains(llarp::ipaddr_ipv4_bits(10, 200, 0, 253))); + .ContainsV4(llarp::ipaddr_ipv4_bits(10, 200, 0, 253))); } TEST_F(TestNet, TestIPv4Netmask) diff --git a/vendor/libtuntap-master/tuntap-unix-linux.c b/vendor/libtuntap-master/tuntap-unix-linux.c index 7068355ea..946c0fa69 100644 --- a/vendor/libtuntap-master/tuntap-unix-linux.c +++ b/vendor/libtuntap-master/tuntap-unix-linux.c @@ -188,14 +188,50 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s4, uint32_t bits) return 0; } +struct in6_ifreq { + struct in6_addr ifr6_addr; + __u32 ifr6_prefixlen; + unsigned int ifr6_ifindex; +}; + + int tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s6, uint32_t bits) { - (void)dev; - (void)s6; - (void)bits; - tuntap_log(TUNTAP_LOG_NOTICE, "IPv6 is not implemented on your system"); - return -1; + struct ifreq ifr; + struct sockaddr_in6 sai; + int sockfd; + struct in6_ifreq ifr6; + + sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP); + if (sockfd == -1) { + return -1; + } + + /* get interface name */ + strncpy(ifr.ifr_name, dev->if_name, IFNAMSIZ); + + memset(&sai, 0, sizeof(struct sockaddr)); + sai.sin6_family = AF_INET6; + sai.sin6_port = 0; + + memcpy((char *) &ifr6.ifr6_addr, (char *) s6, +sizeof(struct in6_addr)); + + if (ioctl(sockfd, SIOGIFINDEX, &ifr) < 0) { + perror("SIOGIFINDEX"); + close(sockfd); + return -1; + } + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = bits; + if (ioctl(sockfd, SIOCSIFADDR, &ifr6) < 0) { + perror("SIOCSIFADDR"); + close(sockfd); + return -1; + } + close(sockfd); + return 0; } int diff --git a/vendor/libtuntap-master/tuntap.cpp b/vendor/libtuntap-master/tuntap.cpp index e0d73ceeb..dbff74c12 100644 --- a/vendor/libtuntap-master/tuntap.cpp +++ b/vendor/libtuntap-master/tuntap.cpp @@ -161,7 +161,7 @@ extern "C" llarp::LogError("invalid ipv6 address: ", addr); return -1; } - return tuntap_sys_set_ipv6(dev, &baddr6, mask); + return tuntap_sys_set_ipv6(dev, &baddr6, netmask); } else if(errval == -1) {