lokinet/llarp/handlers/tun.cpp

1430 lines
42 KiB
C++
Raw Normal View History

2018-10-10 14:06:28 +02:00
#include <algorithm>
#include <variant>
// harmless on other platforms
#define __USE_MINGW_ANSI_STDIO 1
#include "tun.hpp"
#include <sys/types.h>
2018-09-25 10:31:29 +02:00
#ifndef _WIN32
#include <sys/socket.h>
#include <netdb.h>
2018-09-25 10:31:29 +02:00
#endif
2018-08-15 17:36:34 +02:00
#include <llarp/dns/dns.hpp>
#include <llarp/ev/ev.hpp>
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 20:26:32 +01:00
#include <llarp/net/net.hpp>
#include <llarp/router/abstractrouter.hpp>
#include <llarp/router/systemd_resolved.hpp>
#include <llarp/service/context.hpp>
#include <llarp/service/outbound_context.hpp>
#include <llarp/service/endpoint_state.hpp>
#include <llarp/service/outbound_context.hpp>
#include <llarp/service/name.hpp>
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 20:26:32 +01:00
#include <llarp/service/protocol_type.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <llarp/nodedb.hpp>
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 20:26:32 +01:00
#include <llarp/quic/tunnel.hpp>
#include <llarp/rpc/endpoint_rpc.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/endian.hpp>
#include <llarp/dns/srv_data.hpp>
2018-08-15 17:36:34 +02:00
namespace llarp
{
2018-08-16 16:34:15 +02:00
namespace handlers
2018-08-15 17:36:34 +02:00
{
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
2021-03-02 03:06:20 +01:00
// Intercepts DNS IP packets going to an IP on the tun interface; this is currently used on
// Android and macOS where binding to a DNS port (i.e. via llarp::dns::Proxy) isn't possible
// because of OS restrictions, but a tun interface *is* available.
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
2021-03-02 03:06:20 +01:00
class DnsInterceptor : public dns::PacketHandler
{
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
2021-03-02 03:06:20 +01:00
public:
TunEndpoint* const m_Endpoint;
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
2021-03-02 03:06:20 +01:00
explicit DnsInterceptor(AbstractRouter* router, TunEndpoint* ep)
: dns::PacketHandler{router->loop(), ep}, m_Endpoint{ep} {};
void
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
2021-03-02 03:06:20 +01:00
SendServerMessageBufferTo(
2021-03-08 12:59:55 +01:00
const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) override
{
const auto pkt = net::IPPacket::UDP(
from.getIPv4(),
ToNet(huint16_t{from.getPort()}),
to.getIPv4(),
ToNet(huint16_t{to.getPort()}),
buf);
if (pkt.sz == 0)
return;
m_Endpoint->HandleWriteIPPacket(
2021-03-08 12:59:55 +01:00
pkt.ConstBuffer(), net::ExpandV4(from.asIPv4()), net::ExpandV4(to.asIPv4()), 0);
}
#ifdef ANDROID
bool
IsUpstreamResolver(const SockAddr&, const SockAddr&) const override
{
return true;
}
#endif
#ifdef __APPLE__
// DNS on Apple is a bit weird because in order for the NetworkExtension itself to send data
// through the tunnel we have to proxy DNS requests through Apple APIs (and so our actual
// upstream DNS won't be set in our resolvers, which is why the vanilla IsUpstreamResolver
// won't work for us. However when active the mac also only queries the main tunnel IP for
// DNS, so we consider anything else to be upstream-bound DNS to let it through the tunnel.
bool
IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override
{
2021-09-01 20:31:45 +02:00
return to.asIPv6() != m_Endpoint->GetIfAddr();
}
#endif
};
2019-11-29 19:37:19 +01:00
TunEndpoint::TunEndpoint(AbstractRouter* r, service::Context* parent)
: service::Endpoint(r, parent)
{
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 20:26:32 +01:00
m_PacketRouter = std::make_unique<vpn::PacketRouter>(
[this](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); });
2021-07-29 22:40:25 +02:00
#if defined(ANDROID) || defined(__APPLE__)
Replace libuv with uvw & related refactoring - removes all the llarp_ev_* functions, replacing with methods/classes/functions in the llarp namespace. - banish ev/ev.h to the void - Passes various things by const lvalue ref, especially shared_ptr's that don't need to be copied (to avoid an atomic refcount increment/decrement). - Add a llarp::UDPHandle abstract class for UDP handling - Removes the UDP tick handler; code that needs tick can just do a separate handler on the event loop outside the UDP socket. - Adds an "OwnedBuffer" which owns its own memory but is implicitly convertible to a llarp_buffer_t. This is mostly needed to take over ownership of buffers from uvw without copying them as, currently, uvw does its own allocation (pending some open upstream issues/PRs). - Logic: - add `make_caller`/`call_forever`/`call_every` utility functions to abstract Call wrapping and dependent timed tasks. - Add inLogicThread() so that code can tell its inside the logic thread (typically for debugging assertions). - get rid of janky integer returns and dealing with cancellations on call_later: the other methods added here and the event loop code remove the need for them. - Event loop: - redo everything with uvw instead of libuv - rename EventLoopWakeup::Wakeup to EventLoopWakeup::Trigger to better reflect what it does. - add EventLoopRepeater for repeated events, and replace the code that reschedules itself every time it is called with a repeater. - Split up `EventLoop::run()` into a non-virtual base method and abstract `run_loop()` methods; the base method does a couple extra setup/teardown things that don't need to be in the derived class. - udp_listen is replaced with ev->udp(...) which returns a new UDPHandle object rather that needing gross C-style-but-not-actually-C-compatible structs. - Remove unused register_poll_fd_(un)readable - Use shared_ptr for EventLoopWakeup rather than returning a raw pointer; uvw lets us not have to worry about having the event loop class maintain ownership of it. - Add factory EventLoop::create() function to create a default (uvw-based) event loop (previously this was one of the llarp_ev_blahblah unnamespaced functions). - ev_libuv: this is mostly rewritten; all of the glue code/structs, in particular, are gone as they are no longer needed with uvw. - DNS: - Rename DnsHandler to DnsInterceptor to better describe what it does (this is the code that intercepts all DNS to the tun IP range for Android). - endpoint: - remove unused "isolated network" code - remove distinct (but actually always the same) variables for router/endpoint logic objects - llarp_buffer_t - make constructors type-safe against being called with points to non-size-1 values - tun packet reading: - read all available packets off the device/file descriptor; previously we were reading one packet at a time then returning to the event loop to poll again. - ReadNextPacket() now returns a 0-size packet if the read would block (so that we can implement the previous point). - ReadNextPacket() now throws on I/O error - Miscellaneous code cleanups/simplifications
2021-03-02 03:06:20 +01:00
m_Resolver = std::make_shared<DnsInterceptor>(r, this);
m_PacketRouter->AddUDPHandler(huint16_t{53}, [&](net::IPPacket pkt) {
const size_t ip_header_size = (pkt.Header()->ihl * 4);
const uint8_t* ptr = pkt.buf + ip_header_size;
const auto dst = ToNet(pkt.dstv4());
const auto src = ToNet(pkt.srcv4());
const SockAddr laddr{src, nuint16_t{*reinterpret_cast<const uint16_t*>(ptr)}};
const SockAddr raddr{dst, nuint16_t{*reinterpret_cast<const uint16_t*>(ptr + 2)}};
2021-04-12 13:39:07 +02:00
OwnedBuffer buf{pkt.sz - (8 + ip_header_size)};
std::copy_n(ptr + 8, buf.sz, buf.buf.get());
if (m_Resolver->ShouldHandlePacket(raddr, laddr, buf))
m_Resolver->HandlePacket(raddr, laddr, buf);
else
HandleGotUserPacket(std::move(pkt));
});
#else
m_Resolver = std::make_shared<dns::Proxy>(r->loop(), this);
#endif
}
2018-08-16 16:34:15 +02:00
2019-02-11 18:14:43 +01:00
util::StatusObject
TunEndpoint::ExtractStatus() const
2019-02-08 20:43:25 +01:00
{
auto obj = service::Endpoint::ExtractStatus();
obj["ifaddr"] = m_OurRange.ToString();
obj["ifname"] = m_IfName;
std::vector<std::string> resolvers;
for (const auto& addr : m_UpstreamResolvers)
2020-05-06 22:38:44 +02:00
resolvers.emplace_back(addr.toString());
obj["ustreamResolvers"] = resolvers;
2020-05-06 22:38:44 +02:00
obj["localResolver"] = m_LocalResolverAddr.toString();
2019-02-11 18:14:43 +01:00
util::StatusObject ips{};
for (const auto& item : m_IPActivity)
2019-02-08 20:43:25 +01:00
{
util::StatusObject ipObj{{"lastActive", to_json(item.second)}};
2019-02-08 20:43:25 +01:00
std::string remoteStr;
AlignedBuffer<32> addr = m_IPToAddr.at(item.first);
if (m_SNodes.at(addr))
2019-02-08 20:43:25 +01:00
remoteStr = RouterID(addr.as_array()).ToString();
else
remoteStr = service::Address(addr.as_array()).ToString();
ipObj["remote"] = remoteStr;
2019-02-08 20:43:25 +01:00
std::string ipaddr = item.first.ToString();
ips[ipaddr] = ipObj;
2019-02-08 20:43:25 +01:00
}
obj["addrs"] = ips;
obj["ourIP"] = m_OurIP.ToString();
obj["nextIP"] = m_NextIP.ToString();
obj["maxIP"] = m_MaxIP.ToString();
2019-02-11 18:14:43 +01:00
return obj;
2019-02-08 20:43:25 +01:00
}
void
TunEndpoint::Thaw()
{
if (m_Resolver)
m_Resolver->Restart();
}
std::vector<SockAddr>
TunEndpoint::ReconfigureDNS(std::vector<SockAddr> servers)
{
2021-09-01 20:31:45 +02:00
std::swap(m_UpstreamResolvers, servers);
m_Resolver->Stop();
if (!m_Resolver->Start(
m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles))
llarp::LogError(Name(), " failed to reconfigure DNS server");
return servers;
}
2018-08-16 16:34:15 +02:00
bool
TunEndpoint::Configure(const NetworkConfig& conf, const DnsConfig& dnsConf)
2018-08-16 16:34:15 +02:00
{
if (conf.m_reachable)
{
2020-05-04 18:51:57 +02:00
m_PublishIntroSet = true;
LogInfo(Name(), " setting to be reachable by default");
}
else
{
m_PublishIntroSet = false;
LogInfo(Name(), " setting to be not reachable by default");
}
if (conf.m_AuthType != service::AuthType::eAuthTypeNone)
2020-06-02 23:10:42 +02:00
{
std::string url, method;
if (conf.m_AuthUrl.has_value() and conf.m_AuthMethod.has_value())
{
url = *conf.m_AuthUrl;
method = *conf.m_AuthMethod;
}
2020-06-02 23:10:42 +02:00
auto auth = std::make_shared<rpc::EndpointAuthRPC>(
url, method, conf.m_AuthWhitelist, Router()->lmq(), shared_from_this());
2020-06-02 23:10:42 +02:00
auth->Start();
m_AuthPolicy = std::move(auth);
}
2021-04-14 21:40:57 +02:00
m_TrafficPolicy = conf.m_TrafficPolicy;
m_OwnedRanges = conf.m_OwnedRanges;
m_LocalResolverAddr = dnsConf.m_bind;
m_UpstreamResolvers = dnsConf.m_upstreamDNS;
m_hostfiles = dnsConf.m_hostfiles;
m_BaseV6Address = conf.m_baseV6Address;
if (conf.m_PathAlignmentTimeout)
{
m_PathAlignmentTimeout = *conf.m_PathAlignmentTimeout;
}
else
m_PathAlignmentTimeout = service::Endpoint::PathAlignmentTimeout();
2020-05-21 16:18:23 +02:00
for (const auto& item : conf.m_mapAddrs)
2018-08-22 17:52:10 +02:00
{
2020-05-21 16:18:23 +02:00
if (not MapAddress(item.second, item.first, false))
return false;
2018-08-22 17:52:10 +02:00
}
m_IfName = conf.m_ifname;
if (m_IfName.empty())
{
const auto maybe = llarp::FindFreeTun();
if (not maybe.has_value())
throw std::runtime_error("cannot find free interface name");
m_IfName = *maybe;
}
m_OurRange = conf.m_ifaddr;
if (!m_OurRange.addr.h)
{
const auto maybe = llarp::FindFreeRange();
if (not maybe.has_value())
{
throw std::runtime_error("cannot find free address range");
}
m_OurRange = *maybe;
2018-08-16 16:34:15 +02:00
}
2021-02-16 16:59:18 +01:00
m_OurIP = m_OurRange.addr;
2021-02-16 16:59:18 +01:00
m_UseV6 = false;
2021-04-19 17:20:46 +02:00
m_PersistAddrMapFile = conf.m_AddrMapPersistFile;
if (m_PersistAddrMapFile)
{
const auto& file = *m_PersistAddrMapFile;
if (fs::exists(file))
{
bool shouldLoadFile = true;
{
constexpr auto LastModifiedWindow = 1min;
const auto lastmodified = fs::last_write_time(file);
const auto now = decltype(lastmodified)::clock::now();
if (now < lastmodified or now - lastmodified > LastModifiedWindow)
{
shouldLoadFile = false;
}
}
std::vector<char> data;
if (auto maybe = util::OpenFileStream<fs::ifstream>(file, std::ios_base::binary);
maybe and shouldLoadFile)
{
LogInfo(Name(), " loading address map file from ", file);
maybe->seekg(0, std::ios_base::end);
const size_t len = maybe->tellg();
maybe->seekg(0, std::ios_base::beg);
data.resize(len);
LogInfo(Name(), " reading ", len, " bytes");
maybe->read(data.data(), data.size());
}
else
{
if (shouldLoadFile)
{
LogInfo(Name(), " address map file ", file, " does not exist, so we won't load it");
}
else
LogInfo(Name(), " address map file ", file, " not loaded because it's stale");
}
if (not data.empty())
{
std::string_view bdata{data.data(), data.size()};
2021-06-23 13:30:30 +02:00
LogDebug(Name(), " parsing address map data: ", bdata);
const auto parsed = oxenmq::bt_deserialize<oxenmq::bt_dict>(bdata);
for (const auto& [key, value] : parsed)
{
huint128_t ip{};
if (not ip.FromString(key))
{
LogWarn(Name(), " malformed IP in addr map data: ", key);
continue;
}
if (m_OurIP == ip)
continue;
if (not m_OurRange.Contains(ip))
{
LogWarn(Name(), " out of range IP in addr map data: ", ip);
continue;
}
EndpointBase::AddressVariant_t addr;
if (const auto* str = std::get_if<std::string>(&value))
{
if (auto maybe = service::ParseAddress(*str))
{
addr = *maybe;
}
else
{
LogWarn(Name(), " invalid address in addr map: ", *str);
continue;
}
}
else
{
LogWarn(Name(), " invalid first entry in addr map, not a string");
continue;
}
if (const auto* loki = std::get_if<service::Address>(&addr))
{
m_IPToAddr.emplace(ip, loki->data());
m_AddrToIP.emplace(loki->data(), ip);
m_SNodes[*loki] = false;
LogInfo(Name(), " remapped ", ip, " to ", *loki);
}
if (const auto* snode = std::get_if<RouterID>(&addr))
{
m_IPToAddr.emplace(ip, snode->data());
m_AddrToIP.emplace(snode->data(), ip);
m_SNodes[*snode] = true;
LogInfo(Name(), " remapped ", ip, " to ", *snode);
}
if (m_NextIP < ip)
m_NextIP = ip;
// make sure we dont unmap this guy
MarkIPActive(ip);
}
}
}
else
{
LogInfo(
Name(), " skipping loading addr map at ", file, " as it does not currently exist");
}
}
2021-04-19 17:20:46 +02:00
if (auto* quic = GetQUICTunnel())
{
quic->listen([this](std::string_view, uint16_t port) {
return llarp::SockAddr{net::TruncateV6(GetIfAddr()), huint16_t{port}};
});
}
return Endpoint::Configure(conf, dnsConf);
2018-08-16 16:34:15 +02:00
}
2018-11-14 13:23:08 +01:00
bool
TunEndpoint::HasLocalIP(const huint128_t& ip) const
2018-11-14 13:23:08 +01:00
{
return m_IPToAddr.find(ip) != m_IPToAddr.end();
}
2018-12-15 17:56:35 +01:00
void
TunEndpoint::Pump(llarp_time_t now)
{
// flush network to user
while (not m_NetworkToUserPktQueue.empty())
{
m_NetIf->WritePacket(m_NetworkToUserPktQueue.top().pkt);
m_NetworkToUserPktQueue.pop();
}
service::Endpoint::Pump(now);
2018-12-15 17:56:35 +01:00
}
static bool
is_random_snode(const dns::Message& msg)
{
2019-04-26 14:11:34 +02:00
return msg.questions[0].IsName("random.snode");
}
static bool
is_localhost_loki(const dns::Message& msg)
{
return msg.questions[0].IsLocalhost();
}
static dns::Message&
clear_dns_message(dns::Message& msg)
{
msg.authorities.resize(0);
msg.additional.resize(0);
msg.answers.resize(0);
msg.hdr_fields &= ~dns::flags_RCODENameError;
return msg;
}
std::optional<std::variant<service::Address, RouterID>>
TunEndpoint::ObtainAddrForIP(huint128_t ip) const
{
auto itr = m_IPToAddr.find(ip);
if (itr == m_IPToAddr.end())
return std::nullopt;
if (m_SNodes.at(itr->second))
return RouterID{itr->second.as_array()};
else
return service::Address{itr->second.as_array()};
}
2018-12-03 23:22:59 +01:00
bool
TunEndpoint::HandleHookedDNSMessage(dns::Message msg, std::function<void(dns::Message)> reply)
2018-12-03 23:22:59 +01:00
{
auto ReplyToSNodeDNSWhenReady = [this, reply](RouterID snode, auto msg, bool isV6) -> bool {
return EnsurePathToSNode(
snode,
[this, snode, msg, reply, isV6](
const RouterID&, exit::BaseSession_ptr s, [[maybe_unused]] service::ConvoTag tag) {
SendDNSReply(snode, s, msg, reply, isV6);
});
};
auto ReplyToLokiDNSWhenReady = [this, reply, timeout = PathAlignmentTimeout()](
service::Address addr, auto msg, bool isV6) -> bool {
using service::Address;
using service::OutboundContext;
if (HasInboundConvo(addr))
{
// if we have an inbound convo to this address don't mark as outbound so we don't have a
// state race this codepath is hit when an application verifies that reverse and forward
// dns records match for an inbound session
SendDNSReply(addr, this, msg, reply, isV6);
return true;
}
MarkAddressOutbound(addr);
return EnsurePathToService(
addr,
[this, addr, msg, reply, isV6](const Address&, OutboundContext* ctx) {
SendDNSReply(addr, ctx, msg, reply, isV6);
},
timeout);
};
2021-03-20 19:30:18 +01:00
auto ReplyToDNSWhenReady = [ReplyToLokiDNSWhenReady, ReplyToSNodeDNSWhenReady](
auto addr, auto msg, bool isV6) {
if (auto ptr = std::get_if<RouterID>(&addr))
{
ReplyToSNodeDNSWhenReady(*ptr, msg, isV6);
return;
}
if (auto ptr = std::get_if<service::Address>(&addr))
{
ReplyToLokiDNSWhenReady(*ptr, msg, isV6);
return;
}
};
auto ReplyToLokiSRVWhenReady = [this, reply, timeout = PathAlignmentTimeout()](
service::Address addr, auto msg) -> bool {
using service::Address;
using service::OutboundContext;
// TODO: how do we handle SRV record lookups for inbound sessions?
MarkAddressOutbound(addr);
return EnsurePathToService(
addr,
[msg, addr, reply](const Address&, OutboundContext* ctx) {
if (ctx == nullptr)
return;
const auto& introset = ctx->GetCurrentIntroSet();
msg->AddSRVReply(introset.GetMatchingSRVRecords(addr.subdomain));
reply(*msg);
},
timeout);
};
if (msg.answers.size() > 0)
{
const auto& answer = msg.answers[0];
if (answer.HasCNameForTLD(".snode"))
{
dns::Name_t qname;
llarp_buffer_t buf(answer.rData);
if (not dns::DecodeName(&buf, qname, true))
return false;
RouterID addr;
if (not addr.FromString(qname))
return false;
auto replyMsg = std::make_shared<dns::Message>(clear_dns_message(msg));
return ReplyToSNodeDNSWhenReady(addr, std::move(replyMsg), false);
}
else if (answer.HasCNameForTLD(".loki"))
{
dns::Name_t qname;
llarp_buffer_t buf(answer.rData);
if (not dns::DecodeName(&buf, qname, true))
return false;
service::Address addr;
if (not addr.FromString(qname))
return false;
auto replyMsg = std::make_shared<dns::Message>(clear_dns_message(msg));
return ReplyToLokiDNSWhenReady(addr, replyMsg, false);
}
}
if (msg.questions.size() != 1)
2018-12-03 23:22:59 +01:00
{
llarp::LogWarn("bad number of dns questions: ", msg.questions.size());
return false;
}
std::string qname = msg.questions[0].Name();
2020-09-19 16:38:57 +02:00
const auto nameparts = split(qname, ".");
std::string lnsName;
if (nameparts.size() >= 2 and ends_with(qname, ".loki"))
{
lnsName = nameparts[nameparts.size() - 2];
lnsName += ".loki"sv;
}
if (msg.questions[0].qtype == dns::qTypeTXT)
{
RouterID snode;
if (snode.FromString(qname))
{
m_router->LookupRouter(snode, [reply, msg = std::move(msg)](const auto& found) mutable {
if (found.empty())
{
msg.AddNXReply();
}
else
{
std::stringstream ss;
for (const auto& rc : found)
rc.ToTXTRecord(ss);
msg.AddTXTReply(ss.str());
}
reply(msg);
});
return true;
}
else if (msg.questions[0].IsLocalhost() and msg.questions[0].HasSubdomains())
{
const auto subdomain = msg.questions[0].Subdomains();
if (subdomain == "exit")
{
if (HasExit())
{
std::stringstream ss;
m_ExitMap.ForEachEntry([&ss](const auto& range, const auto& exit) {
ss << range.ToString() << "=" << exit.ToString() << "; ";
});
msg.AddTXTReply(ss.str());
}
else
{
msg.AddNXReply();
}
}
else if (subdomain == "netid")
{
std::stringstream ss;
ss << "netid=" << m_router->rc().netID.ToString() << ";";
msg.AddTXTReply(ss.str());
}
else
{
msg.AddNXReply();
}
}
else
{
msg.AddNXReply();
}
reply(msg);
}
else if (msg.questions[0].qtype == dns::qTypeMX)
2018-12-07 22:52:19 +01:00
{
// mx record
2019-02-05 15:23:51 +01:00
service::Address addr;
if (addr.FromString(qname, ".loki") || addr.FromString(qname, ".snode")
|| is_random_snode(msg) || is_localhost_loki(msg))
2021-02-25 16:35:50 +01:00
{
2018-12-07 22:52:19 +01:00
msg.AddMXReply(qname, 1);
2021-02-25 16:35:50 +01:00
}
else if (service::NameIsValid(lnsName))
{
LookupNameAsync(lnsName, [msg, lnsName, reply](auto maybe) mutable {
if (maybe.has_value())
{
var::visit([&](auto&& value) { msg.AddMXReply(value.ToString(), 1); }, *maybe);
}
else
{
msg.AddNXReply();
}
reply(msg);
});
return true;
2021-02-25 16:35:50 +01:00
}
2018-12-07 22:52:19 +01:00
else
msg.AddNXReply();
2018-12-07 23:08:23 +01:00
reply(msg);
2018-12-07 22:52:19 +01:00
}
else if (msg.questions[0].qtype == dns::qTypeCNAME)
2019-01-10 16:49:08 +01:00
{
if (is_random_snode(msg))
2019-01-10 16:49:08 +01:00
{
RouterID random;
if (Router()->GetRandomGoodRouter(random))
{
2019-01-10 16:49:08 +01:00
msg.AddCNAMEReply(random.ToString(), 1);
}
2019-01-10 16:49:08 +01:00
else
msg.AddNXReply();
}
else if (msg.questions[0].IsLocalhost() and msg.questions[0].HasSubdomains())
{
const auto subdomain = msg.questions[0].Subdomains();
if (subdomain == "exit" and HasExit())
{
m_ExitMap.ForEachEntry(
[&msg](const auto&, const auto& exit) { msg.AddCNAMEReply(exit.ToString(), 1); });
}
else
{
msg.AddNXReply();
}
}
else if (is_localhost_loki(msg))
{
size_t counter = 0;
context->ForEachService(
[&](const std::string&, const std::shared_ptr<service::Endpoint>& service) -> bool {
2019-07-05 16:41:26 +02:00
const service::Address addr = service->GetIdentity().pub.Addr();
msg.AddCNAMEReply(addr.ToString(), 1);
++counter;
return true;
});
if (counter == 0)
msg.AddNXReply();
}
2019-01-10 16:49:08 +01:00
else
msg.AddNXReply();
2019-02-05 15:03:38 +01:00
reply(msg);
2019-01-10 16:49:08 +01:00
}
else if (msg.questions[0].qtype == dns::qTypeA || msg.questions[0].qtype == dns::qTypeAAAA)
2018-12-03 23:22:59 +01:00
{
const bool isV6 = msg.questions[0].qtype == dns::qTypeAAAA;
2019-06-11 18:44:05 +02:00
const bool isV4 = msg.questions[0].qtype == dns::qTypeA;
2018-12-03 23:22:59 +01:00
llarp::service::Address addr;
if (isV6 && !SupportsV6())
{ // empty reply but not a NXDOMAIN so that client can retry IPv4
msg.AddNSReply("localhost.loki.");
}
2019-02-05 04:19:06 +01:00
// on MacOS this is a typeA query
else if (is_random_snode(msg))
2019-02-05 04:19:06 +01:00
{
2019-02-05 22:04:30 +01:00
RouterID random;
if (Router()->GetRandomGoodRouter(random))
{
2019-02-05 22:04:30 +01:00
msg.AddCNAMEReply(random.ToString(), 1);
return ReplyToSNodeDNSWhenReady(random, std::make_shared<dns::Message>(msg), isV6);
}
2019-02-05 22:04:30 +01:00
else
msg.AddNXReply();
2019-02-05 04:19:06 +01:00
}
else if (is_localhost_loki(msg))
2018-12-13 01:03:19 +01:00
{
const bool lookingForExit = msg.questions[0].Subdomains() == "exit";
huint128_t ip = GetIfAddr();
if (ip.h)
{
if (lookingForExit)
{
if (HasExit())
{
m_ExitMap.ForEachEntry(
[&msg](const auto&, const auto& exit) { msg.AddCNAMEReply(exit.ToString()); });
msg.AddINReply(ip, isV6);
}
else
{
msg.AddNXReply();
}
}
else
{
msg.AddCNAMEReply(m_Identity.pub.Name(), 1);
msg.AddINReply(ip, isV6);
}
}
else
{
2018-12-13 01:03:19 +01:00
msg.AddNXReply();
}
2018-12-13 01:03:19 +01:00
}
else if (addr.FromString(qname, ".loki"))
2018-12-03 23:22:59 +01:00
{
if (isV4 && SupportsV6())
{
2019-06-11 20:23:53 +02:00
msg.hdr_fields |= dns::flags_QR | dns::flags_AA | dns::flags_RA;
2019-06-11 18:44:05 +02:00
}
else
{
return ReplyToLokiDNSWhenReady(addr, std::make_shared<dns::Message>(msg), isV6);
}
2018-12-03 23:22:59 +01:00
}
else if (addr.FromString(qname, ".snode"))
2018-12-03 23:22:59 +01:00
{
if (isV4 && SupportsV6())
2019-06-12 15:48:14 +02:00
{
msg.hdr_fields |= dns::flags_QR | dns::flags_AA | dns::flags_RA;
}
else
{
return ReplyToSNodeDNSWhenReady(
addr.as_array(), std::make_shared<dns::Message>(msg), isV6);
2019-06-12 15:48:14 +02:00
}
2018-12-03 23:22:59 +01:00
}
2020-09-19 16:38:57 +02:00
else if (service::NameIsValid(lnsName))
{
LookupNameAsync(
2020-09-19 16:38:57 +02:00
lnsName,
[msg = std::make_shared<dns::Message>(msg),
name = Name(),
2020-09-19 16:38:57 +02:00
lnsName,
isV6,
reply,
ReplyToDNSWhenReady](auto maybe) {
if (not maybe.has_value())
{
2020-09-19 16:38:57 +02:00
LogWarn(name, " lns name ", lnsName, " not resolved");
msg->AddNXReply();
reply(*msg);
return;
}
ReplyToDNSWhenReady(*maybe, msg, isV6);
});
return true;
}
2018-12-03 23:22:59 +01:00
else
2018-12-04 17:16:43 +01:00
msg.AddNXReply();
reply(msg);
2018-12-03 23:22:59 +01:00
}
else if (msg.questions[0].qtype == dns::qTypePTR)
2018-12-03 23:22:59 +01:00
{
2018-12-04 17:16:43 +01:00
// reverse dns
2019-06-12 15:48:14 +02:00
huint128_t ip = {0};
if (!dns::DecodePTR(msg.questions[0].qname, ip))
2018-12-03 23:22:59 +01:00
{
2018-12-04 17:16:43 +01:00
msg.AddNXReply();
reply(msg);
2018-12-03 23:22:59 +01:00
return true;
}
if (auto maybe = ObtainAddrForIP(ip))
2018-12-03 23:22:59 +01:00
{
2021-04-20 15:44:52 +02:00
var::visit([&msg](auto&& result) { msg.AddAReply(result.ToString()); }, *maybe);
2018-12-04 17:16:43 +01:00
reply(msg);
2018-12-03 23:22:59 +01:00
return true;
}
2018-12-04 17:16:43 +01:00
msg.AddNXReply();
reply(msg);
2018-12-03 23:22:59 +01:00
return true;
}
else if (msg.questions[0].qtype == dns::qTypeSRV)
{
llarp::service::Address addr;
if (is_localhost_loki(msg))
{
msg.AddSRVReply(introSet().GetMatchingSRVRecords(msg.questions[0].Subdomains()));
reply(msg);
return true;
}
else if (addr.FromString(qname, ".loki"))
{
llarp::LogDebug("SRV request for: ", qname);
return ReplyToLokiSRVWhenReady(addr, std::make_shared<dns::Message>(msg));
}
}
2018-12-03 23:22:59 +01:00
else
2018-12-04 17:16:43 +01:00
{
msg.AddNXReply();
reply(msg);
}
2018-12-03 23:22:59 +01:00
return true;
}
2019-05-07 19:46:38 +02:00
void
TunEndpoint::ResetInternalState()
{
service::Endpoint::ResetInternalState();
}
2019-06-11 18:44:05 +02:00
bool
TunEndpoint::SupportsV6() const
{
return m_UseV6;
}
2019-03-20 04:18:38 +01:00
// FIXME: pass in which question it should be addressing
2018-12-03 23:22:59 +01:00
bool
TunEndpoint::ShouldHookDNSMessage(const dns::Message& msg) const
2018-12-03 23:22:59 +01:00
{
llarp::service::Address addr;
if (msg.questions.size() == 1)
2018-12-03 23:22:59 +01:00
{
/// hook every .loki
if (msg.questions[0].HasTLD(".loki"))
2018-12-13 01:03:19 +01:00
return true;
/// hook every .snode
if (msg.questions[0].HasTLD(".snode"))
2018-12-03 23:22:59 +01:00
return true;
2019-01-10 16:49:08 +01:00
// hook any ranges we own
if (msg.questions[0].qtype == llarp::dns::qTypePTR)
2018-12-03 23:22:59 +01:00
{
2019-06-12 15:48:14 +02:00
huint128_t ip = {0};
if (!dns::DecodePTR(msg.questions[0].qname, ip))
2018-12-03 23:22:59 +01:00
return false;
2019-06-12 15:48:14 +02:00
return m_OurRange.Contains(ip);
2018-12-03 23:22:59 +01:00
}
}
for (const auto& answer : msg.answers)
{
if (answer.HasCNameForTLD(".loki"))
return true;
if (answer.HasCNameForTLD(".snode"))
return true;
}
2018-12-03 23:22:59 +01:00
return false;
}
2018-08-22 17:52:10 +02:00
bool
TunEndpoint::MapAddress(const service::Address& addr, huint128_t ip, bool SNode)
2018-08-22 17:52:10 +02:00
{
auto itr = m_IPToAddr.find(ip);
if (itr != m_IPToAddr.end())
2018-08-22 17:52:10 +02:00
{
llarp::LogWarn(
ip, " already mapped to ", service::Address(itr->second.as_array()).ToString());
2018-08-22 17:52:10 +02:00
return false;
}
2018-11-03 14:19:18 +01:00
llarp::LogInfo(Name() + " map ", addr.ToString(), " to ", ip);
2018-10-19 17:04:14 +02:00
m_IPToAddr[ip] = addr;
m_AddrToIP[addr] = ip;
m_SNodes[addr] = SNode;
2018-09-10 13:08:09 +02:00
MarkIPActiveForever(ip);
MarkAddressOutbound(addr);
2018-08-22 17:52:10 +02:00
return true;
}
2020-08-21 17:07:37 +02:00
std::string
TunEndpoint::GetIfName() const
{
2020-09-29 00:43:31 +02:00
#ifdef _WIN32
return net::TruncateV6(GetIfAddr()).ToString();
#else
2020-08-21 17:07:37 +02:00
return m_IfName;
2020-09-29 00:43:31 +02:00
#endif
2020-08-21 17:07:37 +02:00
}
2018-08-16 16:34:15 +02:00
bool
TunEndpoint::Start()
{
if (!Endpoint::Start())
{
llarp::LogWarn("Couldn't start endpoint");
2018-08-16 16:34:15 +02:00
return false;
}
2018-08-21 20:39:18 +02:00
return SetupNetworking();
2018-08-16 16:34:15 +02:00
}
bool
TunEndpoint::IsSNode() const
{
// TODO : implement me
return false;
}
2018-08-16 16:34:15 +02:00
bool
TunEndpoint::SetupTun()
{
m_NextIP = m_OurIP;
m_MaxIP = m_OurRange.HighestAddr();
llarp::LogInfo(Name(), " set ", m_IfName, " to have address ", m_OurIP);
llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ", m_OurRange);
const service::Address ourAddr = m_Identity.pub.Addr();
if (not MapAddress(ourAddr, GetIfAddr(), false))
{
return false;
}
vpn::InterfaceInfo info;
info.addrs.emplace(m_OurRange);
if (m_BaseV6Address)
{
IPRange v6range = m_OurRange;
v6range.addr = (*m_BaseV6Address) | m_OurRange.addr;
LogInfo(Name(), " using v6 range: ", v6range);
info.addrs.emplace(v6range, AF_INET6);
}
2021-02-16 16:59:18 +01:00
info.ifname = m_IfName;
info.dnsaddr.FromString(m_LocalResolverAddr.toHost());
LogInfo(Name(), " setting up network...");
try
2019-06-11 18:44:05 +02:00
{
m_NetIf = Router()->GetVPNPlatform()->ObtainInterface(std::move(info));
2019-06-11 18:44:05 +02:00
}
catch (std::exception& ex)
2019-06-11 18:44:05 +02:00
{
LogError(Name(), " failed to set up network interface: ", ex.what());
}
if (not m_NetIf)
{
LogError(Name(), " failed to obtain network interface");
return false;
}
m_IfName = m_NetIf->IfName();
LogInfo(Name(), " got network interface ", m_IfName);
2021-03-02 16:23:38 +01:00
if (not Router()->loop()->add_network_interface(m_NetIf, [this](net::IPPacket pkt) {
m_PacketRouter->HandleIPPacket(std::move(pkt));
}))
2019-11-29 01:37:58 +01:00
{
LogError(Name(), " failed to add network interface");
2019-11-29 01:37:58 +01:00
return false;
}
#ifdef __APPLE__
m_OurIPv6 = llarp::huint128_t{
llarp::uint128_t{0xfd2e'6c6f'6b69'0000, llarp::net::TruncateV6(m_OurRange.addr).h}};
#else
const auto maybe = GetInterfaceIPv6Address(m_IfName);
2021-02-16 16:59:18 +01:00
if (maybe.has_value())
{
m_OurIPv6 = *maybe;
LogInfo(Name(), " has ipv6 address ", m_OurIPv6);
2021-02-16 16:59:18 +01:00
}
#endif
// Attempt to register DNS on the interface
2021-04-28 22:07:44 +02:00
systemd_resolved_set_dns(
m_IfName,
m_LocalResolverAddr.createSockAddr(),
false /* just .loki/.snode DNS initially */);
if (m_OnUp)
{
2019-04-22 16:00:59 +02:00
m_OnUp->NotifyAsync(NotifyParams());
}
2019-11-29 01:37:58 +01:00
return HasAddress(ourAddr);
2018-08-16 16:34:15 +02:00
}
std::unordered_map<std::string, std::string>
2019-04-22 16:00:59 +02:00
TunEndpoint::NotifyParams() const
{
auto env = Endpoint::NotifyParams();
env.emplace("IP_ADDR", m_OurIP.ToString());
env.emplace("IF_ADDR", m_OurRange.ToString());
env.emplace("IF_NAME", m_IfName);
std::string strictConnect;
for (const auto& addr : m_StrictConnectAddrs)
2020-05-06 22:38:44 +02:00
strictConnect += addr.toString() + " ";
env.emplace("STRICT_CONNECT_ADDRS", strictConnect);
2019-04-22 16:00:59 +02:00
return env;
}
2018-08-16 16:34:15 +02:00
bool
TunEndpoint::SetupNetworking()
{
llarp::LogInfo("Set Up networking for ", Name());
if (!SetupTun())
2018-10-04 15:42:22 +02:00
{
2018-12-03 23:22:59 +01:00
llarp::LogError(Name(), " failed to set up network interface");
return false;
2018-10-04 15:42:22 +02:00
}
if (!m_Resolver->Start(
m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles))
{
llarp::LogError(Name(), " failed to start DNS server");
return false;
}
2018-12-03 23:22:59 +01:00
return true;
2018-08-16 16:34:15 +02:00
}
void
TunEndpoint::Tick(llarp_time_t now)
{
2019-11-20 20:45:23 +01:00
Endpoint::Tick(now);
2018-08-16 16:34:15 +02:00
}
bool
TunEndpoint::Stop()
{
// save address map if applicable
#ifndef ANDROID
if (m_PersistAddrMapFile)
{
const auto& file = *m_PersistAddrMapFile;
LogInfo(Name(), " saving address map to ", file);
if (auto maybe = util::OpenFileStream<fs::ofstream>(file, std::ios_base::binary))
{
std::map<std::string, std::string> addrmap;
for (const auto& [ip, addr] : m_IPToAddr)
{
if (not m_SNodes.at(addr))
{
const service::Address a{addr.as_array()};
if (HasInboundConvo(a))
addrmap[ip.ToString()] = a.ToString();
}
}
const auto data = oxenmq::bt_serialize(addrmap);
maybe->write(data.data(), data.size());
}
}
#endif
2020-10-29 15:19:45 +01:00
if (m_Resolver)
m_Resolver->Stop();
return llarp::service::Endpoint::Stop();
}
2018-08-22 17:52:10 +02:00
void
TunEndpoint::HandleGotUserPacket(net::IPPacket pkt)
2018-08-22 17:52:10 +02:00
{
huint128_t dst, src;
if (pkt.IsV4())
{
dst = pkt.dst4to6();
src = pkt.src4to6();
}
else
{
dst = pkt.dstv6();
src = pkt.srcv6();
}
// this is for ipv6 slaac on ipv6 exits
/*
constexpr huint128_t ipv6_multicast_all_nodes =
huint128_t{uint128_t{0xff01'0000'0000'0000UL, 1UL}};
constexpr huint128_t ipv6_multicast_all_routers =
huint128_t{uint128_t{0xff01'0000'0000'0000UL, 2UL}};
if (dst == ipv6_multicast_all_nodes and m_state->m_ExitEnabled)
{
// send ipv6 multicast
for (const auto& [ip, addr] : m_IPToAddr)
{
(void)ip;
SendToOrQueue(
service::Address{addr.as_array()}, pkt.ConstBuffer(), service::ProtocolType::Exit);
}
return;
}
*/
if (m_state->m_ExitEnabled)
{
dst = net::ExpandV4(net::TruncateV6(dst));
}
auto itr = m_IPToAddr.find(dst);
if (itr == m_IPToAddr.end())
{
// find all ranges that match the destination ip
const auto exitEntries = m_ExitMap.FindAllEntries(dst);
if (exitEntries.empty())
2018-08-22 17:52:10 +02:00
{
// send icmp unreachable as we dont have any exits for this ip
if (const auto icmp = pkt.MakeICMPUnreachable())
2019-06-11 21:48:21 +02:00
{
HandleWriteIPPacket(icmp->ConstBuffer(), dst, src, 0);
2020-05-21 16:18:23 +02:00
}
2019-06-11 18:44:05 +02:00
return;
2018-08-22 17:52:10 +02:00
}
service::Address addr{};
for (const auto& [range, exitAddr] : exitEntries)
2021-06-08 20:52:16 +02:00
{
2021-11-15 22:15:16 +01:00
if (not IsBogon(dst) or range.BogonContains(dst))
{
addr = exitAddr;
}
// we do not permit bogons when they don't explicitly match a permitted bogon range
2021-06-08 20:52:16 +02:00
}
if (addr.IsZero()) // drop becase no exit was found that matches our rules
return;
pkt.ZeroSourceAddress();
MarkAddressOutbound(addr);
EnsurePathToService(
addr,
[pkt, this](service::Address addr, service::OutboundContext* ctx) {
if (ctx)
{
ctx->SendPacketToRemote(pkt.ConstBuffer(), service::ProtocolType::Exit);
Router()->TriggerPump();
return;
}
LogWarn("cannot ensure path to exit ", addr, " so we drop some packets");
},
PathAlignmentTimeout());
return;
}
std::variant<service::Address, RouterID> to;
service::ProtocolType type;
if (m_SNodes.at(itr->second))
{
to = RouterID{itr->second.as_array()};
type = service::ProtocolType::TrafficV4;
}
else
{
to = service::Address{itr->second.as_array()};
type = m_state->m_ExitEnabled and src != m_OurIP ? service::ProtocolType::Exit
: pkt.ServiceProtocol();
}
// prepare packet for insertion into network
// this includes clearing IP addresses, recalculating checksums, etc
// this does not happen for exits because the point is they don't rewrite addresses
if (type != service::ProtocolType::Exit)
{
if (pkt.IsV4())
pkt.UpdateIPv4Address({0}, {0});
else
pkt.UpdateIPv6Address({0}, {0});
}
// try sending it on an existing convotag
// this succeds for inbound convos, probably.
if (auto maybe = GetBestConvoTagFor(to))
{
if (SendToOrQueue(*maybe, pkt.ConstBuffer(), type))
{
MarkIPActive(dst);
Router()->TriggerPump();
return;
}
}
// try establishing a path to this guy
// will fail if it's an inbound convo
EnsurePathTo(
to,
[pkt, type, dst, to, this](auto maybe) {
if (not maybe)
{
var::visit(
[this](auto&& addr) {
LogWarn(Name(), " failed to ensure path to ", addr, " no convo tag found");
},
to);
}
if (SendToOrQueue(*maybe, pkt.ConstBuffer(), type))
{
MarkIPActive(dst);
Router()->TriggerPump();
}
else
{
var::visit(
[this](auto&& addr) {
LogWarn(Name(), " failed to send to ", addr, ", SendToOrQueue failed");
},
to);
}
},
PathAlignmentTimeout());
2018-08-22 17:52:10 +02:00
}
2021-04-14 17:07:06 +02:00
bool
TunEndpoint::ShouldAllowTraffic(const net::IPPacket& pkt) const
{
if (const auto exitPolicy = GetExitPolicy())
{
if (not exitPolicy->AllowsTraffic(pkt))
return false;
}
return true;
}
bool
2020-05-21 16:18:23 +02:00
TunEndpoint::HandleInboundPacket(
const service::ConvoTag tag,
const llarp_buffer_t& buf,
service::ProtocolType t,
uint64_t seqno)
2020-05-21 16:18:23 +02:00
{
LogTrace("Inbound ", t, " packet (", buf.sz, "B) on convo ", tag);
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 20:26:32 +01:00
if (t == service::ProtocolType::QUIC)
{
auto* quic = GetQUICTunnel();
if (!quic)
{
LogWarn("incoming quic packet but this endpoint is not quic capable; dropping");
return false;
}
if (buf.sz < 4)
{
LogWarn("invalid incoming quic packet, dropping");
return false;
}
LogInfo("tag active T=", tag);
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 20:26:32 +01:00
quic->receive_packet(tag, buf);
return true;
}
2021-03-08 21:48:11 +01:00
if (t != service::ProtocolType::TrafficV4 && t != service::ProtocolType::TrafficV6
&& t != service::ProtocolType::Exit)
2020-05-21 16:18:23 +02:00
return false;
std::variant<service::Address, RouterID> addr;
if (auto maybe = GetEndpointWithConvoTag(tag))
{
addr = *maybe;
}
else
2020-05-21 16:18:23 +02:00
return false;
huint128_t src, dst;
net::IPPacket pkt;
if (not pkt.Load(buf))
return false;
if (m_state->m_ExitEnabled)
2020-05-21 16:18:23 +02:00
{
// exit side from exit
2021-04-14 17:07:06 +02:00
// check packet against exit policy and if as needed
if (not ShouldAllowTraffic(pkt))
return false;
src = ObtainIPForAddr(addr);
2021-03-08 21:48:11 +01:00
if (t == service::ProtocolType::Exit)
{
if (pkt.IsV4())
dst = pkt.dst4to6();
else if (pkt.IsV6())
2021-02-16 16:59:18 +01:00
{
dst = pkt.dstv6();
2021-02-16 16:59:18 +01:00
src = net::ExpandV4Lan(net::TruncateV6(src));
}
}
else
{
// non exit traffic on exit
dst = m_OurIP;
}
2020-05-21 16:18:23 +02:00
}
2021-03-08 21:48:11 +01:00
else if (t == service::ProtocolType::Exit)
{
// client side exit traffic from exit
if (pkt.IsV4())
{
dst = m_OurIP;
src = pkt.src4to6();
}
else if (pkt.IsV6())
{
dst = m_OurIPv6;
src = pkt.srcv6();
}
// find what exit we think this should be for
service::Address fromAddr{};
if (const auto* ptr = std::get_if<service::Address>(&addr))
{
fromAddr = *ptr;
}
else // don't allow snode
return false;
2021-04-14 17:07:06 +02:00
const auto mapped = m_ExitMap.FindAllEntries(src);
bool allow = false;
for (const auto& [range, exitAddr] : mapped)
{
2021-11-15 22:15:16 +01:00
if (not IsBogon(src) or range.BogonContains(src))
{
// allow if this address matches the endpoint we think it should be
allow = exitAddr == fromAddr;
break;
}
}
2021-04-14 17:07:06 +02:00
if (not allow)
{
var::visit(
[&](auto&& address) { LogWarn(Name(), " does not allow ", src, " from ", address); },
addr);
2021-04-14 17:07:06 +02:00
return false;
}
}
2020-05-21 16:18:23 +02:00
else
{
// snapp traffic
src = ObtainIPForAddr(addr);
2020-05-21 16:18:23 +02:00
dst = m_OurIP;
}
HandleWriteIPPacket(buf, src, dst, seqno);
2020-05-21 16:18:23 +02:00
return true;
}
bool
TunEndpoint::HandleWriteIPPacket(
const llarp_buffer_t& b, huint128_t src, huint128_t dst, uint64_t seqno)
2018-08-18 16:01:21 +02:00
{
2019-02-03 01:48:10 +01:00
ManagedBuffer buf(b);
WritePacket write;
write.seqno = seqno;
auto& pkt = write.pkt;
// load
if (!pkt.Load(buf))
{
return false;
}
if (pkt.IsV4())
{
pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(src)), xhtonl(net::TruncateV6(dst)));
}
else if (pkt.IsV6())
{
pkt.UpdateIPv6Address(src, dst);
}
m_NetworkToUserPktQueue.push(std::move(write));
// wake up so we ensure that all packets are written to user
Router()->TriggerPump();
return true;
2018-08-20 21:12:12 +02:00
}
2018-10-19 17:04:14 +02:00
2019-06-11 18:44:05 +02:00
huint128_t
2018-11-14 13:23:08 +01:00
TunEndpoint::GetIfAddr() const
{
2018-11-14 13:23:08 +01:00
return m_OurIP;
}
2018-08-20 21:12:12 +02:00
2019-06-11 18:44:05 +02:00
huint128_t
TunEndpoint::ObtainIPForAddr(std::variant<service::Address, RouterID> addr)
2018-08-20 21:12:12 +02:00
{
llarp_time_t now = Now();
2019-06-11 18:44:05 +02:00
huint128_t nextIP = {0};
AlignedBuffer<32> ident{};
bool snode = false;
2021-04-20 15:44:52 +02:00
var::visit([&ident](auto&& val) { ident = val.data(); }, addr);
if (std::get_if<RouterID>(&addr))
{
snode = true;
}
{
// previously allocated address
2018-11-14 21:56:54 +01:00
auto itr = m_AddrToIP.find(ident);
if (itr != m_AddrToIP.end())
2018-08-22 17:52:10 +02:00
{
// mark ip active
2018-09-16 14:25:17 +02:00
MarkIPActive(itr->second);
return itr->second;
2018-08-22 17:52:10 +02:00
}
}
// allocate new address
if (m_NextIP < m_MaxIP)
{
do
{
nextIP = ++m_NextIP;
} while (m_IPToAddr.find(nextIP) != m_IPToAddr.end() && m_NextIP < m_MaxIP);
if (nextIP < m_MaxIP)
{
m_AddrToIP[ident] = nextIP;
2018-11-14 22:40:44 +01:00
m_IPToAddr[nextIP] = ident;
m_SNodes[ident] = snode;
var::visit(
[&](auto&& remote) { llarp::LogInfo(Name(), " mapped ", remote, " to ", nextIP); },
addr);
MarkIPActive(nextIP);
return nextIP;
}
}
// we are full
// expire least active ip
// TODO: prevent DoS
std::pair<huint128_t, llarp_time_t> oldest = {huint128_t{0}, 0s};
// find oldest entry
auto itr = m_IPActivity.begin();
while (itr != m_IPActivity.end())
{
if (itr->second <= now)
{
if ((now - itr->second) > oldest.second)
{
oldest.first = itr->first;
oldest.second = itr->second;
}
}
++itr;
}
// remap address
2018-11-14 22:47:58 +01:00
m_IPToAddr[oldest.first] = ident;
m_AddrToIP[ident] = oldest.first;
m_SNodes[ident] = snode;
nextIP = oldest.first;
// mark ip active
m_IPActivity[nextIP] = std::max(m_IPActivity[nextIP], now);
2018-08-20 21:12:12 +02:00
return nextIP;
}
bool
2019-06-11 18:44:05 +02:00
TunEndpoint::HasRemoteForIP(huint128_t ip) const
2018-08-20 21:12:12 +02:00
{
return m_IPToAddr.find(ip) != m_IPToAddr.end();
2018-08-18 16:01:21 +02:00
}
void
2019-06-11 18:44:05 +02:00
TunEndpoint::MarkIPActive(huint128_t ip)
{
2019-06-11 23:28:55 +02:00
llarp::LogDebug(Name(), " address ", ip, " is active");
2018-10-29 17:48:36 +01:00
m_IPActivity[ip] = std::max(Now(), m_IPActivity[ip]);
}
2018-09-10 13:08:09 +02:00
void
2019-06-11 18:44:05 +02:00
TunEndpoint::MarkIPActiveForever(huint128_t ip)
2018-09-10 13:08:09 +02:00
{
m_IPActivity[ip] = std::numeric_limits<llarp_time_t>::max();
2018-09-10 13:08:09 +02:00
}
2019-07-31 01:42:13 +02:00
TunEndpoint::~TunEndpoint() = default;
2018-08-15 17:36:34 +02:00
2018-08-16 16:34:15 +02:00
} // namespace handlers
} // namespace llarp