[*] Harden glibc resolver
This commit is contained in:
parent
6e9e962c84
commit
e63fb1c996
@ -5,14 +5,25 @@
|
||||
Date: 2022-8-26
|
||||
Author: Reece
|
||||
***/
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
#define RESOLVER_IS_VERY_FREETARDED
|
||||
// Compilers compiled for linux should define this for us, including GCC.
|
||||
#if !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
//Defines: __USE_GNU
|
||||
#include <features.h>
|
||||
#endif
|
||||
#include "Networking.hpp"
|
||||
#include "AuNetResolver.Unix.hpp"
|
||||
#include "AuNetEndpoint.hpp"
|
||||
#include <Source/IO/Loop/LSSignalCatcher.Linux.hpp>
|
||||
#include <Source/IO/Loop/LSEvent.hpp>
|
||||
|
||||
#if defined(AURORA_IS_LINUX_DERIVED)
|
||||
#define RESOLVER_IS_VERY_FREETARDED
|
||||
// https://elixir.bootlin.com/glibc/glibc-2.40.9000/source/bits/types/sigevent_t.h#L8
|
||||
// https://elixir.bootlin.com/musl/v1.2.5/source/include/signal.h#L190
|
||||
#if defined(__USE_GNU)
|
||||
#define sigev_notify_thread_id _sigev_un._tid
|
||||
#endif
|
||||
|
||||
namespace Aurora::IO::Net
|
||||
@ -147,9 +158,17 @@ namespace Aurora::IO::Net
|
||||
}
|
||||
|
||||
sigevent event {0};
|
||||
|
||||
#if defined(AURORA_PLATFORM_LINUX)
|
||||
event.sigev_notify = SIGEV_SIGNAL;
|
||||
event.sigev_signo = GetGAIAsyncIOSignal();
|
||||
//event._sigev_un._tid = gettid();
|
||||
event.sigev_notify_thread_id = gettid();
|
||||
// pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid() : 0;
|
||||
// not required for glibc resolv?
|
||||
#else
|
||||
// TODO: setup threaded callback:
|
||||
return this->StartStandard();
|
||||
#endif
|
||||
|
||||
auto pQueue = AuMakeShared<ThreadLocalCaughtCompletion>(this);
|
||||
if (!pQueue)
|
||||
@ -170,12 +189,6 @@ namespace Aurora::IO::Net
|
||||
pBase->ar_request = (addrinfo *)&infoEx;
|
||||
pBase->ar_name = hostname.c_str();
|
||||
|
||||
if (!AuTryInsert(tlsResolvers, AuSharedFromThis()))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
return false;
|
||||
}
|
||||
|
||||
int iStatus = pgetaddrinfo_a(GAI_NOWAIT,
|
||||
&pBase,
|
||||
1,
|
||||
@ -183,27 +196,27 @@ namespace Aurora::IO::Net
|
||||
|
||||
switch (iStatus)
|
||||
{
|
||||
case EAI_AGAIN:
|
||||
{
|
||||
SysPushErrorNet("Low Resources | Failed to resolve");
|
||||
this->uOsError = iStatus;
|
||||
this->error_ = this->ToError();
|
||||
return false;
|
||||
}
|
||||
case EAI_MEMORY:
|
||||
{
|
||||
SysPushErrorNet("Out of Memory | Failed to resolve");
|
||||
this->uOsError = iStatus;
|
||||
this->error_ = this->ToError();
|
||||
return false;
|
||||
}
|
||||
case EAI_SYSTEM:
|
||||
{
|
||||
SysPushErrorNet("Invalid | Failed to resolve: {}", errno);
|
||||
this->uOsError = errno;
|
||||
this->error_ = this->ToError();
|
||||
return false;
|
||||
}
|
||||
case EAI_AGAIN:
|
||||
{
|
||||
SysPushErrorNet("Low Resources | Failed to resolve");
|
||||
this->uOsError = iStatus;
|
||||
this->error_ = this->ToError();
|
||||
return false;
|
||||
}
|
||||
case EAI_MEMORY:
|
||||
{
|
||||
SysPushErrorNet("Out of Memory | Failed to resolve");
|
||||
this->uOsError = iStatus;
|
||||
this->error_ = this->ToError();
|
||||
return false;
|
||||
}
|
||||
case EAI_SYSTEM:
|
||||
{
|
||||
SysPushErrorNet("Invalid | Failed to resolve: {}", errno);
|
||||
this->uOsError = errno;
|
||||
this->error_ = this->ToError();
|
||||
return this->StartStandard();
|
||||
}
|
||||
}
|
||||
|
||||
if (iStatus != 0)
|
||||
@ -214,6 +227,13 @@ namespace Aurora::IO::Net
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AuTryInsert(tlsResolvers, AuSharedFromThis()))
|
||||
{
|
||||
SysPushErrorMemory();
|
||||
this->Cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->BeginOperation(AuSharedFromThis(),
|
||||
this->pWorker_);
|
||||
|
||||
@ -468,12 +488,85 @@ namespace Aurora::IO::Net
|
||||
|
||||
#if defined(AURORA_HAS_GLIBC_RESOLVER_PROXY_STUBS)
|
||||
|
||||
// Our name-resolution signaling options for glibc / GAHHNUUU-EEB-SNCCEE are:
|
||||
// 1) [gahnuu IO] Wait forever for glibc to spawn a thread with their own pthreads; or
|
||||
// 2) [gahnuu IO] Use their interface for sending a signal instead. Noting that Linux-likes can
|
||||
// handle sigev_notify_thread_id notifications, via a signalqueue and sigevent field.
|
||||
// 3) [posix] Just call getaddrinfo in a thread pool ourselves (or just not and create a thread each time. same for winxp.)
|
||||
//
|
||||
// Noting that GAHHNUUU-SNCCEE resolv NSS modules are the only hope of standard Linux-like applications of getting DoH,
|
||||
// alternative plugin-based DNS services, and cached results on their system.
|
||||
// musl and other embedded drivers are hopeless.
|
||||
//
|
||||
// No matter the POSIX implementation type, it'll match WinXP - 11 with the Windows Name Resolution stack under Windows Sockets 2.
|
||||
// Canceling? Windows XP, Vista and 7 doesn't even have GetAddrInfoExCancel. glibc says, na, not yet because its not in posix yet.
|
||||
// Canceling, but can we? Ok, we can sort of cancel on all platforms. On old Windows, we could force term a thread, but we dont, and idk if we should.
|
||||
// On other POSIX systems, we could force term a thread, but we dont, and idk if we should.
|
||||
// On glibc, we have gai_cancel, that might work.
|
||||
// On glibc, posix, and Windows 7-XP, we will probably find ourselves spinning in a yield loop until the DNS request has been resolved or properly canceled.
|
||||
// Caching? Yea probably.
|
||||
// IPv6? Yea, if the platform vendor supports it.
|
||||
// User config? Yea, if the platform vendor supports it.
|
||||
// Native async? Maybe a thread pool if we're lucky. Otherwise we can just spawn a thread and get the same results
|
||||
//
|
||||
// On the plus side, libc abstraction of getaddrinfo in async form (glibc) or our own hack of spawn a thread (hello ::StartStandard),
|
||||
// we always guarantee the system has a good async getaddrinfo;
|
||||
// the interface we just established has the ability for the user to configure it; and
|
||||
// the system will probably be handling our DNS caching in a global platform standard.
|
||||
//
|
||||
// On alternative libcs and platforms:
|
||||
// >Musl will just have to write a good internal DNS library with plugin routing, caching, and/or async. Not my problem.
|
||||
// >Android has its' own DNS stack based on ISCs lib, with caching. No async expected.
|
||||
// >XNU has its' own dns stack based on ISCs lib (or at least they did. old libresolv.). No async expected.
|
||||
// We can expect forks of ISCs library with IPv6 support with cached entries, somewhere; or similar features under getaddrinfo.
|
||||
//
|
||||
// On Linux:
|
||||
// >Most Linux users will be using their own local version of glibc.
|
||||
// >DNS can be configured how the user wants.
|
||||
// >systemd-resolv and friends should take care of system local cache conctrol.
|
||||
// >and yes that does mean implicit integration with systemd
|
||||
// (systemd-resolve via the NSS module 'nss-resolve' gets served under our users of getaddrinfo [also incl the call under glibc aio] ).
|
||||
//
|
||||
// We assume best case glibc/signal on linux glibc targets.
|
||||
// glibcs async resolve just uses getaddrinfo under the hood, with an actual threadpool. the only question which is faster: pthread spawn or a linux sigqueue?
|
||||
// Knowing we can jut rely on getaddrinfo no matter what, we just spawn a detached thread, if we need async on other platforms with the same expected feature set.
|
||||
// getaddrinfo may suck, but it's the only minimum interface we can provide and expect.
|
||||
//
|
||||
// So far as providing a common async abstraction for the expected platform provider is concerned, this should be the right thing.
|
||||
//
|
||||
// We could always build our own resolver on top of this and:
|
||||
// >platform("k.root-servers.net") ?? (EU RIPE NCC, headquartered in Amsterdam. probably won't care for german or american lower level judges having a moment. )
|
||||
// >193.0.14.129 ?? 2001:7fd::1 ??
|
||||
// >platform("g.root-servers.net") ?? (US DoD glow plant. the good thing: EU plebs and activists be damned, they will not touch DNS results without a vaild US federal court order and 15 layers of bureaucracy. bc DOD feds.)
|
||||
// >192.112.36.4 ?? 2001:500:12::d0d
|
||||
// for the most globally standard, consistent, and censorship-free results.
|
||||
// The downsides:
|
||||
// No caching (TODO: registry with sqlite?)
|
||||
// Probably wont be privacy friendly.
|
||||
// Not all servers with be authenticated or encrypted.
|
||||
// You could implement a nonstandard DNS server that's always recursive, cached, and encrypted, *but* then you probably need to worry about user consent and extra costs.
|
||||
static void Annoying(int)
|
||||
{
|
||||
// We probably do not need SA_NODEFER or iterator protection.
|
||||
//
|
||||
// Under Linux, we can target a specific posix processes with a signal properly.
|
||||
// Under other systems, we cant. On these systems, we shouldn't expect SA_NODEFER to exist.
|
||||
// Let's assume we have proper signal queues. On this note...
|
||||
//
|
||||
// if (--*waitlist->counterp == 0)
|
||||
// __gai_notify_only (waitlist->sigevp, waitlist->caller_pid);
|
||||
// https://elixir.bootlin.com/glibc/glibc-2.40.9000/source/resolv/gai_misc.c#L337
|
||||
// https://elixir.bootlin.com/glibc/glibc-2.40.9000/source/resolv/gai_notify.c#L124-L128
|
||||
// https://elixir.bootlin.com/glibc/glibc-2.40.9000/source/sysdeps/unix/sysv/linux/gai_sigqueue.c#L31
|
||||
// I think glibc is trying to protect us against this as well? I don't even know. I doubt they know either.
|
||||
// They correctly pass around the pid, and then claim they need to because of a linux bug? what the actual fuck.
|
||||
// Average gahnnuuu project. beri quality code.
|
||||
|
||||
for (const auto &gawad : tlsResolvers)
|
||||
{
|
||||
if (auto pResolver = gawad.lock())
|
||||
if (auto pResolver = AuTryLockMemoryType(gawad))
|
||||
{
|
||||
// Under almost all POSIX systems, this will result in a blocking write
|
||||
pResolver->pEvent->Set();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user