2021-03-10 15:11:42 +00:00
|
|
|
#pragma once
|
|
|
|
|
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 19:26:32 +00:00
|
|
|
#include <llarp/net/sock_addr.hpp>
|
|
|
|
|
2021-03-10 15:11:42 +00:00
|
|
|
#include <array>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
2021-03-12 13:50:21 +00:00
|
|
|
#include <memory>
|
2021-03-10 15:11:42 +00:00
|
|
|
#include <string>
|
|
|
|
#include <iosfwd>
|
|
|
|
|
|
|
|
#include <ngtcp2/ngtcp2.h>
|
|
|
|
|
2021-03-12 13:50:21 +00:00
|
|
|
#include <llarp/net/sock_addr.hpp>
|
|
|
|
#include <llarp/service/convotag.hpp>
|
2021-03-10 15:11:42 +00:00
|
|
|
|
|
|
|
namespace llarp::quic
|
|
|
|
{
|
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 19:26:32 +00:00
|
|
|
// Wrapper around a sockaddr; ngtcp2 requires more intrusive access that llarp::SockAddr is meant
|
|
|
|
// to deal with, hence this wrapper (rather than trying to abuse llarp::SockAddr).
|
2021-03-10 15:11:42 +00:00
|
|
|
class Address
|
|
|
|
{
|
2021-03-12 13:50:21 +00:00
|
|
|
sockaddr_in6 saddr{};
|
2022-01-31 17:20:27 +00:00
|
|
|
ngtcp2_addr a{reinterpret_cast<sockaddr*>(&saddr), sizeof(saddr)};
|
2021-03-10 15:11:42 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
Address() = default;
|
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 19:26:32 +00:00
|
|
|
Address(const SockAddr& addr);
|
2021-03-12 13:50:21 +00:00
|
|
|
|
|
|
|
Address(const Address& other)
|
2021-03-10 15:11:42 +00:00
|
|
|
{
|
2021-03-12 13:50:21 +00:00
|
|
|
*this = other;
|
2021-03-10 15:11:42 +00:00
|
|
|
}
|
2021-03-12 13:50:21 +00:00
|
|
|
|
2021-03-10 15:11:42 +00:00
|
|
|
Address&
|
2021-03-12 13:50:21 +00:00
|
|
|
operator=(const Address&);
|
2021-03-10 15:11:42 +00:00
|
|
|
|
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 19:26:32 +00:00
|
|
|
// Implicit conversion to sockaddr* and ngtcp2_addr& so that an Address can be passed wherever
|
2022-07-16 00:41:14 +00:00
|
|
|
// one of those is expected. Templatized so that implicit conversion to other things doesn't
|
|
|
|
// happen.
|
|
|
|
template <typename T, std::enable_if_t<std::is_same_v<T, sockaddr>, int> = 0>
|
|
|
|
operator T*()
|
2021-03-10 15:11:42 +00:00
|
|
|
{
|
2021-03-12 13:50:21 +00:00
|
|
|
return reinterpret_cast<sockaddr*>(&saddr);
|
2021-03-10 15:11:42 +00:00
|
|
|
}
|
2021-03-12 13:50:21 +00:00
|
|
|
|
2022-07-16 00:41:14 +00:00
|
|
|
template <typename T, std::enable_if_t<std::is_same_v<T, sockaddr>, int> = 0>
|
|
|
|
operator const T*() const
|
2021-03-10 15:11:42 +00:00
|
|
|
{
|
2021-03-12 13:50:21 +00:00
|
|
|
return reinterpret_cast<const sockaddr*>(&saddr);
|
2021-03-10 15:11:42 +00:00
|
|
|
}
|
2021-03-12 13:50:21 +00:00
|
|
|
|
2021-03-10 15:11:42 +00:00
|
|
|
operator ngtcp2_addr&()
|
|
|
|
{
|
|
|
|
return a;
|
|
|
|
}
|
2021-03-12 13:50:21 +00:00
|
|
|
|
2021-03-10 15:11:42 +00:00
|
|
|
operator const ngtcp2_addr&() const
|
|
|
|
{
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2021-03-12 13:50:21 +00:00
|
|
|
size_t
|
|
|
|
sockaddr_size() const
|
|
|
|
{
|
|
|
|
return sizeof(sockaddr_in6);
|
|
|
|
}
|
|
|
|
|
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 19:26:32 +00:00
|
|
|
// Implicit conversion to a convo tag so you can pass an Address to things taking a ConvoTag
|
|
|
|
operator service::ConvoTag() const;
|
|
|
|
|
|
|
|
// Returns the lokinet pseudo-port for the quic connection (which routes this quic packet to the
|
|
|
|
// correct waiting quic instance on the remote).
|
|
|
|
nuint16_t
|
|
|
|
port() const
|
|
|
|
{
|
|
|
|
return nuint16_t{saddr.sin6_port};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets the address port
|
|
|
|
void
|
|
|
|
port(nuint16_t port)
|
|
|
|
{
|
|
|
|
saddr.sin6_port = port.n;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implicit conversion to SockAddr for going back to general llarp code
|
|
|
|
// FIXME: see if this is still needed, I think it may have been refactored away with the
|
|
|
|
// ConvoTag operator
|
|
|
|
operator SockAddr() const
|
|
|
|
{
|
|
|
|
return SockAddr(saddr);
|
|
|
|
}
|
|
|
|
|
2021-03-10 15:11:42 +00:00
|
|
|
std::string
|
2022-07-16 00:41:14 +00:00
|
|
|
ToString() const;
|
2021-03-10 15:11:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Wraps an ngtcp2_path (which is basically just and address pair) with remote/local components.
|
|
|
|
// Implicitly convertable to a ngtcp2_path* so that this can be passed wherever a ngtcp2_path* is
|
|
|
|
// taken in the ngtcp2 API.
|
|
|
|
struct Path
|
|
|
|
{
|
|
|
|
private:
|
2021-03-12 13:50:21 +00:00
|
|
|
Address local_, remote_;
|
2021-03-10 15:11:42 +00:00
|
|
|
|
|
|
|
public:
|
2022-01-31 17:20:27 +00:00
|
|
|
ngtcp2_path path{{local_, local_.sockaddr_size()}, {remote_, remote_.sockaddr_size()}, nullptr};
|
2021-03-10 15:11:42 +00:00
|
|
|
|
|
|
|
// Public accessors are const:
|
|
|
|
const Address& local = local_;
|
|
|
|
const Address& remote = remote_;
|
|
|
|
|
|
|
|
Path() = default;
|
2021-03-12 13:50:21 +00:00
|
|
|
Path(const Address& laddr, const Address& raddr) : local_{laddr}, remote_{raddr}
|
2021-03-10 15:11:42 +00:00
|
|
|
{}
|
2021-03-12 13:50:21 +00:00
|
|
|
|
|
|
|
Path(const Path& p) : Path{p.local, p.remote}
|
2021-03-10 15:11:42 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
Path&
|
|
|
|
operator=(const Path& p)
|
|
|
|
{
|
|
|
|
local_ = p.local_;
|
|
|
|
remote_ = p.remote_;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Equivalent to `&obj.path`, but slightly more convenient for passing into ngtcp2 functions
|
2022-07-16 00:41:14 +00:00
|
|
|
// taking a ngtcp2_path pointer. Templatized to prevent implicit conversion to other type of
|
|
|
|
// pointers/ints.
|
|
|
|
template <typename T, std::enable_if_t<std::is_same_v<T, ngtcp2_path>, int> = 0>
|
|
|
|
operator T*()
|
2021-03-10 15:11:42 +00:00
|
|
|
{
|
|
|
|
return &path;
|
|
|
|
}
|
2022-07-16 00:41:14 +00:00
|
|
|
template <typename T, std::enable_if_t<std::is_same_v<T, ngtcp2_path>, int> = 0>
|
|
|
|
operator const T*() const
|
2021-03-10 15:11:42 +00:00
|
|
|
{
|
|
|
|
return &path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
2022-07-16 00:41:14 +00:00
|
|
|
ToString() const;
|
2021-03-10 15:11:42 +00:00
|
|
|
};
|
|
|
|
} // namespace llarp::quic
|
2022-07-16 00:41:14 +00:00
|
|
|
|
|
|
|
template <>
|
|
|
|
constexpr inline bool llarp::IsToStringFormattable<llarp::quic::Address> = true;
|
|
|
|
template <>
|
|
|
|
constexpr inline bool llarp::IsToStringFormattable<llarp::quic::Path> = true;
|