#ifndef LLARP_HANDLERS_TUN_HPP #define LLARP_HANDLERS_TUN_HPP #include #include #include #include #include #include #include #include #include namespace llarp { namespace handlers { struct TunEndpoint : public service::Endpoint, public dns::IQueryHandler, public std::enable_shared_from_this { TunEndpoint( AbstractRouter* r, llarp::service::Context* parent, bool lazyVPN = false); ~TunEndpoint() override; path::PathSet_ptr GetSelf() override { return shared_from_this(); } bool Configure(const NetworkConfig& conf, const DnsConfig& dnsConf) override; void Tick(llarp_time_t now) override; util::StatusObject ExtractStatus() const; std::unordered_map NotifyParams() const override; bool SupportsV6() const override; bool ShouldHookDNSMessage(const dns::Message& msg) const override; bool HandleHookedDNSMessage( dns::Message query, std::function sendreply) override; void TickTun(llarp_time_t now); static void tunifTick(llarp_tun_io*); bool MapAddress(const service::Address& remote, huint128_t ip, bool SNode); bool Start() override; bool Stop() override; bool IsSNode() const; /// set up tun interface, blocking bool SetupTun(); /// overrides Endpoint bool SetupNetworking() override; /// overrides Endpoint bool HandleInboundPacket( const service::ConvoTag tag, const llarp_buffer_t& pkt, service::ProtocolType t) override { if (t != service::eProtocolTrafficV4 && t != service::eProtocolTrafficV6) return false; AlignedBuffer<32> addr; bool snode = false; if (!GetEndpointWithConvoTag(tag, addr, snode)) return false; return HandleWriteIPPacket( pkt, [=]() -> huint128_t { return ObtainIPForAddr(addr, snode); }); } /// handle inbound traffic bool HandleWriteIPPacket(const llarp_buffer_t& buf, std::function getFromIP); /// queue outbound packet to the world bool QueueOutboundTraffic(llarp::net::IPPacket&& pkt); /// get the local interface's address huint128_t GetIfAddr() const override; /// we have an interface addr bool HasIfAddr() const override { return true; } bool HasLocalIP(const huint128_t& ip) const; std::unique_ptr tunif; llarp_vpn_io* vpnif = nullptr; bool InjectVPN(llarp_vpn_io* io, llarp_vpn_ifaddr_info info) override { if (tunif) return false; m_LazyVPNPromise.set_value(lazy_vpn{info, io}); return true; } /// called before writing to tun interface static void tunifBeforeWrite(llarp_tun_io* t); /// handle user to network send buffer flush /// called in router logic thread static void handleNetSend(void*); /// called every time we wish to read a packet from the tun interface static void tunifRecvPkt(llarp_tun_io* t, const llarp_buffer_t& buf); /// called in the endpoint logic thread static void handleTickTun(void* u); /// get a key for ip address template Addr_t ObtainAddrForIP(huint128_t ip, bool isSNode) { Addr_t addr; auto itr = m_IPToAddr.find(ip); if (itr != m_IPToAddr.end() and m_SNodes[itr->second] == isSNode) { addr = Addr_t(itr->second); } // found return addr; } template bool FindAddrForIP(Addr_t& addr, huint128_t ip); bool HasAddress(const AlignedBuffer<32>& addr) const { return m_AddrToIP.find(addr) != m_AddrToIP.end(); } /// get ip address for key unconditionally huint128_t ObtainIPForAddr(const AlignedBuffer<32>& addr, bool serviceNode); /// flush network traffic void Flush(); void ResetInternalState() override; protected: bool ShouldFlushNow(llarp_time_t now) const; llarp_time_t m_LastFlushAt = 0s; using PacketQueue_t = llarp::util::CoDelQueue< net::IPPacket, net::IPPacket::GetTime, net::IPPacket::PutTime, net::IPPacket::CompareOrder, net::IPPacket::GetNow>; /// queue packet for send on net thread from user std::vector m_TunPkts; /// 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(huint128_t ipv4) const; /// mark this address as active void MarkIPActive(huint128_t ip); /// mark this address as active forever void MarkIPActiveForever(huint128_t ip); /// flush ip packets virtual void FlushSend(); /// maps ip to key (host byte order) std::unordered_map> m_IPToAddr; /// maps key to ip (host byte order) std::unordered_map, huint128_t, AlignedBuffer<32>::Hash> m_AddrToIP; /// maps key to true if key is a service node, maps key to false if key is /// a hidden service std::unordered_map, bool, AlignedBuffer<32>::Hash> m_SNodes; private: llarp_vpn_io_impl* GetVPNImpl() { if (vpnif && vpnif->impl) return static_cast(vpnif->impl); return nullptr; } bool QueueInboundPacketForExit(const llarp_buffer_t& buf) { ManagedBuffer copy{buf}; return m_NetworkToUserPktQueue.EmplaceIf([&](llarp::net::IPPacket& pkt) -> bool { if (!pkt.Load(copy.underlying)) return false; if (SupportsV6()) { if (pkt.IsV4()) { pkt.UpdateIPv6Address(net::IPPacket::ExpandV4(pkt.srcv4()), m_OurIP); } else { pkt.UpdateIPv6Address(pkt.srcv6(), m_OurIP); } } else { if (pkt.IsV4()) pkt.UpdateIPv4Address( xhtonl(pkt.srcv4()), xhtonl(net::IPPacket::TruncateV6(m_OurIP))); else return false; } return true; }); } template void SendDNSReply( Addr_t addr, Endpoint_t ctx, std::shared_ptr query, std::function reply, bool snode, bool sendIPv6) { if (ctx) { huint128_t ip = ObtainIPForAddr(addr, snode); query->answers.clear(); query->AddINReply(ip, sendIPv6); } else query->AddNXReply(); reply(*query); } /// our dns resolver std::shared_ptr m_Resolver; /// maps ip address to timestamp last active std::unordered_map m_IPActivity; /// our ip address (host byte order) huint128_t m_OurIP; /// next ip address to allocate (host byte order) huint128_t m_NextIP; /// highest ip address to allocate (host byte order) huint128_t m_MaxIP; /// our ip range we are using llarp::IPRange m_OurRange; /// upstream dns resolver list std::vector m_UpstreamResolvers; /// local dns llarp::Addr m_LocalResolverAddr; /// list of strict connect addresses for hooks std::vector m_StrictConnectAddrs; /// use v6? bool m_UseV6; struct lazy_vpn { llarp_vpn_ifaddr_info info; llarp_vpn_io* io; }; std::promise m_LazyVPNPromise; /// send packets on endpoint to user using send function /// send function returns true to indicate stop iteration and do codel /// drop void FlushToUser(std::function sendfunc); }; } // namespace handlers } // namespace llarp #endif